예제 #1
0
            public void intersectBox(Ray r, float hx, float hy, float hz, int primID, IntersectionState state)
            {
                switch (k)
                {
                case 0:
                {
                    float hu = hy;
                    float hv = hz;
                    float u  = hu * bnu + hv * bnv + bnd;
                    if (u < 0.0f)
                    {
                        u = 0;
                    }
                    float v = hu * cnu + hv * cnv + cnd;
                    if (v < 0.0f)
                    {
                        v = 0;
                    }
                    state.setIntersection(primID, u, v);
                    return;
                }

                case 1:
                {
                    float hu = hz;
                    float hv = hx;
                    float u  = hu * bnu + hv * bnv + bnd;
                    if (u < 0.0f)
                    {
                        u = 0;
                    }
                    float v = hu * cnu + hv * cnv + cnd;
                    if (v < 0.0f)
                    {
                        v = 0;
                    }
                    state.setIntersection(primID, u, v);
                    return;
                }

                case 2:
                {
                    float hu = hx;
                    float hv = hy;
                    float u  = hu * bnu + hv * bnv + bnd;
                    if (u < 0.0f)
                    {
                        u = 0;
                    }
                    float v = hu * cnu + hv * cnv + cnd;
                    if (v < 0.0f)
                    {
                        v = 0;
                    }
                    state.setIntersection(primID, u, v);
                    return;
                }
                }
            }
예제 #2
0
파일: Sphere.cs 프로젝트: rzel/sunflowsharp
        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);
            }
        }
예제 #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);
            }
        }
예제 #4
0
 public void intersectPrimitive(Ray r, int primID, IntersectionState state)
 {
     if (r.getMax() == float.PositiveInfinity)
     {
         state.setIntersection(0, 0, 0);
     }
 }
예제 #5
0
        private void intersectTriangleKensler(Ray r, int primID, IntersectionState state)
        {
            int   tri    = 3 * primID;
            int   a      = 3 * triangles[tri + 0];
            int   b      = 3 * triangles[tri + 1];
            int   c      = 3 * triangles[tri + 2];
            float edge0x = points[b + 0] - points[a + 0];
            float edge0y = points[b + 1] - points[a + 1];
            float edge0z = points[b + 2] - points[a + 2];
            float edge1x = points[a + 0] - points[c + 0];
            float edge1y = points[a + 1] - points[c + 1];
            float edge1z = points[a + 2] - points[c + 2];
            float nx     = edge0y * edge1z - edge0z * edge1y;
            float ny     = edge0z * edge1x - edge0x * edge1z;
            float nz     = edge0x * edge1y - edge0y * edge1x;
            float v      = r.dot(nx, ny, nz);
            float iv     = 1 / v;
            float edge2x = points[a + 0] - r.ox;
            float edge2y = points[a + 1] - r.oy;
            float edge2z = points[a + 2] - r.oz;
            float va     = nx * edge2x + ny * edge2y + nz * edge2z;
            float t      = iv * va;

            if (!r.isInside(t))
            {
                return;
            }
            float ix   = edge2y * r.dz - edge2z * r.dy;
            float iy   = edge2z * r.dx - edge2x * r.dz;
            float iz   = edge2x * r.dy - edge2y * r.dx;
            float v1   = ix * edge1x + iy * edge1y + iz * edge1z;
            float beta = iv * v1;

            if (beta < 0)
            {
                return;
            }
            float v2 = ix * edge0x + iy * edge0y + iz * edge0z;

            if ((v1 + v2) * v > v * v)
            {
                return;
            }
            float gamma = iv * v2;

            if (gamma < 0)
            {
                return;
            }
            r.setMax(t);
            state.setIntersection(primID, beta, gamma);
        }
예제 #6
0
        public void intersectPrimitive(Ray r, int primID, IntersectionState state)
        {
            float dn = normal.x * r.dx + normal.y * r.dy + normal.z * r.dz;

            if (dn == 0.0)
            {
                return;
            }
            float t = (((center.x - r.ox) * normal.x) + ((center.y - r.oy) * normal.y) + ((center.z - r.oz) * normal.z)) / dn;

            if (r.isInside(t))
            {
                r.setMax(t);
                state.setIntersection(0);
            }
        }
예제 #7
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);
                        return;
                    }
                }
            }
        }
예제 #8
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);
                        return;
                    }
                }
            }
        }
