Exemple #1
0
 public void intersectPrimitive(Ray r, int primID, IntersectionState state)
 {
     // intersect in local space
     float rd2x = r.dx * r.dx;
     float rd2y = r.dy * r.dy;
     float rd2z = r.dz * r.dz;
     float ro2x = r.ox * r.ox;
     float ro2y = r.oy * r.oy;
     float ro2z = r.oz * r.oz;
     // setup the quartic coefficients
     // some common terms could probably be shared across these
     double A = (rd2y * rd2y + rd2z * rd2z + rd2x * rd2x);
     double B = 4 * (r.oy * rd2y * r.dy + r.oz * r.dz * rd2z + r.ox * r.dx * rd2x);
     double C = (-rd2x - rd2y - rd2z + 6 * (ro2y * rd2y + ro2z * rd2z + ro2x * rd2x));
     double D = 2 * (2 * ro2z * r.oz * r.dz - r.oz * r.dz + 2 * ro2x * r.ox * r.dx + 2 * ro2y * r.oy * r.dy - r.ox * r.dx - r.oy * r.dy);
     double E = 3.0f / 8.0f + (-ro2z + ro2z * ro2z - ro2y + ro2y * ro2y - ro2x + ro2x * ro2x);
     // solve equation
     double[] t = Solvers.solveQuartic(A, B, C, D, E);
     if (t != null)
     {
         // early rejection
         if (t[0] >= r.getMax() || t[t.Length - 1] <= r.getMin())
             return;
         // find first intersection in front of the ray
         for (int i = 0; i < t.Length; i++)
         {
             if (t[i] > r.getMin())
             {
                 r.setMax((float)t[i]);
                 state.setIntersection(0, 0, 0);
                 return;
             }
         }
     }
 }
Exemple #2
0
 public void intersectPrimitive(Ray r, int primID, IntersectionState state)
 {
     // intersect in local space
     float qa = r.dx * r.dx + r.dy * r.dy + r.dz * r.dz;
     float qb = 2 * ((r.dx * r.ox) + (r.dy * r.oy) + (r.dz * r.oz));
     float qc = ((r.ox * r.ox) + (r.oy * r.oy) + (r.oz * r.oz)) - 1;
     double[] t = Solvers.solveQuadric(qa, qb, qc);
     if (t != null)
     {
         // early rejection
         if (t[0] >= r.getMax() || t[1] <= r.getMin())
             return;
         if (t[0] > r.getMin())
             r.setMax((float)t[0]);
         else
             r.setMax((float)t[1]);
         state.setIntersection(0, 0, 0);
     }
 }
Exemple #3
0
 public void intersectPrimitive(Ray r, int primID, IntersectionState state)
 {
     int i3 = primID * 3;
     float ocx = r.ox - particles[i3 + 0];
     float ocy = r.oy - particles[i3 + 1];
     float ocz = r.oz - particles[i3 + 2];
     float qa = r.dx * r.dx + r.dy * r.dy + r.dz * r.dz;
     float qb = 2 * ((r.dx * ocx) + (r.dy * ocy) + (r.dz * ocz));
     float qc = ((ocx * ocx) + (ocy * ocy) + (ocz * ocz)) - r2;
     double[] t = Solvers.solveQuadric(qa, qb, qc);
     if (t != null)
     {
         // early rejection
         if (t[0] >= r.getMax() || t[1] <= r.getMin())
             return;
         if (t[0] > r.getMin())
             r.setMax((float)t[0]);
         else
             r.setMax((float)t[1]);
         state.setIntersection(primID);
     }
 }