예제 #9
0
        public void intersectPrimitive(Ray r, int primID, IntersectionState state)
        {
            float intervalMin = float.NegativeInfinity;
            float intervalMax = float.PositiveInfinity;
            float orgX = r.ox;
            float invDirX = 1 / r.dx;
            float t1, t2;

            t1 = (minX - orgX) * invDirX;
            t2 = (maxX - orgX) * invDirX;
            int sideIn = -1, sideOut = -1;

            if (invDirX > 0)
            {
                if (t1 > intervalMin)
                {
                    intervalMin = t1;
                    sideIn      = 0;
                }
                if (t2 < intervalMax)
                {
                    intervalMax = t2;
                    sideOut     = 1;
                }
            }
            else
            {
                if (t2 > intervalMin)
                {
                    intervalMin = t2;
                    sideIn      = 1;
                }
                if (t1 < intervalMax)
                {
                    intervalMax = t1;
                    sideOut     = 0;
                }
            }
            if (intervalMin > intervalMax)
            {
                return;
            }
            float orgY    = r.oy;
            float invDirY = 1 / r.dy;

            t1 = (minY - orgY) * invDirY;
            t2 = (maxY - orgY) * invDirY;
            if (invDirY > 0)
            {
                if (t1 > intervalMin)
                {
                    intervalMin = t1;
                    sideIn      = 2;
                }
                if (t2 < intervalMax)
                {
                    intervalMax = t2;
                    sideOut     = 3;
                }
            }
            else
            {
                if (t2 > intervalMin)
                {
                    intervalMin = t2;
                    sideIn      = 3;
                }
                if (t1 < intervalMax)
                {
                    intervalMax = t1;
                    sideOut     = 2;
                }
            }
            if (intervalMin > intervalMax)
            {
                return;
            }
            float orgZ    = r.oz;
            float invDirZ = 1 / r.dz;

            t1 = (minZ - orgZ) * invDirZ; // no front wall
            t2 = (maxZ - orgZ) * invDirZ;
            if (invDirZ > 0)
            {
                if (t1 > intervalMin)
                {
                    intervalMin = t1;
                    sideIn      = 4;
                }
                if (t2 < intervalMax)
                {
                    intervalMax = t2;
                    sideOut     = 5;
                }
            }
            else
            {
                if (t2 > intervalMin)
                {
                    intervalMin = t2;
                    sideIn      = 5;
                }
                if (t1 < intervalMax)
                {
                    intervalMax = t1;
                    sideOut     = 4;
                }
            }
            if (intervalMin > intervalMax)
            {
                return;
            }
            Debug.Assert(sideIn != -1);
            Debug.Assert(sideOut != -1);
            // can't hit minY wall, there is none
            if (sideIn != 2 && r.isInside(intervalMin))
            {
                r.setMax(intervalMin);
                state.setIntersection(sideIn);
            }
            else if (sideOut != 2 && r.isInside(intervalMax))
            {
                r.setMax(intervalMax);
                state.setIntersection(sideOut);
            }
        }