Exemple #4
0
 public void intersectPrimitive(Ray r, int primID, IntersectionState state)
 {
     float intervalMin = r.getMin();
     float intervalMax = r.getMax();
     float orgX = r.ox;
     float orgY = r.oy;
     float orgZ = r.oz;
     float dirX = r.dx, invDirX = 1 / dirX;
     float dirY = r.dy, invDirY = 1 / dirY;
     float dirZ = r.dz, invDirZ = 1 / dirZ;
     float t1, t2;
     t1 = (-1 - orgX) * invDirX;
     t2 = (+1 - orgX) * invDirX;
     int curr = -1;
     if (invDirX > 0)
     {
         if (t1 > intervalMin)
         {
             intervalMin = t1;
             curr = 0;
         }
         if (t2 < intervalMax)
             intervalMax = t2;
         if (intervalMin > intervalMax)
             return;
     }
     else
     {
         if (t2 > intervalMin)
         {
             intervalMin = t2;
             curr = 1;
         }
         if (t1 < intervalMax)
             intervalMax = t1;
         if (intervalMin > intervalMax)
             return;
     }
     t1 = (-1 - orgY) * invDirY;
     t2 = (+1 - orgY) * invDirY;
     if (invDirY > 0)
     {
         if (t1 > intervalMin)
         {
             intervalMin = t1;
             curr = 2;
         }
         if (t2 < intervalMax)
             intervalMax = t2;
         if (intervalMin > intervalMax)
             return;
     }
     else
     {
         if (t2 > intervalMin)
         {
             intervalMin = t2;
             curr = 3;
         }
         if (t1 < intervalMax)
             intervalMax = t1;
         if (intervalMin > intervalMax)
             return;
     }
     t1 = (-1 - orgZ) * invDirZ;
     t2 = (+1 - orgZ) * invDirZ;
     if (invDirZ > 0)
     {
         if (t1 > intervalMin)
         {
             intervalMin = t1;
             curr = 4;
         }
         if (t2 < intervalMax)
             intervalMax = t2;
         if (intervalMin > intervalMax)
             return;
     }
     else
     {
         if (t2 > intervalMin)
         {
             intervalMin = t2;
             curr = 5;
         }
         if (t1 < intervalMax)
             intervalMax = t1;
         if (intervalMin > intervalMax)
             return;
     }
     // box is hit at [intervalMin, intervalMax]
     orgX += intervalMin * dirX;
     orgY += intervalMin * dirY;
     orgZ += intervalMin * dirZ;
     // locate starting point inside the grid
     // and set up 3D-DDA vars
     int indxX, indxY, indxZ;
     int stepX, stepY, stepZ;
     int stopX, stopY, stopZ;
     float deltaX, deltaY, deltaZ;
     float tnextX, tnextY, tnextZ;
     // stepping factors along X
     indxX = (int)((orgX + 1) * invVoxelwx);
     if (indxX < 0)
         indxX = 0;
     else if (indxX >= nx)
         indxX = nx - 1;
     if (Math.Abs(dirX) < 1e-6f)
     {
         stepX = 0;
         stopX = indxX;
         deltaX = 0;
         tnextX = float.PositiveInfinity;
     }
     else if (dirX > 0)
     {
         stepX = 1;
         stopX = nx;
         deltaX = voxelwx * invDirX;
         tnextX = intervalMin + ((indxX + 1) * voxelwx - 1 - orgX) * invDirX;
     }
     else
     {
         stepX = -1;
         stopX = -1;
         deltaX = -voxelwx * invDirX;
         tnextX = intervalMin + (indxX * voxelwx - 1 - orgX) * invDirX;
     }
     // stepping factors along Y
     indxY = (int)((orgY + 1) * invVoxelwy);
     if (indxY < 0)
         indxY = 0;
     else if (indxY >= ny)
         indxY = ny - 1;
     if (Math.Abs(dirY) < 1e-6f)
     {
         stepY = 0;
         stopY = indxY;
         deltaY = 0;
         tnextY = float.PositiveInfinity;
     }
     else if (dirY > 0)
     {
         stepY = 1;
         stopY = ny;
         deltaY = voxelwy * invDirY;
         tnextY = intervalMin + ((indxY + 1) * voxelwy - 1 - orgY) * invDirY;
     }
     else
     {
         stepY = -1;
         stopY = -1;
         deltaY = -voxelwy * invDirY;
         tnextY = intervalMin + (indxY * voxelwy - 1 - orgY) * invDirY;
     }
     // stepping factors along Z
     indxZ = (int)((orgZ + 1) * invVoxelwz);
     if (indxZ < 0)
         indxZ = 0;
     else if (indxZ >= nz)
         indxZ = nz - 1;
     if (Math.Abs(dirZ) < 1e-6f)
     {
         stepZ = 0;
         stopZ = indxZ;
         deltaZ = 0;
         tnextZ = float.PositiveInfinity;
     }
     else if (dirZ > 0)
     {
         stepZ = 1;
         stopZ = nz;
         deltaZ = voxelwz * invDirZ;
         tnextZ = intervalMin + ((indxZ + 1) * voxelwz - 1 - orgZ) * invDirZ;
     }
     else
     {
         stepZ = -1;
         stopZ = -1;
         deltaZ = -voxelwz * invDirZ;
         tnextZ = intervalMin + (indxZ * voxelwz - 1 - orgZ) * invDirZ;
     }
     // are we starting inside the cube
     bool isInside = inside(indxX, indxY, indxZ) && bounds.contains(r.ox, r.oy, r.oz);
     // trace through the grid
     for (; ; )
     {
         if (inside(indxX, indxY, indxZ) != isInside)
         {
             // we hit a boundary
             r.setMax(intervalMin);
             // if we are inside, the last bit needs to be flipped
             if (isInside)
                 curr ^= 1;
             state.setIntersection(curr);
             return;
         }
         if (tnextX < tnextY && tnextX < tnextZ)
         {
             curr = dirX > 0 ? 0 : 1;
             intervalMin = tnextX;
             if (intervalMin > intervalMax)
                 return;
             indxX += stepX;
             if (indxX == stopX)
                 return;
             tnextX += deltaX;
         }
         else if (tnextY < tnextZ)
         {
             curr = dirY > 0 ? 2 : 3;
             intervalMin = tnextY;
             if (intervalMin > intervalMax)
                 return;
             indxY += stepY;
             if (indxY == stopY)
                 return;
             tnextY += deltaY;
         }
         else
         {
             curr = dirZ > 0 ? 4 : 5;
             intervalMin = tnextZ;
             if (intervalMin > intervalMax)
                 return;
             indxZ += stepZ;
             if (indxZ == stopZ)
                 return;
             tnextZ += deltaZ;
         }
     }
 }