예제 #10
0
            public void intersectPrimitive(Ray r, int primID, IntersectionState state)
            {
                float uv00 = 0, uv01 = 0, uv10 = 0, uv11 = 0, uv20 = 0, uv21 = 0;

                switch (triangleMesh.uvs.interp)
                {
                case ParameterList.InterpolationType.NONE:
                case ParameterList.InterpolationType.FACE:
                default:
                    return;

                case ParameterList.InterpolationType.VERTEX:
                {
                    int     tri    = 3 * primID;
                    int     index0 = triangleMesh.triangles[tri + 0];
                    int     index1 = triangleMesh.triangles[tri + 1];
                    int     index2 = triangleMesh.triangles[tri + 2];
                    int     i20    = 2 * index0;
                    int     i21    = 2 * index1;
                    int     i22    = 2 * index2;
                    float[] uvs    = triangleMesh.uvs.data;
                    uv00 = uvs[i20 + 0];
                    uv01 = uvs[i20 + 1];
                    uv10 = uvs[i21 + 0];
                    uv11 = uvs[i21 + 1];
                    uv20 = uvs[i22 + 0];
                    uv21 = uvs[i22 + 1];
                    break;
                }

                case ParameterList.InterpolationType.FACEVARYING:
                {
                    int     idx = (3 * primID) << 1;
                    float[] uvs = triangleMesh.uvs.data;
                    uv00 = uvs[idx + 0];
                    uv01 = uvs[idx + 1];
                    uv10 = uvs[idx + 2];
                    uv11 = uvs[idx + 3];
                    uv20 = uvs[idx + 4];
                    uv21 = uvs[idx + 5];
                    break;
                }
                }

                double edge1x = uv10 - uv00;
                double edge1y = uv11 - uv01;
                double edge2x = uv20 - uv00;
                double edge2y = uv21 - uv01;
                double pvecx = r.dy * 0 - r.dz * edge2y;
                double pvecy = r.dz * edge2x - r.dx * 0;
                double pvecz = r.dx * edge2y - r.dy * edge2x;
                double qvecx, qvecy, qvecz;
                double u, v;
                double det = edge1x * pvecx + edge1y * pvecy + 0 * pvecz;

                if (det > 0)
                {
                    double tvecx = r.ox - uv00;
                    double tvecy = r.oy - uv01;
                    double tvecz = r.oz;
                    u = (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz);
                    if (u < 0.0 || u > det)
                    {
                        return;
                    }
                    qvecx = tvecy * 0 - tvecz * edge1y;
                    qvecy = tvecz * edge1x - tvecx * 0;
                    qvecz = tvecx * edge1y - tvecy * edge1x;
                    v     = (r.dx * qvecx + r.dy * qvecy + r.dz * qvecz);
                    if (v < 0.0 || u + v > det)
                    {
                        return;
                    }
                }
                else if (det < 0)
                {
                    double tvecx = r.ox - uv00;
                    double tvecy = r.oy - uv01;
                    double tvecz = r.oz;
                    u = (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz);
                    if (u > 0.0 || u < det)
                    {
                        return;
                    }
                    qvecx = tvecy * 0 - tvecz * edge1y;
                    qvecy = tvecz * edge1x - tvecx * 0;
                    qvecz = tvecx * edge1y - tvecy * edge1x;
                    v     = (r.dx * qvecx + r.dy * qvecy + r.dz * qvecz);
                    if (v > 0.0 || u + v < det)
                    {
                        return;
                    }
                }
                else
                {
                    return;
                }
                double inv_det = 1.0 / det;
                float  t       = (float)((edge2x * qvecx + edge2y * qvecy + 0 * qvecz) * inv_det);

                if (r.isInside(t))
                {
                    r.setMax(t);
                    state.setIntersection(primID, (float)(u * inv_det), (float)(v * inv_det));
                }
            }
예제 #11
0
            public void intersect(Ray r, int primID, IntersectionState state)
            {
                switch (k)
                {
                case 0:
                {
                    float det = 1.0f / (r.dx + nu * r.dy + nv * r.dz);
                    float t   = (nd - r.ox - nu * r.oy - nv * r.oz) * det;
                    if (!r.isInside(t))
                    {
                        return;
                    }
                    float hu = r.oy + t * r.dy;
                    float hv = r.oz + t * r.dz;
                    float u  = hu * bnu + hv * bnv + bnd;
                    if (u < 0.0f)
                    {
                        return;
                    }
                    float v = hu * cnu + hv * cnv + cnd;
                    if (v < 0.0f)
                    {
                        return;
                    }
                    if (u + v > 1.0f)
                    {
                        return;
                    }
                    r.setMax(t);
                    state.setIntersection(primID, u, v);
                    return;
                }

                case 1:
                {
                    float det = 1.0f / (r.dy + nu * r.dz + nv * r.dx);
                    float t   = (nd - r.oy - nu * r.oz - nv * r.ox) * det;
                    if (!r.isInside(t))
                    {
                        return;
                    }
                    float hu = r.oz + t * r.dz;
                    float hv = r.ox + t * r.dx;
                    float u  = hu * bnu + hv * bnv + bnd;
                    if (u < 0.0f)
                    {
                        return;
                    }
                    float v = hu * cnu + hv * cnv + cnd;
                    if (v < 0.0f)
                    {
                        return;
                    }
                    if (u + v > 1.0f)
                    {
                        return;
                    }
                    r.setMax(t);
                    state.setIntersection(primID, u, v);
                    return;
                }

                case 2:
                {
                    float det = 1.0f / (r.dz + nu * r.dx + nv * r.dy);
                    float t   = (nd - r.oz - nu * r.ox - nv * r.oy) * det;
                    if (!r.isInside(t))
                    {
                        return;
                    }
                    float hu = r.ox + t * r.dx;
                    float hv = r.oy + t * r.dy;
                    float u  = hu * bnu + hv * bnv + bnd;
                    if (u < 0.0f)
                    {
                        return;
                    }
                    float v = hu * cnu + hv * cnv + cnd;
                    if (v < 0.0f)
                    {
                        return;
                    }
                    if (u + v > 1.0f)
                    {
                        return;
                    }
                    r.setMax(t);
                    state.setIntersection(primID, u, v);
                    return;
                }
                }
            }