Exemple #5
0
 public void intersect(Ray r, IntersectionState state)
 {
     float intervalMin = r.getMin();
     float intervalMax = r.getMax();
     float orgX = r.ox;
     float dirX = r.dx, invDirX = 1 / dirX;
     float t1, t2;
     t1 = (bounds.getMinimum().x - orgX) * invDirX;
     t2 = (bounds.getMaximum().x - orgX) * invDirX;
     if (invDirX > 0)
     {
         if (t1 > intervalMin)
             intervalMin = t1;
         if (t2 < intervalMax)
             intervalMax = t2;
     }
     else
     {
         if (t2 > intervalMin)
             intervalMin = t2;
         if (t1 < intervalMax)
             intervalMax = t1;
     }
     if (intervalMin > intervalMax)
         return;
     float orgY = r.oy;
     float dirY = r.dy, invDirY = 1 / dirY;
     t1 = (bounds.getMinimum().y - orgY) * invDirY;
     t2 = (bounds.getMaximum().y - orgY) * invDirY;
     if (invDirY > 0)
     {
         if (t1 > intervalMin)
             intervalMin = t1;
         if (t2 < intervalMax)
             intervalMax = t2;
     }
     else
     {
         if (t2 > intervalMin)
             intervalMin = t2;
         if (t1 < intervalMax)
             intervalMax = t1;
     }
     if (intervalMin > intervalMax)
         return;
     float orgZ = r.oz;
     float dirZ = r.dz, invDirZ = 1 / dirZ;
     t1 = (bounds.getMinimum().z - orgZ) * invDirZ;
     t2 = (bounds.getMaximum().z - orgZ) * invDirZ;
     if (invDirZ > 0)
     {
         if (t1 > intervalMin)
             intervalMin = t1;
         if (t2 < intervalMax)
             intervalMax = t2;
     }
     else
     {
         if (t2 > intervalMin)
             intervalMin = t2;
         if (t1 < intervalMax)
             intervalMax = t1;
     }
     if (intervalMin > intervalMax)
         return;
     // box is hit at [intervalMin, intervalMax]
     orgX += intervalMin * dirX;
     orgY += intervalMin * dirY;
     orgZ += intervalMin * dirZ;
     // locate starting point inside the grid
     // and set up 3D-DDA vars
     int indxX, indxY, indxZ;
     int stepX, stepY, stepZ;
     int stopX, stopY, stopZ;
     float deltaX, deltaY, deltaZ;
     float tnextX, tnextY, tnextZ;
     // stepping factors along X
     indxX = (int)((orgX - bounds.getMinimum().x) * invVoxelwx);
     if (indxX < 0)
         indxX = 0;
     else if (indxX >= nx)
         indxX = nx - 1;
     if (Math.Abs(dirX) < 1e-6f)
     {
         stepX = 0;
         stopX = indxX;
         deltaX = 0;
         tnextX = float.PositiveInfinity;
     }
     else if (dirX > 0)
     {
         stepX = 1;
         stopX = nx;
         deltaX = voxelwx * invDirX;
         tnextX = intervalMin + ((indxX + 1) * voxelwx + bounds.getMinimum().x - orgX) * invDirX;
     }
     else
     {
         stepX = -1;
         stopX = -1;
         deltaX = -voxelwx * invDirX;
         tnextX = intervalMin + (indxX * voxelwx + bounds.getMinimum().x - orgX) * invDirX;
     }
     // stepping factors along Y
     indxY = (int)((orgY - bounds.getMinimum().y) * invVoxelwy);
     if (indxY < 0)
         indxY = 0;
     else if (indxY >= ny)
         indxY = ny - 1;
     if (Math.Abs(dirY) < 1e-6f)
     {
         stepY = 0;
         stopY = indxY;
         deltaY = 0;
         tnextY = float.PositiveInfinity;
     }
     else if (dirY > 0)
     {
         stepY = 1;
         stopY = ny;
         deltaY = voxelwy * invDirY;
         tnextY = intervalMin + ((indxY + 1) * voxelwy + bounds.getMinimum().y - orgY) * invDirY;
     }
     else
     {
         stepY = -1;
         stopY = -1;
         deltaY = -voxelwy * invDirY;
         tnextY = intervalMin + (indxY * voxelwy + bounds.getMinimum().y - orgY) * invDirY;
     }
     // stepping factors along Z
     indxZ = (int)((orgZ - bounds.getMinimum().z) * invVoxelwz);
     if (indxZ < 0)
         indxZ = 0;
     else if (indxZ >= nz)
         indxZ = nz - 1;
     if (Math.Abs(dirZ) < 1e-6f)
     {
         stepZ = 0;
         stopZ = indxZ;
         deltaZ = 0;
         tnextZ = float.PositiveInfinity;
     }
     else if (dirZ > 0)
     {
         stepZ = 1;
         stopZ = nz;
         deltaZ = voxelwz * invDirZ;
         tnextZ = intervalMin + ((indxZ + 1) * voxelwz + bounds.getMinimum().z - orgZ) * invDirZ;
     }
     else
     {
         stepZ = -1;
         stopZ = -1;
         deltaZ = -voxelwz * invDirZ;
         tnextZ = intervalMin + (indxZ * voxelwz + bounds.getMinimum().z - orgZ) * invDirZ;
     }
     int cellstepX = stepX;
     int cellstepY = stepY * nx;
     int cellstepZ = stepZ * ny * nx;
     int cell = indxX + indxY * nx + indxZ * ny * nx;
     // trace through the grid
     for (; ; )
     {
         if (tnextX < tnextY && tnextX < tnextZ)
         {
             if (cells[cell] != null)
             {
                 foreach (int i in cells[cell])
                     primitives.intersectPrimitive(r, i, state);
                 if (state.hit() && (r.getMax() < tnextX && r.getMax() < intervalMax))
                     return;
             }
             intervalMin = tnextX;
             if (intervalMin > intervalMax)
                 return;
             indxX += stepX;
             if (indxX == stopX)
                 return;
             tnextX += deltaX;
             cell += cellstepX;
         }
         else if (tnextY < tnextZ)
         {
             if (cells[cell] != null)
             {
                 foreach (int i in cells[cell])
                     primitives.intersectPrimitive(r, i, state);
                 if (state.hit() && (r.getMax() < tnextY && r.getMax() < intervalMax))
                     return;
             }
             intervalMin = tnextY;
             if (intervalMin > intervalMax)
                 return;
             indxY += stepY;
             if (indxY == stopY)
                 return;
             tnextY += deltaY;
             cell += cellstepY;
         }
         else
         {
             if (cells[cell] != null)
             {
                 foreach (int i in cells[cell])
                     primitives.intersectPrimitive(r, i, state);
                 if (state.hit() && (r.getMax() < tnextZ && r.getMax() < intervalMax))
                     return;
             }
             intervalMin = tnextZ;
             if (intervalMin > intervalMax)
                 return;
             indxZ += stepZ;
             if (indxZ == stopZ)
                 return;
             tnextZ += deltaZ;
             cell += cellstepZ;
         }
     }
 }