예제 #12
0
        public void intersectPrimitive(Ray r, int primID, IntersectionState state)
        {
            // ray/bilinear patch intersection adapted from "Production Rendering:
            // Design and Implementation" by Ian Stephenson (Ed.)
            int quad = 4 * primID;
            int p0   = 3 * quads[quad + 0];
            int p1   = 3 * quads[quad + 1];
            int p2   = 3 * quads[quad + 2];
            int p3   = 3 * quads[quad + 3];

            // transform patch into Hilbert space
            float[] A =
            {
                points[p2 + 0] - points[p3 + 0] - points[p1 + 0] + points[p0 + 0],
                points[p2 + 1] - points[p3 + 1] - points[p1 + 1] + points[p0 + 1],
                points[p2 + 2] - points[p3 + 2] - points[p1 + 2] + points[p0 + 2]
            };
            float[] B = { points[p1 + 0] - points[p0 + 0],
                          points[p1 + 1] - points[p0 + 1],
                          points[p1 + 2] - points[p0 + 2] };
            float[] C = { points[p3 + 0] - points[p0 + 0],
                          points[p3 + 1] - points[p0 + 1],
                          points[p3 + 2] - points[p0 + 2] };
            float[] R = { r.ox - points[p0 + 0], r.oy - points[p0 + 1],
                          r.oz - points[p0 + 2] };
            float[] Q = { r.dx, r.dy, r.dz };

            // pick major direction
            float absqx = Math.Abs(r.dx);
            float absqy = Math.Abs(r.dy);
            float absqz = Math.Abs(r.dz);

            int X = 0, Y = 1, Z = 2;

            if (absqx > absqy && absqx > absqz)
            {
                // X = 0, Y = 1, Z = 2
            }
            else if (absqy > absqz)
            {
                // X = 1, Y = 0, Z = 2
                X = 1;
                Y = 0;
            }
            else
            {
                // X = 2, Y = 1, Z = 0
                X = 2;
                Z = 0;
            }

            float Cxz = C[X] * Q[Z] - C[Z] * Q[X];
            float Cyx = C[Y] * Q[X] - C[X] * Q[Y];
            float Czy = C[Z] * Q[Y] - C[Y] * Q[Z];
            float Rxz = R[X] * Q[Z] - R[Z] * Q[X];
            float Ryx = R[Y] * Q[X] - R[X] * Q[Y];
            float Rzy = R[Z] * Q[Y] - R[Y] * Q[Z];
            float Bxy = B[X] * Q[Y] - B[Y] * Q[X];
            float Byz = B[Y] * Q[Z] - B[Z] * Q[Y];
            float Bzx = B[Z] * Q[X] - B[X] * Q[Z];
            float a   = A[X] * Byz + A[Y] * Bzx + A[Z] * Bxy;

            if (a == 0)
            {
                // setup for linear equation
                float b = B[X] * Czy + B[Y] * Cxz + B[Z] * Cyx;
                float c = C[X] * Rzy + C[Y] * Rxz + C[Z] * Ryx;
                float u = -c / b;
                if (u >= 0 && u <= 1)
                {
                    float v = (u * Bxy + Ryx) / Cyx;
                    if (v >= 0 && v <= 1)
                    {
                        float t = (B[X] * u + C[X] * v - R[X]) / Q[X];
                        if (r.isInside(t))
                        {
                            r.setMax(t);
                            state.setIntersection(primID, u, v);
                        }
                    }
                }
            }
            else
            {
                // setup for quadratic equation
                float b       = A[X] * Rzy + A[Y] * Rxz + A[Z] * Ryx + B[X] * Czy + B[Y] * Cxz + B[Z] * Cyx;
                float c       = C[X] * Rzy + C[Y] * Rxz + C[Z] * Ryx;
                float discrim = b * b - 4 * a * c;
                // reject trivial cases
                if (c * (a + b + c) > 0 && (discrim < 0 || a * c < 0 || b / a > 0 || b / a < -2))
                {
                    return;
                }
                // solve quadratic
                float q = b > 0 ? -0.5f * (b + (float)Math.Sqrt(discrim)) : -0.5f * (b - (float)Math.Sqrt(discrim));
                // check first solution
                float Axy = A[X] * Q[Y] - A[Y] * Q[X];
                float u   = q / a;
                if (u >= 0 && u <= 1)
                {
                    float d = u * Axy - Cyx;
                    float v = -(u * Bxy + Ryx) / d;
                    if (v >= 0 && v <= 1)
                    {
                        float t = (A[X] * u * v + B[X] * u + C[X] * v - R[X]) / Q[X];
                        if (r.isInside(t))
                        {
                            r.setMax(t);
                            state.setIntersection(primID, u, v);
                        }
                    }
                }
                u = c / q;
                if (u >= 0 && u <= 1)
                {
                    float d = u * Axy - Cyx;
                    float v = -(u * Bxy + Ryx) / d;
                    if (v >= 0 && v <= 1)
                    {
                        float t = (A[X] * u * v + B[X] * u + C[X] * v - R[X]) / Q[X];
                        if (r.isInside(t))
                        {
                            r.setMax(t);
                            state.setIntersection(primID, u, v);
                        }
                    }
                }
            }
        }