Exemple #6
0
        public void intersect(Ray r, IntersectionState state)
        {
            float intervalMin = r.getMin();
            float intervalMax = r.getMax();
            float orgX = r.ox;
            float dirX = r.dx, invDirX = 1 / dirX;
            float t1, t2;

                t1 = (bounds.getMinimum ().x - orgX) * invDirX;
                t2 = (bounds.getMaximum ().x - orgX) * invDirX;
                if (invDirX > 0) {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                } else {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                    return;
                float orgY = r.oy;
                float dirY = r.dy, invDirY = 1 / dirY;
                t1 = (bounds.getMinimum ().y - orgY) * invDirY;
                t2 = (bounds.getMaximum ().y - orgY) * invDirY;
                if (invDirY > 0) {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                } else {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                    return;
                float orgZ = r.oz;
                float dirZ = r.dz, invDirZ = 1 / dirZ;
                t1 = (bounds.getMinimum ().z - orgZ) * invDirZ;
                t2 = (bounds.getMaximum ().z - orgZ) * invDirZ;
                if (invDirZ > 0) {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                } else {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                    return;

                // compute custom offsets from direction sign bit
                int offsetXFront = (int)((uint)(ByteUtil.floatToRawIntBits (dirX) & (1 << 31)) >> 30);//>>>
                int offsetYFront = (int)((uint)(ByteUtil.floatToRawIntBits (dirY) & (1 << 31)) >> 30);//>>>
                int offsetZFront = (int)((uint)(ByteUtil.floatToRawIntBits (dirZ) & (1 << 31)) >> 30);//>>>

                int offsetXBack = offsetXFront ^ 2;
                int offsetYBack = offsetYFront ^ 2;
                int offsetZBack = offsetZFront ^ 2;

                IntersectionState.StackNode[] stack = state.getStack ();
                int stackPos = 0;
                int node = 0;

                while (true) {
                    int tn = tree [node];
                    int axis = tn & (3 << 30);
                    int offset = tn & ~(3 << 30);
                    switch (axis) {
                    case 0:
                        {
                            float d = (ByteUtil.intBitsToFloat (tree [node + 1]) - orgX) * invDirX;
                            int back = offset + offsetXBack;
                            node = back;
                            if (d < intervalMin)
                                continue;
                            node = offset + offsetXFront; // front
                            if (d > intervalMax)
                                continue;
                            // push back node
                            stack [stackPos].node = back;
                            stack [stackPos].near = (d >= intervalMin) ? d : intervalMin;
                            stack [stackPos].far = intervalMax;
                            stackPos++;
                            // update ray interval for front node
                            intervalMax = (d <= intervalMax) ? d : intervalMax;
                            continue;
                        }
                    case 1 << 30:
                        {
                            // y axis
                            float d = (ByteUtil.intBitsToFloat (tree [node + 1]) - orgY) * invDirY;
                            int back = offset + offsetYBack;
                            node = back;
                            if (d < intervalMin)
                                continue;
                            node = offset + offsetYFront; // front
                            if (d > intervalMax)
                                continue;
                            // push back node
                            stack [stackPos].node = back;
                            stack [stackPos].near = (d >= intervalMin) ? d : intervalMin;
                            stack [stackPos].far = intervalMax;
                            stackPos++;
                            // update ray interval for front node
                            intervalMax = (d <= intervalMax) ? d : intervalMax;
                            continue;
                        }
                    case 2 << 30:
                        {
                            // z axis
                            float d = (ByteUtil.intBitsToFloat (tree [node + 1]) - orgZ) * invDirZ;
                            int back = offset + offsetZBack;
                            node = back;
                            if (d < intervalMin)
                                continue;
                            node = offset + offsetZFront; // front
                            if (d > intervalMax)
                                continue;
                            // push back node
                            stack [stackPos].node = back;
                            stack [stackPos].near = (d >= intervalMin) ? d : intervalMin;
                            stack [stackPos].far = intervalMax;
                            stackPos++;
                            // update ray interval for front node
                            intervalMax = (d <= intervalMax) ? d : intervalMax;
                            continue;
                        }
                    default:
                        {
                            // leaf - test some objects
                            int n = tree [node + 1];
                            while (n > 0) {
                                primitiveList.intersectPrimitive (r, primitives [offset], state);
                                n--;
                                offset++;
                            }
                            if (r.getMax () < intervalMax)
                                return;
                            do {
                                // stack is empty?
                                if (stackPos == 0)
                                    return;
                                // move back up the stack
                                stackPos--;
                                intervalMin = stack [stackPos].near;
                                if (r.getMax () < intervalMin)
                                    continue;
                                node = stack [stackPos].node;
                                intervalMax = stack [stackPos].far;
                                break;
                            } while (true);
                            break;
                        }
                    } // switch
                } // traversal loop
        }
Exemple #7
0
        public void intersectPrimitiveRobust(Ray r, int primID, IntersectionState state)
        {
            // ray-triangle intersection here
            int tri = 3 * primID;
            int a = 3 * triangles[tri + 0];
            int b = 3 * triangles[tri + 1];
            int c = 3 * triangles[tri + 2];
            float[] stack = state.getRobustStack();
            for (int i = 0, i3 = 0; i < 3; i++, i3 += 3)
            {
                stack[i3 + 0] = points[a + i];
                stack[i3 + 1] = points[b + i];
                stack[i3 + 2] = points[c + i];
            }
            stack[9] = float.PositiveInfinity;
            int stackpos = 0;
            float orgX = r.ox;
            float dirX = r.dx, invDirX = 1 / dirX;
            float orgY = r.oy;
            float dirY = r.dy, invDirY = 1 / dirY;
            float orgZ = r.oz;
            float dirZ = r.dz, invDirZ = 1 / dirZ;
            float t1, t2;
            float minx, maxx;
            float miny, maxy;
            float minz, maxz;
            float mint = r.getMin();
            float maxt = r.getMax();
            while (stackpos >= 0)
            {
                float intervalMin = mint;
                float intervalMax = maxt;
                float p0x = stack[stackpos + 0];
                float p1x = stack[stackpos + 1];
                float p2x = stack[stackpos + 2];
                t1 = ((minx = MathUtils.min(p0x, p1x, p2x)) - orgX) * invDirX;
                t2 = ((maxx = MathUtils.max(p0x, p1x, p2x)) - orgX) * invDirX;
                if (invDirX > 0)
                {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                }
                else
                {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                {
                    stackpos -= 10;
                    continue;
                }
                float p0y = stack[stackpos + 3];
                float p1y = stack[stackpos + 4];
                float p2y = stack[stackpos + 5];
                t1 = ((miny = MathUtils.min(p0y, p1y, p2y)) - orgY) * invDirY;
                t2 = ((maxy = MathUtils.max(p0y, p1y, p2y)) - orgY) * invDirY;
                if (invDirY > 0)
                {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                }
                else
                {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                {
                    stackpos -= 10;
                    continue;
                }
                float p0z = stack[stackpos + 6];
                float p1z = stack[stackpos + 7];
                float p2z = stack[stackpos + 8];
                t1 = ((minz = MathUtils.min(p0z, p1z, p2z)) - orgZ) * invDirZ;
                t2 = ((maxz = MathUtils.max(p0z, p1z, p2z)) - orgZ) * invDirZ;
                if (invDirZ > 0)
                {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                }
                else
                {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                {
                    stackpos -= 10;
                    continue;
                }
                // intersection was found - keep going
                float size = (maxx - minx) + (maxy - miny) + (maxz - minz);
                if (ByteUtil.floatToRawIntBits(stack[stackpos + 9]) == ByteUtil.floatToRawIntBits(size))
                {
                    // L1 norm is 0, we are done
                    r.setMax(intervalMin);
                    triaccel[primID].intersectBox(r, p0x, p0y, p0z, primID, state);
                    return; // safe to return, only one intersection per primitive
                }
                // not small enough yet - subdivide
                float p01x = (p0x + p1x) * 0.5f;
                float p01y = (p0y + p1y) * 0.5f;
                float p01z = (p0z + p1z) * 0.5f;

                float p12x = (p1x + p2x) * 0.5f;
                float p12y = (p1y + p2y) * 0.5f;
                float p12z = (p1z + p2z) * 0.5f;

                float p20x = (p2x + p0x) * 0.5f;
                float p20y = (p2y + p0y) * 0.5f;
                float p20z = (p2z + p0z) * 0.5f;

                // triangle 0
                stack[stackpos + 0] = p0x;
                stack[stackpos + 1] = p01x;
                stack[stackpos + 2] = p20x;
                stack[stackpos + 3] = p0y;
                stack[stackpos + 4] = p01y;
                stack[stackpos + 5] = p20y;
                stack[stackpos + 6] = p0z;
                stack[stackpos + 7] = p01z;
                stack[stackpos + 8] = p20z;
                stack[stackpos + 9] = size;
                stackpos += 10;
                // triangle 1
                stack[stackpos + 0] = p1x;
                stack[stackpos + 1] = p12x;
                stack[stackpos + 2] = p01x;
                stack[stackpos + 3] = p1y;
                stack[stackpos + 4] = p12y;
                stack[stackpos + 5] = p01y;
                stack[stackpos + 6] = p1z;
                stack[stackpos + 7] = p12z;
                stack[stackpos + 8] = p01z;
                stack[stackpos + 9] = size;
                stackpos += 10;
                // triangle 2
                stack[stackpos + 0] = p2x;
                stack[stackpos + 1] = p20x;
                stack[stackpos + 2] = p12x;
                stack[stackpos + 3] = p2y;
                stack[stackpos + 4] = p20y;
                stack[stackpos + 5] = p12y;
                stack[stackpos + 6] = p2z;
                stack[stackpos + 7] = p20z;
                stack[stackpos + 8] = p12z;
                stack[stackpos + 9] = size;
                stackpos += 10;
                // triangle 4
                stack[stackpos + 0] = p20x;
                stack[stackpos + 1] = p12x;
                stack[stackpos + 2] = p01x;
                stack[stackpos + 3] = p20y;
                stack[stackpos + 4] = p12y;
                stack[stackpos + 5] = p01y;
                stack[stackpos + 6] = p20z;
                stack[stackpos + 7] = p12z;
                stack[stackpos + 8] = p01z;
                stack[stackpos + 9] = size;
            }
        }
Exemple #8
0
        public void intersectPrimitive(Ray r, int primID, IntersectionState state)
        {
            // intersect with bounding sphere
            float qc = ((r.ox * r.ox) + (r.oy * r.oy) + (r.oz * r.oz)) - BOUNDING_RADIUS2;
            float qt = r.getMin();
            if (qc > 0)
            {
                // we are starting outside the sphere, find intersection on the
                // sphere
                float qa = r.dx * r.dx + r.dy * r.dy + r.dz * r.dz;
                float qb = 2 * ((r.dx * r.ox) + (r.dy * r.oy) + (r.dz * r.oz));
                double[] t = Solvers.solveQuadric(qa, qb, qc);
                // early rejection
                if (t == null || t[0] >= r.getMax() || t[1] <= r.getMin())
                    return;
                qt = (float)t[0];
            }
            float dist = float.PositiveInfinity;
            float rox = r.ox + qt * r.dx;
            float roy = r.oy + qt * r.dy;
            float roz = r.oz + qt * r.dz;
            float invRayLength = (float)(1 / Math.Sqrt(r.dx * r.dx + r.dy * r.dy + r.dz * r.dz));
            // now we can start intersection
            while (true)
            {
                float zw = rox;
                float zx = roy;
                float zy = roz;
                float zz = 0;

                float zpw = 1;
                float zpx = 0;
                float zpy = 0;
                float zpz = 0;

                // run several iterations
                float dotz = 0;
                for (int i = 0; i < maxIterations; i++)
                {
                    {
                        // zp = 2 * (z * zp)
                        float nw = zw * zpw - zx * zpx - zy * zpy - zz * zpz;
                        float nx = zw * zpx + zx * zpw + zy * zpz - zz * zpy;
                        float ny = zw * zpy + zy * zpw + zz * zpx - zx * zpz;
                        zpz = 2 * (zw * zpz + zz * zpw + zx * zpy - zy * zpx);
                        zpw = 2 * nw;
                        zpx = 2 * nx;
                        zpy = 2 * ny;
                    }
                    {
                        // z = z*z + c
                        float nw = zw * zw - zx * zx - zy * zy - zz * zz + cw;
                        zx = 2 * zw * zx + cx;
                        zy = 2 * zw * zy + cy;
                        zz = 2 * zw * zz + cz;
                        zw = nw;
                    }
                    dotz = zw * zw + zx * zx + zy * zy + zz * zz;
                    if (dotz > ESCAPE_THRESHOLD)
                        break;

                }
                float normZ = (float)Math.Sqrt(dotz);
                dist = 0.5f * normZ * (float)Math.Log(normZ) / Length(zpw, zpx, zpy, zpz);
                rox += dist * r.dx;
                roy += dist * r.dy;
                roz += dist * r.dz;
                qt += dist;
                if (dist * invRayLength < epsilon)
                    break;
                if (rox * rox + roy * roy + roz * roz > BOUNDING_RADIUS2)
                    return;
            }
            // now test t value again
            if (!r.isInside(qt))
                return;
            if (dist * invRayLength < epsilon)
            {
                // valid hit
                r.setMax(qt);
                state.setIntersection(0, 0, 0);
            }
        }
Exemple #9
0
 public void intersectPrimitive(Ray r, int primID, IntersectionState state)
 {
     // intersect in local space
     float rd2x = r.dx * r.dx;
     float rd2y = r.dy * r.dy;
     float rd2z = r.dz * r.dz;
     float ro2x = r.ox * r.ox;
     float ro2y = r.oy * r.oy;
     float ro2z = r.oz * r.oz;
     // compute some common factors
     double alpha = rd2x + rd2y + rd2z;
     double beta = 2 * (r.ox * r.dx + r.oy * r.dy + r.oz * r.dz);
     double gamma = (ro2x + ro2y + ro2z) - ri2 - ro2;
     // setup quartic coefficients
     double A = alpha * alpha;
     double B = 2 * alpha * beta;
     double C = beta * beta + 2 * alpha * gamma + 4 * ro2 * rd2z;
     double D = 2 * beta * gamma + 8 * ro2 * r.oz * r.dz;
     double E = gamma * gamma + 4 * ro2 * ro2z - 4 * ro2 * ri2;
     // solve equation
     double[] t = Solvers.solveQuartic(A, B, C, D, E);
     if (t != null)
     {
         // early rejection
         if (t[0] >= r.getMax() || t[t.Length - 1] <= r.getMin())
             return;
         // find first intersection in front of the ray
         for (int i = 0; i < t.Length; i++)
         {
             if (t[i] > r.getMin())
             {
                 r.setMax((float)t[i]);
                 state.setIntersection(0, 0, 0);
                 return;
             }
         }
     }
 }
        public void intersect(Ray r, IntersectionState state)
        {
            float intervalMin = r.getMin();
            float intervalMax = r.getMax();
            float orgX = r.ox;
            float dirX = r.dx, invDirX = 1 / dirX;
            float t1, t2;
            t1 = (bounds.getMinimum().x - orgX) * invDirX;
            t2 = (bounds.getMaximum().x - orgX) * invDirX;
            if (invDirX > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;
            float orgY = r.oy;
            float dirY = r.dy, invDirY = 1 / dirY;
            t1 = (bounds.getMinimum().y - orgY) * invDirY;
            t2 = (bounds.getMaximum().y - orgY) * invDirY;
            if (invDirY > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;
            float orgZ = r.oz;
            float dirZ = r.dz, invDirZ = 1 / dirZ;
            t1 = (bounds.getMinimum().z - orgZ) * invDirZ;
            t2 = (bounds.getMaximum().z - orgZ) * invDirZ;
            if (invDirZ > 0)
            {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            }
            else
            {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax)
                return;

            // compute custom offsets from direction sign bit

            int offsetXFront = (int)((uint)ByteUtil.floatToRawIntBits(dirX) >> 31);//>>>
            int offsetYFront = (int)((uint)ByteUtil.floatToRawIntBits(dirY) >> 31);//>>>
            int offsetZFront = (int)((uint)ByteUtil.floatToRawIntBits(dirZ) >> 31);//>>>

            int offsetXBack = offsetXFront ^ 1;
            int offsetYBack = offsetYFront ^ 1;
            int offsetZBack = offsetZFront ^ 1;

            int offsetXFront3 = offsetXFront * 3;
            int offsetYFront3 = offsetYFront * 3;
            int offsetZFront3 = offsetZFront * 3;

            int offsetXBack3 = offsetXBack * 3;
            int offsetYBack3 = offsetYBack * 3;
            int offsetZBack3 = offsetZBack * 3;

            // avoid always adding 1 during the inner loop
            offsetXFront++;
            offsetYFront++;
            offsetZFront++;
            offsetXBack++;
            offsetYBack++;
            offsetZBack++;

            IntersectionState.StackNode[] stack = state.getStack();
            int stackTop = state.getStackTop();
            int stackPos = stackTop;
            int node = 0;

            while (true)
            {
            pushloop:
                while (true)
                {
                    int tn = tree[node];
                    int axis = tn & (7 << 29);
                    int offset = tn & ~(7 << 29);
                    switch (axis)
                    {
                        case 0:
                            {
                                // x axis
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetXFront]) - orgX) * invDirX;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetXBack]) - orgX) * invDirX;
                                // ray passes between clip zones
                                if (tf < intervalMin && tb > intervalMax)
                                    goto pushloopend;
                                int back = offset + offsetXBack3;
                                node = back;
                                // ray passes through far node only
                                if (tf < intervalMin)
                                {
                                    intervalMin = (tb >= intervalMin) ? tb : intervalMin;
                                    continue;
                                }
                                node = offset + offsetXFront3; // front
                                // ray passes through near node only
                                if (tb > intervalMax)
                                {
                                    intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                    continue;
                                }
                                // ray passes through both nodes
                                // push back node
                                stack[stackPos].node = back;
                                stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                                stack[stackPos].far = intervalMax;
                                stackPos++;
                                // update ray interval for front node
                                intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                continue;
                            }
                        case 1 << 30:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetYFront]) - orgY) * invDirY;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetYBack]) - orgY) * invDirY;
                                // ray passes between clip zones
                                if (tf < intervalMin && tb > intervalMax)
                                    goto pushloopend;
                                int back = offset + offsetYBack3;
                                node = back;
                                // ray passes through far node only
                                if (tf < intervalMin)
                                {
                                    intervalMin = (tb >= intervalMin) ? tb : intervalMin;
                                    continue;
                                }
                                node = offset + offsetYFront3; // front
                                // ray passes through near node only
                                if (tb > intervalMax)
                                {
                                    intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                    continue;
                                }
                                // ray passes through both nodes
                                // push back node
                                stack[stackPos].node = back;
                                stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                                stack[stackPos].far = intervalMax;
                                stackPos++;
                                // update ray interval for front node
                                intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                continue;
                            }
                        case 2 << 30:
                            {
                                // z axis
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetZFront]) - orgZ) * invDirZ;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetZBack]) - orgZ) * invDirZ;
                                // ray passes between clip zones
                                if (tf < intervalMin && tb > intervalMax)
                                    goto pushloopend;
                                int back = offset + offsetZBack3;
                                node = back;
                                // ray passes through far node only
                                if (tf < intervalMin)
                                {
                                    intervalMin = (tb >= intervalMin) ? tb : intervalMin;
                                    continue;
                                }
                                node = offset + offsetZFront3; // front
                                // ray passes through near node only
                                if (tb > intervalMax)
                                {
                                    intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                    continue;
                                }
                                // ray passes through both nodes
                                // push back node
                                stack[stackPos].node = back;
                                stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                                stack[stackPos].far = intervalMax;
                                stackPos++;
                                // update ray interval for front node
                                intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                                continue;
                            }
                        case 3 << 30:
                            {
                                // leaf - test some objects
                                int n = tree[node + 1];
                                while (n > 0)
                                {
                                    primitives.intersectPrimitive(r, objects[offset], state);
                                    n--;
                                    offset++;
                                }
                                goto pushloopend;
                            }
                        case 1 << 29:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetXFront]) - orgX) * invDirX;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetXBack]) - orgX) * invDirX;
                                node = offset;
                                intervalMin = (tf >= intervalMin) ? tf : intervalMin;
                                intervalMax = (tb <= intervalMax) ? tb : intervalMax;
                                if (intervalMin > intervalMax)
                                    goto pushloopend;
                                continue;
                            }
                        case 3 << 29:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetYFront]) - orgY) * invDirY;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetYBack]) - orgY) * invDirY;
                                node = offset;
                                intervalMin = (tf >= intervalMin) ? tf : intervalMin;
                                intervalMax = (tb <= intervalMax) ? tb : intervalMax;
                                if (intervalMin > intervalMax)
                                    goto pushloopend;
                                continue;
                            }
                        case 5 << 29:
                            {
                                float tf = (ByteUtil.intBitsToFloat(tree[node + offsetZFront]) - orgZ) * invDirZ;
                                float tb = (ByteUtil.intBitsToFloat(tree[node + offsetZBack]) - orgZ) * invDirZ;
                                node = offset;
                                intervalMin = (tf >= intervalMin) ? tf : intervalMin;
                                intervalMax = (tb <= intervalMax) ? tb : intervalMax;
                                if (intervalMin > intervalMax)
                                    goto pushloopend;
                                continue;
                            }
                        default:
                            return; // should not happen
                    } // switch
                } // traversal loop
            pushloopend:
                do
                {
                    // stack is empty?
                    if (stackPos == stackTop)
                        return;
                    // move back up the stack
                    stackPos--;
                    intervalMin = stack[stackPos].near;
                    if (r.getMax() < intervalMin)
                        continue;
                    node = stack[stackPos].node;
                    intervalMax = stack[stackPos].far;
                    break;
                } while (true);
            }
        }