예제 #13
0
        public void intersectPrimitive(Ray r, int primID, IntersectionState state)
        {
            int   hair  = primID / numSegments;
            int   line  = primID % numSegments;
            int   vRoot = hair * 3 * (numSegments + 1);
            int   v0    = vRoot + line * 3;
            int   v1    = v0 + 3;
            float vx    = points[v1 + 0] - points[v0 + 0];
            float vy    = points[v1 + 1] - points[v0 + 1];
            float vz    = points[v1 + 2] - points[v0 + 2];
            float ux    = r.dy * vz - r.dz * vy;
            float uy    = r.dz * vx - r.dx * vz;
            float uz    = r.dx * vy - r.dy * vx;
            float nx    = uy * vz - uz * vy;
            float ny    = uz * vx - ux * vz;
            float nz    = ux * vy - uy * vx;
            float tden  = 1 / (nx * r.dx + ny * r.dy + nz * r.dz);
            float tnum  = nx * (points[v0 + 0] - r.ox) + ny * (points[v0 + 1] - r.oy) + nz * (points[v0 + 2] - r.oz);
            float t     = tnum * tden;

            if (r.isInside(t))
            {
                int   vn = hair * (numSegments + 1) + line;
                float px = r.ox + t * r.dx;
                float py = r.oy + t * r.dy;
                float pz = r.oz + t * r.dz;
                float qx = px - points[v0 + 0];
                float qy = py - points[v0 + 1];
                float qz = pz - points[v0 + 2];
                float q  = (vx * qx + vy * qy + vz * qz) / (vx * vx + vy * vy + vz * vz);
                if (q <= 0)
                {
                    // don't included rounded tip at root
                    if (line == 0)
                    {
                        return;
                    }
                    float dx    = points[v0 + 0] - px;
                    float dy    = points[v0 + 1] - py;
                    float dz    = points[v0 + 2] - pz;
                    float d2    = dx * dx + dy * dy + dz * dz;
                    float width = getWidth(vn);
                    if (d2 < (width * width * 0.25f))
                    {
                        r.setMax(t);
                        state.setIntersection(primID, 0, 0);
                    }
                }
                else if (q >= 1)
                {
                    float dx    = points[v1 + 0] - px;
                    float dy    = points[v1 + 1] - py;
                    float dz    = points[v1 + 2] - pz;
                    float d2    = dx * dx + dy * dy + dz * dz;
                    float width = getWidth(vn + 1);
                    if (d2 < (width * width * 0.25f))
                    {
                        r.setMax(t);
                        state.setIntersection(primID, 0, 1);
                    }
                }
                else
                {
                    float dx    = points[v0 + 0] + q * vx - px;
                    float dy    = points[v0 + 1] + q * vy - py;
                    float dz    = points[v0 + 2] + q * vz - pz;
                    float d2    = dx * dx + dy * dy + dz * dz;
                    float width = (1 - q) * getWidth(vn) + q * getWidth(vn + 1);
                    if (d2 < (width * width * 0.25f))
                    {
                        r.setMax(t);
                        state.setIntersection(primID, 0, q);
                    }
                }
            }
        }
예제 #14
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);
            }
        }
예제 #15
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;
            }
        }
예제 #16
0
        private void intersectFlake(Ray r, IntersectionState state, int level, float qa, float qaInv, float cx, float cy, float cz, float dx, float dy, float dz, float radius)
        {
            if (level <= 0) {
                // we reached the bottom - intersect sphere and bail out
                float vcx = cx - r.ox;
                float vcy = cy - r.oy;
                float vcz = cz - r.oz;
                float b = r.dx * vcx + r.dy * vcy + r.dz * vcz;
                float disc = b * b - qa * ((vcx * vcx + vcy * vcy + vcz * vcz) - radius * radius);
                if (disc > 0) {
                    // intersects - check t values
                    float d = (float) Math.Sqrt(disc);
                    float t1 = (b - d) * qaInv;
                    float t2 = (b + d) * qaInv;
                    if (t1 >= r.getMax() || t2 <= r.getMin())
                        return;
                    if (t1 > r.getMin())
                        r.setMax(t1);
                    else
                        r.setMax(t2);
                    state.setIntersection(0, cx, cy, cz);
                }
            } else {
                float boundRadius = radius * (1 + boundingRadiusOffset[level]);
                float vcx = cx - r.ox;
                float vcy = cy - r.oy;
                float vcz = cz - r.oz;
                float b = r.dx * vcx + r.dy * vcy + r.dz * vcz;
                float vcd = (vcx * vcx + vcy * vcy + vcz * vcz);
                float disc = b * b - qa * (vcd - boundRadius * boundRadius);
                if (disc > 0) {
                    // intersects - check t values
                    float d = (float) Math.Sqrt(disc);
                    float t1 = (b - d) * qaInv;
                    float t2 = (b + d) * qaInv;
                    if (t1 >= r.getMax() || t2 <= r.getMin())
                        return;

                    // we hit the bounds, now compute intersection with the actual
                    // leaf sphere
                    disc = b * b - qa * (vcd - radius * radius);
                    if (disc > 0) {
                        d = (float) Math.Sqrt(disc);
                        t1 = (b - d) * qaInv;
                        t2 = (b + d) * qaInv;
                        if (t1 >= r.getMax() || t2 <= r.getMin()) {
                            // no hit
                        } else {
                            if (t1 > r.getMin())
                                r.setMax(t1);
                            else
                                r.setMax(t2);
                            state.setIntersection(0, cx, cy, cz);
                        }
                    }

                    // recursively intersect 9 other spheres
                    // step1: compute basis around displacement vector
                    float b1x, b1y, b1z;
                    if (dx * dx < dy * dy && dx * dx < dz * dz) {
                        b1x = 0;
                        b1y = dz;
                        b1z = -dy;
                    }
                    else if (dy * dy < dz * dz)
                    {
                        b1x = dz;
                        b1y = 0;
                        b1z = -dx;
                    }
                    else
                    {
                        b1x = dy;
                        b1y = -dx;
                        b1z = 0;
                    }

                    float n = 1 / (float) Math.Sqrt(b1x * b1x + b1y * b1y + b1z * b1z);
                    b1x *= n;
                    b1y *= n;
                    b1z *= n;
                    float b2x = dy * b1z - dz * b1y;
                    float b2y = dz * b1x - dx * b1z;
                    float b2z = dx * b1y - dy * b1x;
                    b1x = dy * b2z - dz * b2y;
                    b1y = dz * b2x - dx * b2z;
                    b1z = dx * b2y - dy * b2x;
                    // step2: generate 9 children recursively
                    float nr = radius * (1 / 3.0f), scale = radius + nr;
                    for (int i = 0; i < 9 * 3; i += 3) {
                        // transform by basis
                        float ndx = recursivePattern[i] * dx + recursivePattern[i + 1] * b1x + recursivePattern[i + 2] * b2x;
                        float ndy = recursivePattern[i] * dy + recursivePattern[i + 1] * b1y + recursivePattern[i + 2] * b2y;
                        float ndz = recursivePattern[i] * dz + recursivePattern[i + 1] * b1z + recursivePattern[i + 2] * b2z;
                        // recurse !
                        intersectFlake(r, state, level - 1, qa, qaInv, cx + scale * ndx, cy + scale * ndy, cz + scale * ndz, ndx, ndy, ndz, nr);
                    }
                }
            }
        }