Exemple #11
0
        public void intersectPrimitive(Ray r, int primID, IntersectionState state)
        {
            // ray patch intersection
            float[] stack = state.getRobustStack();
            int STACKSIZE = 64;
            {
                // init patch
                float[] patch = patches[primID];
                for (int i = 0; i < 4 * 4 * 3; i++)
                    stack[i] = patch[i];
                stack[48] = float.PositiveInfinity; // bbox size
                stack[49] = 0; // umin
                stack[50] = 0; // vmin
                stack[51] = 1; // umax
                stack[52] = 1; // vmax
            }
            int stackpos = 0;
            float orgX = r.ox, invDirX = 1 / r.dx;
            float orgY = r.oy, invDirY = 1 / r.dy;
            float orgZ = r.oz, invDirZ = 1 / r.dz;
            float t1, t2;
            while (stackpos >= 0)
            {
                float intervalMin = r.getMin();
                float intervalMax = r.getMax();
                // x-axis bbox
                float minx = stack[stackpos + 0];
                float maxx = stack[stackpos + 0];
                for (int j = 1, idx = stackpos + 3; j < 4 * 4; j++, idx += 3)
                {
                    if (minx > stack[idx])
                        minx = stack[idx];
                    if (maxx < stack[idx])
                        maxx = stack[idx];
                }
                t1 = (minx - orgX) * invDirX;
                t2 = (maxx - orgX) * invDirX;
                if (invDirX > 0)
                {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                }
                else
                {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                {
                    stackpos -= STACKSIZE;
                    continue;
                }
                // y-axis bbox
                float miny = stack[stackpos + 1];
                float maxy = stack[stackpos + 1];
                for (int j = 1, idx = stackpos + 4; j < 4 * 4; j++, idx += 3)
                {
                    if (miny > stack[idx])
                        miny = stack[idx];
                    if (maxy < stack[idx])
                        maxy = stack[idx];
                }
                t1 = (miny - orgY) * invDirY;
                t2 = (maxy - orgY) * invDirY;
                if (invDirY > 0)
                {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                }
                else
                {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }
                if (intervalMin > intervalMax)
                {
                    stackpos -= STACKSIZE;
                    continue;
                }
                // z-axis bbox
                float minz = stack[stackpos + 2];
                float maxz = stack[stackpos + 2];
                for (int j = 1, idx = stackpos + 5; j < 4 * 4; j++, idx += 3)
                {
                    if (minz > stack[idx])
                        minz = stack[idx];
                    if (maxz < stack[idx])
                        maxz = stack[idx];
                }

                t1 = (minz - orgZ) * invDirZ;
                t2 = (maxz - orgZ) * invDirZ;
                if (invDirZ > 0)
                {
                    if (t1 > intervalMin)
                        intervalMin = t1;
                    if (t2 < intervalMax)
                        intervalMax = t2;
                }
                else
                {
                    if (t2 > intervalMin)
                        intervalMin = t2;
                    if (t1 < intervalMax)
                        intervalMax = t1;
                }

                if (intervalMin > intervalMax)
                {
                    stackpos -= STACKSIZE;
                    continue;
                }
                // intersection was found - keep going
                float size = (maxx - minx) + (maxy - miny) + (maxz - minz);
                if (ByteUtil.floatToRawIntBits(stack[stackpos + 48]) == ByteUtil.floatToRawIntBits(size))
                {
                    // L1 norm is 0, we are done
                    r.setMax(intervalMin);
                    state.setIntersection(primID, stack[stackpos + 49], stack[stackpos + 50]);
                    stackpos -= STACKSIZE;
                    continue;
                }
                // not small enough yet - subdivide
                // lets pick a subdivision axis first:
                float sizeu = 0;
                float sizev = 0;
                for (int i = 0; i < 3; i++)
                {
                    sizeu += System.Math.Abs(stack[stackpos + (0 * 4 + 3) * 3 + i] - stack[stackpos + i]);
                    sizev += System.Math.Abs(stack[stackpos + (3 * 4 + 0) * 3 + i] - stack[stackpos + i]);
                }

                if (sizeu > sizev)
                {
                    // split in U direction
                    for (int i = 0; i < 4; i++)
                    {
                        for (int axis = 0; axis < 3; axis++)
                        {
                            // load data
                            float p0 = stack[stackpos + (i * 4 + 0) * 3 + axis];
                            float p1 = stack[stackpos + (i * 4 + 1) * 3 + axis];
                            float p2 = stack[stackpos + (i * 4 + 2) * 3 + axis];
                            float p3 = stack[stackpos + (i * 4 + 3) * 3 + axis];
                            // Split curve in the middle
                            float q0 = p0;
                            float q1 = (p0 + p1) * 0.5f;
                            float q2 = q1 * 0.5f + (p1 + p2) * 0.25f;
                            float r3 = p3;
                            float r2 = (p2 + p3) * 0.5f;
                            float r1 = r2 * 0.5f + (p1 + p2) * 0.25f;
                            float q3 = (q2 + r1) * 0.5f;
                            float r0 = q3;
                            // load new curve data into the stack
                            stack[stackpos + (i * 4 + 0) * 3 + axis] = q0;
                            stack[stackpos + (i * 4 + 1) * 3 + axis] = q1;
                            stack[stackpos + (i * 4 + 2) * 3 + axis] = q2;
                            stack[stackpos + (i * 4 + 3) * 3 + axis] = q3;
                            stack[stackpos + STACKSIZE + (i * 4 + 0) * 3 + axis] = r0;
                            stack[stackpos + STACKSIZE + (i * 4 + 1) * 3 + axis] = r1;
                            stack[stackpos + STACKSIZE + (i * 4 + 2) * 3 + axis] = r2;
                            stack[stackpos + STACKSIZE + (i * 4 + 3) * 3 + axis] = r3;
                        }
                    }
                    // copy current bbox size
                    stack[stackpos + 48] = stack[stackpos + STACKSIZE + 48] = size;
                    // finally - split uv ranges
                    float umin = stack[stackpos + 49];
                    float umax = stack[stackpos + 51];
                    stack[stackpos + 49] = umin;
                    stack[stackpos + STACKSIZE + 50] = stack[stackpos + 50];
                    stack[stackpos + 51] = stack[stackpos + STACKSIZE + 49] = (umin + umax) * 0.5f;
                    stack[stackpos + STACKSIZE + 51] = umax;
                    stack[stackpos + STACKSIZE + 52] = stack[stackpos + 52];
                }
                else
                {
                    // split in V direction
                    for (int i = 0; i < 4; i++)
                    {
                        for (int axis = 0; axis < 3; axis++)
                        {
                            // load data
                            float p0 = stack[stackpos + (0 * 4 + i) * 3 + axis];
                            float p1 = stack[stackpos + (1 * 4 + i) * 3 + axis];
                            float p2 = stack[stackpos + (2 * 4 + i) * 3 + axis];
                            float p3 = stack[stackpos + (3 * 4 + i) * 3 + axis];
                            // Split curve in the middle
                            float q0 = p0;
                            float q1 = (p0 + p1) * 0.5f;
                            float q2 = q1 * 0.5f + (p1 + p2) * 0.25f;
                            float r3 = p3;
                            float r2 = (p2 + p3) * 0.5f;
                            float r1 = r2 * 0.5f + (p1 + p2) * 0.25f;
                            float q3 = (q2 + r1) * 0.5f;
                            float r0 = q3;
                            // load new curve data into the stack
                            stack[stackpos + (0 * 4 + i) * 3 + axis] = q0;
                            stack[stackpos + (1 * 4 + i) * 3 + axis] = q1;
                            stack[stackpos + (2 * 4 + i) * 3 + axis] = q2;
                            stack[stackpos + (3 * 4 + i) * 3 + axis] = q3;
                            stack[stackpos + STACKSIZE + (0 * 4 + i) * 3 + axis] = r0;
                            stack[stackpos + STACKSIZE + (1 * 4 + i) * 3 + axis] = r1;
                            stack[stackpos + STACKSIZE + (2 * 4 + i) * 3 + axis] = r2;
                            stack[stackpos + STACKSIZE + (3 * 4 + i) * 3 + axis] = r3;
                        }
                    }
                    // copy current bbox size
                    stack[stackpos + 48] = stack[stackpos + STACKSIZE + 48] = size;
                    // finally - split uv ranges
                    float vmin = stack[stackpos + 50];
                    float vmax = stack[stackpos + 52];
                    stack[stackpos + STACKSIZE + 49] = stack[stackpos + 49];
                    stack[stackpos + 50] = vmin;
                    stack[stackpos + 52] = stack[stackpos + STACKSIZE + 50] = (vmin + vmax) * 0.5f;
                    stack[stackpos + STACKSIZE + 51] = stack[stackpos + 51];
                    stack[stackpos + STACKSIZE + 52] = vmax;
                }
                stackpos += STACKSIZE;
            }
        }