예제 #17
0
        private void intersectFlake(Ray r, IntersectionState state, int level, float qa, float qaInv, float cx, float cy, float cz, float dx, float dy, float dz, float radius)
        {
            if (level <= 0)
            {
                // we reached the bottom - intersect sphere and bail out
                float vcx  = cx - r.ox;
                float vcy  = cy - r.oy;
                float vcz  = cz - r.oz;
                float b    = r.dx * vcx + r.dy * vcy + r.dz * vcz;
                float disc = b * b - qa * ((vcx * vcx + vcy * vcy + vcz * vcz) - radius * radius);
                if (disc > 0)
                {
                    // intersects - check t values
                    float d  = (float)Math.Sqrt(disc);
                    float t1 = (b - d) * qaInv;
                    float t2 = (b + d) * qaInv;
                    if (t1 >= r.getMax() || t2 <= r.getMin())
                    {
                        return;
                    }
                    if (t1 > r.getMin())
                    {
                        r.setMax(t1);
                    }
                    else
                    {
                        r.setMax(t2);
                    }
                    state.setIntersection(0, cx, cy, cz);
                }
            }
            else
            {
                float boundRadius = radius * (1 + boundingRadiusOffset[level]);
                float vcx         = cx - r.ox;
                float vcy         = cy - r.oy;
                float vcz         = cz - r.oz;
                float b           = r.dx * vcx + r.dy * vcy + r.dz * vcz;
                float vcd         = (vcx * vcx + vcy * vcy + vcz * vcz);
                float disc        = b * b - qa * (vcd - boundRadius * boundRadius);
                if (disc > 0)
                {
                    // intersects - check t values
                    float d  = (float)Math.Sqrt(disc);
                    float t1 = (b - d) * qaInv;
                    float t2 = (b + d) * qaInv;
                    if (t1 >= r.getMax() || t2 <= r.getMin())
                    {
                        return;
                    }

                    // we hit the bounds, now compute intersection with the actual
                    // leaf sphere
                    disc = b * b - qa * (vcd - radius * radius);
                    if (disc > 0)
                    {
                        d  = (float)Math.Sqrt(disc);
                        t1 = (b - d) * qaInv;
                        t2 = (b + d) * qaInv;
                        if (t1 >= r.getMax() || t2 <= r.getMin())
                        {
                            // no hit
                        }
                        else
                        {
                            if (t1 > r.getMin())
                            {
                                r.setMax(t1);
                            }
                            else
                            {
                                r.setMax(t2);
                            }
                            state.setIntersection(0, cx, cy, cz);
                        }
                    }

                    // recursively intersect 9 other spheres
                    // step1: compute basis around displacement vector
                    float b1x, b1y, b1z;
                    if (dx * dx < dy * dy && dx * dx < dz * dz)
                    {
                        b1x = 0;
                        b1y = dz;
                        b1z = -dy;
                    }
                    else if (dy * dy < dz * dz)
                    {
                        b1x = dz;
                        b1y = 0;
                        b1z = -dx;
                    }
                    else
                    {
                        b1x = dy;
                        b1y = -dx;
                        b1z = 0;
                    }

                    float n = 1 / (float)Math.Sqrt(b1x * b1x + b1y * b1y + b1z * b1z);
                    b1x *= n;
                    b1y *= n;
                    b1z *= n;
                    float b2x = dy * b1z - dz * b1y;
                    float b2y = dz * b1x - dx * b1z;
                    float b2z = dx * b1y - dy * b1x;
                    b1x = dy * b2z - dz * b2y;
                    b1y = dz * b2x - dx * b2z;
                    b1z = dx * b2y - dy * b2x;
                    // step2: generate 9 children recursively
                    float nr = radius * (1 / 3.0f), scale = radius + nr;
                    for (int i = 0; i < 9 * 3; i += 3)
                    {
                        // transform by basis
                        float ndx = recursivePattern[i] * dx + recursivePattern[i + 1] * b1x + recursivePattern[i + 2] * b2x;
                        float ndy = recursivePattern[i] * dy + recursivePattern[i + 1] * b1y + recursivePattern[i + 2] * b2y;
                        float ndz = recursivePattern[i] * dz + recursivePattern[i + 1] * b1z + recursivePattern[i + 2] * b2z;
                        // recurse !
                        intersectFlake(r, state, level - 1, qa, qaInv, cx + scale * ndx, cy + scale * ndy, cz + scale * ndz, ndx, ndy, ndz, nr);
                    }
                }
            }
        }
예제 #18
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;
                }
            }
        }