Example #1
0
 public RayInfo(RayInfo vray) {
     this.Org = vray.Org;
     this.Dir = vray.Dir;
     InvDir = 1f / vray.Dir;
     this.MinT = vray.MinT;
     this.MaxT = vray.MaxT;
 }
Example #2
0
 public override Spectrum tau(RayInfo r, float stepSize, float offset) {
     float t0, t1;
     float length = r.Dir.Length;
     if (length == 0f) return RgbSpectrum.ZeroSpectrum();
     RayInfo rn = new RayInfo(r.Org, r.Dir / length, r.MinT * length, r.MaxT * length);
     if (!IntersectP(rn, out t0, out t1)) return RgbSpectrum.ZeroSpectrum();
     Spectrum tau = new RgbSpectrum();
     t0 += offset * stepSize;
     while (t0 < t1) {
         var pt = rn.Point(t0);
         var d = -rn.Dir;
         tau += sigma_t(ref pt, ref d, 1.0f);
         t0 += stepSize;
     }
     return tau * stepSize;
 }
Example #3
0
        public RgbSpectrum SamplePhoton(SceneGeometryInfo scene, float u0, float u1, float u2, float u3, float u4, out float pdf, out RayInfo ray)
        {
            // Choose two points p1 and p2 on scene bounding sphere
            var worldCenter = scene.BoundingSphereCenter;
            var worldRadius = scene.BoundingSphereRadius * 1.01f;

            var p1 = worldCenter + worldRadius * MC.UniformSampleSphere(u0, u1);
            var p2 = worldCenter + worldRadius * MC.UniformSampleSphere(u2, u3);

            // Construct ray between p1 and p2
            ray = new RayInfo(p1, (p2 - p1).Normalize(), 1e-4f, 1e4f);

            // Compute InfiniteAreaLight ray weight
            Vector toCenter = (worldCenter - p1).Normalize();
            var rayDir = ray.Dir;
            float costheta = MathLab.AbsDot(ref toCenter, ref rayDir);
            pdf = costheta / (4f * MathLab.M_PI * MathLab.M_PI * worldRadius * worldRadius);

            return Le(ray.Dir);
        }
Example #4
0
        public bool Intersect(ref RayInfo ray) {
            return ShadowIntersectBVH(ref ray);
            //return IntersectNode(RootNode, ray);

        }
Example #5
0
 public bool Intersect(ref RayInfo ray, out RayHit intersection) {
     intersection = new RayHit();
     //return IntersectLBVH(ref ray, ref intersection);
     return IntersectBVH(ref ray, ref intersection);
     //return IntersectNode(RootNode, ray, out intersection);
 }
 private RgbSpectrum ShadeBackground(RayInfo ray)
 {
     if (EnvironmentMap == null)
     {
         return RgbSpectrum.ZeroSpectrum();
     }
     return EnvironmentMap.Le(-ray.Dir);
 }
 private void Intersect(ref RayInfo rayInfo, ref  RayHit rayHit) {
     //accel.Intersect(ref rayInfo, out rayHit);
 }
Example #8
0
 public RgbSpectrum Sample(ref Point point, ref Normal n, float u0, float u1, float u2, out RayInfo ray, out float pdf)
 {
     var dir = (Position - point);
     var l2 = dir.Length;
     dir.Normalize();
     pdf = MC.UniformSpherePdf();
     ray = new RayInfo(point, dir, 1e-4f, l2 - 1e-4f);
     return Power / l2;
 }
Example #9
0
        public RgbSpectrum SamplePhoton(SceneGeometryInfo scene, float u0, float u1, float u2, float u3, float u4, out float pdf, out RayInfo ray)
        {

            Vector dir = MC.UniformSampleSphere(u0, u1);

            ray = new RayInfo(Position+dir*Radius, dir, 1e-4f, 1e4f);

            pdf = MathLab.INV4PI;

            return (Power * Radius * MathLab.M_PI * 4f);
        }
Example #10
0
        public RgbSpectrum Sample(ref Point point, ref Normal n, float u0, float u1, float u2, out RayInfo ray, out float pdf)
        {
            var samplePoint = new Point();
            float b0, b1, b2;
            int tries = 0;
            int maxTries = 0;
        startTry:
            var tri = SampleTriangle();

            tri.Sample(ref mesh.scene.Vertices, u2, u1, out samplePoint, out b0, out b1, out b2);
            var TriangleNormal =NormalModifier * tri.ComputeNormal(ref mesh.scene.Vertices);
            var area = tri.AreaV(ref mesh.scene.Vertices);
            //var sampleN = TriangleNormal;
            //var N = n;

            Vector wi = samplePoint - point;
            //wi.Normalize();
            float distanceSquared = wi.Length2();
            float distance = MathLab.Sqrt(distanceSquared);
            wi /= distance;

            var nw = -wi;
            float sampleNdotMinusWi = Normal.Dot(ref TriangleNormal, ref nw);
            float NdotWi = Normal.Dot(ref n, ref wi);
            if ((sampleNdotMinusWi <= 0f) || (NdotWi <= 0f))
            {
                tries++;
                if (tries > maxTries)
                {
                    pdf = 0f;
                    ray = new RayInfo(Point.Zero, Vector.Zero);
                    return RgbSpectrum.ZeroSpectrum();
                }

                goto startTry;
            }

            ray = new RayInfo(point, wi, MathLab.RAY_EPSILON, distance - MathLab.RAY_EPSILON);
            pdf = (distanceSquared / (sampleNdotMinusWi * meshArea))  * (1f / Math.Max(1, tries + 1));

            // Using 0.01 instead of 0.0 to cut down fireflies
            if (pdf <= 0.01f)
            {
                pdf = 0f;
                return RgbSpectrum.ZeroSpectrum();
            }
            return gain * meshArea;
        }
Example #11
0
 public abstract bool IntersectP(RayInfo ray, out float t0, out float t1);
Example #12
0
 public RayDifferential(RayInfo vray)
     : base(vray)
 {
     hasDifferentials = false;
 }
Example #13
0
        public RgbSpectrum SamplePhoton(SceneGeometryInfo scene, float u0, float u1, float u2, float u3, float u4, out float pdf,
                                        out RayInfo ray)
        {
            float b0, b1, b2;
            Point orig;
            var tri = SampleTriangle(u4);

            tri.Sample(ref mesh.scene.Vertices, u0, u1, out orig, out b0, out b1, out b2);
            var TriangleNormal = NormalModifier * tri.ComputeNormal(ref mesh.scene.Vertices);
            var area = tri.AreaV(ref mesh.scene.Vertices);
            // Ray direction
            var sampleN = TriangleNormal;
            Vector dir = MC.UniformSampleSphere(u2, u3);
            float RdotN = Normal.Dot(ref dir, ref sampleN);
            if (RdotN < 0f)
            {
                dir *= -1f;
                RdotN = -RdotN;
            }

            ray = new RayInfo(orig, dir);

            pdf = (MathLab.INVTWOPI / area) * (1f / mesh.TrianglesCount);

            return (gain * RdotN);
        }
Example #14
0
        //Transform WorldToVolume;

        public override bool IntersectP(RayInfo ray, out float t0, out float t1) {
            return this.worldBound.Intersect(ray, out t0, out t1);
        }
Example #15
0
        public void GetRay(double xp, double yp, out IRay cameraRay) {
            var u = (float)(2.0f * xp / w - 1.0f);
            var v = (float)(1.0f - 2.0f * yp / h);

            Vector rdir = mRight * u + mUp * v + this.Look;
            var rorig = (Position + rdir * 0.1f);
            rdir.Normalize();
            cameraRay = new RayInfo(rorig, rdir);
        }
        private RgbSpectrum Shade(MediumInfo currentMedium, float weight, RayInfo vray, IntersectionInfo isect, int depth)
        {
            var txtn = isect.GeometryInfo.GeoNormal;
            var p = isect.GeometryInfo.HitPoint;
            Vector v1, v2;
            Vector.CoordinateSystem(ref txtn, out v1, out v2);

            var Radiance = BaseColor * Vector.AbsDot(ref txtn, ref vray.Dir);
            for (int i = 0; i < shadowRayCount; i++)
            {
                var dir = MC.CosineSampleHemisphere(rnd.Value.NextFloat(), rnd.Value.NextFloat());
                dir = new Vector(v1.x * dir.x + v2.x * dir.y + txtn.x * dir.z, v1.y * dir.x + v2.y * dir.y + txtn.y * dir.z, v1.z * dir.x + v2.z * dir.y + txtn.z * dir.z);
                stats.intersections++;
                if (!manager.Intersect(new RayInfo(p, dir, 1e-4f, maxOcclussionRayLength)))
                {
                    Radiance += AddedRadiance * (1.0f / shadowRayCount);
                }
            }
            return Radiance;
        }
Example #17
0
 private bool IntersectNode(Node node, ref RayInfo ray) {
     if (node == null) {
         return false;
     }
     float t1 = 0f, u = 0f, v = 0f;
     if (IntersectBox(node.Bound, ref ray)) {
         //ray.MinT = t0;
         // ray.MaxT = t1;
         if (node.nPrims > 0) {
             for (var np = node.StartOffset; np < (node.StartOffset + node.nPrims); np++) {
                 if (Intersect(ref triangles[np], sceneVertices, ref ray, ref t1, ref u, ref v))
                 {
                     return true;
                 }
             }
         }
         return IntersectNode(node.Left, ref ray) || IntersectNode(node.Right, ref ray);
     }
     return false;
 }
Example #18
0
        protected PathVertex[] PropagatePath(RayInfo startRay, int maxPaths)
        {
            IntersectionInfo isect;
            var vertices = new PathVertex[maxPaths];
            var ray = new RayInfo(startRay);
            var sm = rnd.Value;
            for (int i = 0; i < maxPaths; i++)
            {
                Interlocked.Increment(ref stats.totalRays);
                if (manager.Intersect(ray, out isect))
                {
                    var vertice = new PathVertex { Wi = -ray.Dir };
                    Interlocked.Increment(ref stats.intersections);
                    var triangle = GetTriangle(isect.PrimitiveId, isect.PrimitiveIndex);
                    if (IsLight(triangle))
                    {
                        var lt = GetLight(triangle.Owner);
                        vertice.Emittance = lt.Le(ray.Dir);
                        vertices[i] = (vertice);
                        break;
                    }
                    vertice.Intersection = isect;
                    var bsdf = matLib.GetSurfMat(isect.Material.Name);
                    vertice.Bsdf = bsdf.First;
                    var t = RgbSpectrum.Unit;
                    vertice.BsdfSample = bsdf.Sample_f(ref vertice.Wi, out vertice.Wo, ref isect.GeometryInfo.GeoNormal,
                                                       ref isect.GeometryInfo.ShadingNormal, ref t,
                                                       sm.NextFloat(),
                                                       sm.NextFloat(),
                                                       sm.NextFloat(), ref isect.TextureData    , out vertice.BsdfPdf,
                                                       out vertice.SpecularBounce);

                    vertices[i] = (vertice);

                    ray = new RayInfo(isect.GeometryInfo.HitPoint, vertice.Wo);

                }
                else
                {
                    vertices[i] = (new PathVertex() { Wi = -ray.Dir });
                    break;
                }
            }
            return vertices;
        }
Example #19
0
 public abstract RgbSpectrum tau(RayInfo ray, float step = 1f, float offset = 0.5f);
Example #20
0
        public static RgbSpectrum EstimateDirect(ref Vector wo, IAccellerationStructure intersector, SceneGeometryInfo scene, ILight light, IntersectionInfo isect, SurfaceBsdf bsdf, FastRandom rnd)
        {
            RgbSpectrum Ld = new RgbSpectrum();
            Vector wi;
            float lightPdf, bsdfPdf;
            RayInfo shadowRay;
            RgbSpectrum Li = light.Sample(ref isect.GeometryInfo.HitPoint, ref isect.GeometryInfo.GeoNormal, rnd.NextFloat(), rnd.NextFloat(), rnd.NextFloat(),
                                          out shadowRay, out lightPdf);
            if (lightPdf > 0f && !Li.IsBlack())
            {
                wi = -shadowRay.Dir;
                RgbSpectrum f ;
                bsdf.f(ref wo, ref wi, ref isect.GeometryInfo.GeoNormal, ref Ld, out f);
                if (!f.IsBlack() && !intersector.Intersect(shadowRay))
                {
                    // Add light's contribution to reflected radiance
                    //Li *= visibility.Transmittance(scene, renderer, NULL, rng, arena);
                    if (light.IsDelta)
                        Ld += f * Li * (Vector.AbsDot(ref wi, ref isect.GeometryInfo.GeoNormal) / lightPdf);
                    else
                    {
                        bsdfPdf = bsdf.Pdf(ref wo, ref wi, BxDFTypes.BSDF_ALL_TYPES);
                        float weight = MC.PowerHeuristic(1, lightPdf, 1, bsdfPdf);
                        Ld += f * Li * (Vector.AbsDot(ref wi, ref isect.GeometryInfo.GeoNormal) * weight / lightPdf);
                    }
                }
            }
            if (!light.IsDelta)
            {
                //float bsdfPdf;
                bool spb;
                BsdfSampleData result;
                bsdf.Sample_f(ref wo, ref isect.GeometryInfo.GeoNormal, ref isect.GeometryInfo.ShadingNormal, ref Ld, rnd.NextFloat(),
                                              rnd.NextFloat(), rnd.NextFloat(), ref isect.TextureData, out result);
                bsdfPdf = result.Pdf;
                if (!result.F.IsBlack() && result.Pdf > 0f)
                {
                    if (lightPdf > 0f)
                    {
                        float weight = MC.PowerHeuristic(1, bsdfPdf, 1, lightPdf);
                        IntersectionInfo lightIsect;
                        RgbSpectrum li = new RgbSpectrum();
                        var ray = new RayInfo(isect.GeometryInfo.HitPoint, result.Wi, 1e-4f, 1e+4f);
                        if (intersector.Intersect(ray, out lightIsect))
                        {
                            if (light is TriangleLight && lightIsect.PrimitiveId.Equals(((TriangleLight)light).Owner.Id))
                                li = light.Le(-result.Wi);
                        }
                        else
                            li = light.Le(ray.Dir);
                        if (!li.IsBlack())
                        {
                            //Li *= scene->Transmittance(ray);
                            Ld += result.F * li * Vector.AbsDot(ref result.Wi, ref isect.GeometryInfo.GeoNormal) * weight / bsdfPdf;
                        }
                    }
                }
            }
            /*

            if (!light->IsDeltaLight()) {
		BxDFType flags = BxDFType(BSDF_ALL & ~BSDF_SPECULAR);
		Spectrum f = bsdf->Sample_f(wo, &wi,
			bs1, bs2, bcs, &bsdfPdf, flags);
		if (!f.Black() && bsdfPdf > 0.) {
			lightPdf = light->Pdf(p, n, wi);
			if (lightPdf > 0.) {
				// Add light contribution from BSDF sampling
				float weight = PowerHeuristic(1, bsdfPdf, 1, lightPdf);
				Intersection lightIsect;
				Spectrum Li(0.f);
				RayDifferential ray(p, wi);
				if (scene->Intersect(ray, &lightIsect)) {
					if (lightIsect.primitive->GetAreaLight() == light)
						Li = lightIsect.Le(-wi);
				}
				else
					Li = light->Le(ray);
				if (!Li.Black()) {
					Li *= scene->Transmittance(ray);
					Ld += f * Li * AbsDot(wi, n) * weight / bsdfPdf;
				}
			}
		}
	} 
             */
            return Ld;
        }
        public void GenerateRay(float xp, float yp, out RayInfo ray)
        {
            var u = 2.0f * xp / Width - 1.0f;
            var v = 1.0f - 2.0f * yp / Height;

            Vector rdir = x * u + y * v + dir;
            var rorig = (Position + rdir * 0.1f);
            rdir.Normalize();
            ray = new RayInfo(rorig, -rdir);
        }
Example #22
0
        public RgbSpectrum Sample(ref Point point, ref Normal n, float u0, float u1, float u2, out RayInfo ray, out float pdf)
        {
            var wi = MC.CosineSampleHemisphere(u1, u2);
            pdf = wi.z * MathLab.INVPI;

            Vector v1, v2;
            Vector.CoordinateSystem(n.ToVec(), out v1, out v2);

            wi = new Vector(
                v1.x * wi.x + v2.x * wi.y + n.x * wi.z,
                v1.y * wi.x + v2.y * wi.y + n.y * wi.z,
                v1.z * wi.x + v2.z * wi.y + n.z * wi.z);
            ray = new RayInfo(point, wi, 1e-4f, float.MaxValue);

            return Le(wi);
        }
Example #23
0
        public RgbSpectrum Sample(ref Point point, ref Normal n, float u0, float u1, float u2, out RayInfo ray, out float pdf)
        {
            var l = Position - point + MC.UniformSampleSphere(u0, u1) * Radius;	// vector to random point on source
            var Dist = l.Length;		// distance to light source
            var Attenuation = 17f / Dist;	// distance attenuation of light


            pdf = MC.UniformSpherePdf();
            ray = new RayInfo(point, l / Dist, 1e-4f, Dist - 1e-4f);
            return (Power*Radius / Dist);
        }
Example #24
0
            public static bool IntersectBox(BBox box, RayInfo ray)
            {
                float t0 = ray.Min;
                float t1 = ray.Max;

                var rayInvDir = 1f / ray.Dir;
                //1f /ray.Dir;

                float invDirX = rayInvDir.x;
                if (!process_box_coord(ref t0, ref t1, box.Min.x - ray.Org.x, box.Max.x - ray.Org.x, invDirX))
                    return false;

                float invDirY = rayInvDir.y;
                if (!process_box_coord(ref t0, ref t1, box.Min.y - ray.Org.y, box.Max.y - ray.Org.y, invDirY))
                    return false;

                float invDirZ = rayInvDir.z;
                if (!process_box_coord(ref t0, ref t1, box.Min.z - ray.Org.z, box.Max.z - ray.Org.z, invDirZ))
                    return false;
                return true;
            }
Example #25
0
        public bool IntersectLBVH(ref RayInfo ray, ref RayHit sp) {
            int currentNode = 0;
            float u = 0f, v = 0f, t1 = float.MaxValue, dist = float.MaxValue;
            bool hit = false;
            int stopNode = gpuBvhTree[0].SkipOffset;
            sp.Index = RayBuffer.NotHit;

            while (currentNode < stopNode) {
                if (BBox.IntersectBox(ref gpuBvhTree[currentNode].Bound, ref ray)) {
                    if (gpuBvhTree[currentNode].PrimOffset != 0) 
                    {
                        if (Intersect(ref triangles[gpuBvhTree[currentNode].PrimOffset], sceneVertices, ref ray, ref t1, ref u,
                                                                                  ref v)) {
                            var triangleIndex = gpuBvhTree[currentNode].PrimOffset;
                            dist = t1;
                            sp.Index = (uint)(triangleIndex);
                            sp.Distance = dist;
                            sp.U = u;
                            sp.V = v;
                            hit = true;
                        }
                    }
                    currentNode++;
                }
                else {
                    currentNode = gpuBvhTree[currentNode].SkipOffset;
                }
            }
            return hit;
        }
 private RgbSpectrum Trace(RayInfo ray, float weight, MediumInfo currentMedium, int depth)
 {
     IntersectionInfo isect;
     //RaysTraced++;
     stats.totalRays++;
     var color = new RgbSpectrum(0f);
     if (manager.Intersect(ray, out isect))
     {
         stats.intersections++;
         //Intersections++;
         color = this.Shade(currentMedium, weight, ray, isect, depth);
     }
     else
     {
         color = this.ShadeBackground(ray);
     }
     return color;
 }
Example #27
0
        public bool Intersect(ref Point[] meshVertices, ref RayInfo ray, ref float thit, ref float u, ref float v) {
            Vector s1;
            if (!edgesInitialized) {
                Point.Sub(ref meshVertices[v1], ref meshVertices[v0], out e1);
                Point.Sub(ref meshVertices[v2], ref meshVertices[v0], out e2);
                edgesInitialized = true;
            }

            Vector.Cross(ref ray.Dir, ref e2, out s1);


            var divisor = Vector.Dot(ref s1, ref e1);
            if (divisor < MathLab.Epsilon)
                return false;

            var invDivisor = 1f / divisor;


            Vector d, s2;
            d = ray.Org - meshVertices[v0];
            //Point.Sub(ref ray.Org, ref meshVertices[v0], out d);
            var b1 = Vector.Dot(ref d, ref s1) * invDivisor;
            if (b1 < 0f)
                return false;

            Vector.Cross(ref d, ref  e1, out s2);
            var b2 = Vector.Dot(ref ray.Dir, ref  s2) * invDivisor;
            if (b2 < 0f)
                return false;

            var b0 = 1f - b1 - b2;
            if (b0 < 0f)
                return false;

            var t = Vector.Dot(ref e2, ref s2) * invDivisor;
            if (t < ray.MinT || t > ray.MaxT)
                return false;

            thit = t;
            u = b1;
            v = b2;

            return true;
        }
Example #28
0
        private bool IntersectBVH(ref RayInfo ray, ref RayHit sp) {
            if (bvhTree.Length == 0)
                return false;

            int triangleIndex = -1;
            float u = 0f, v = 0f;
            bool hit = false;
            Vector invDir = ray.InvDirection;
            //new Vector(1f / ray.Dir.x, 1f / ray.Dir.y, 1f / ray.Dir.z);
            var dirIsNeg = new[] { invDir.x < 0, invDir.y < 0, invDir.z < 0 };
            int todoOffset = 0, nodeNum = 0;
            int[] todo = new int[TraversalStackSize];
            var dist = float.MaxValue;
            while (true) {
                var node = bvhTree[nodeNum];
                float t1 = 0f;
                if (BBox.IntersectBox(ref node.Bound, ref ray)) {
                    //if (node.bbox.Intersect(vray, out t0, out t2)) {
                    if (node.PrimitiveCount > 0) {
                        for (var i = 0; i < node.PrimitiveCount; ++i) {
                            if (Intersect(ref triangles[node.PrimOffset + i], sceneVertices, ref ray, ref t1, ref u, ref v)) {
                                if (dist > t1) {
                                    triangleIndex = node.PrimOffset + i;
                                    dist = t1;
                                    sp.Index = (uint)(triangleIndex);
                                    sp.Distance = dist;
                                    sp.U = u;
                                    sp.V = v;
                                    hit = true;
                                }
                            }
                        }
                        if (todoOffset == 0)
                            break;
                        nodeNum = todo[--todoOffset];
                    }
                    else {
                        if (dirIsNeg[node.Axis]) {
                            todo[todoOffset++] = nodeNum + 1;
                            nodeNum = node.SecondChildOffset;
                        }
                        else {
                            todo[todoOffset++] = node.SecondChildOffset;
                            nodeNum = nodeNum + 1;
                        }
                    }
                }
                else {
                    if (todoOffset == 0)
                        break;
                    nodeNum = todo[--todoOffset];
                }
            }

            if (hit) {
                return true;
            }
            sp.Index = RayBuffer.NotHit;

            return false;
        }
Example #29
0
        public static bool IntersectBox(AABB box, RayInfo ray)
        {
            float t0 = ray.minT;
            float t1 = ray.maxT;
            //float hitt0 = t0;
            //float hitt1 = t1;

            if (!process_box_coord(ref t0, ref t1, box.Min.x - ray.Org.x, box.Max.x - ray.Org.x, 1f / ray.Dir.x))
                return false;

            if (!process_box_coord(ref t0, ref t1, box.Min.y - ray.Org.y, box.Max.y - ray.Org.y, 1f / ray.Dir.y))
                return false;

            if (!process_box_coord(ref t0, ref t1, box.Min.z - ray.Org.z, box.Max.z - ray.Org.z, 1f / ray.Dir.z))
                return false;

            /*
            for (int i = 0; i < 3; ++i) {
                // Update interval for _i_th bounding box slab
                float invRayDir = 1f / ray.Direction[i];
                if (!process_box_coord(ref t0, ref t1, min[i] - ray.Origin[i], max[i] - ray.Origin[i], invRayDir)) return false;
            }
             * */
            //ray.MinT = t0;
            //ray.MaxT = t1;
            //hitt0 = t0;
            //hitt1 = t1;
            return true;
        }
Example #30
0
        private bool ShadowIntersectBVH(ref RayInfo ray) {
            if (nodes.Count == 0)
                return false;
            bool hit = false;
            Vector invDir = ray.InvDirection;
            //new Vector(1f / ray.Dir.x, 1f / ray.Dir.y, 1f / ray.Dir.z);
            var dirIsNeg = new[] { invDir.x < 0, invDir.y < 0, invDir.z < 0 };
            int todoOffset = 0, nodeNum = 0;
            int[] todo = new int[TraversalStackSize];
            while (true) {
                var node = bvhTree[nodeNum];
                float t1 = 0f, u = 0f, v = 0f;
                if (BBox.IntersectBox(ref node.Bound, ref ray)) {
                    if (node.PrimitiveCount > 0) {
                        for (var i = 0; i < node.PrimitiveCount; ++i) {
                            if (!Intersect(ref triangles[node.PrimOffset + i], sceneVertices, ref ray, ref t1, ref u, ref v))
                                continue;
                            hit = true;
                            break;
                        }
                        if (todoOffset == 0)
                            break;
                        nodeNum = todo[--todoOffset];
                    }
                    else {
                        if (dirIsNeg[node.Axis]) {
                            todo[todoOffset++] = nodeNum + 1;
                            nodeNum = node.SecondChildOffset;
                        }
                        else {
                            todo[todoOffset++] = node.SecondChildOffset;
                            nodeNum = nodeNum + 1;
                        }
                    }
                }
                else {
                    if (todoOffset == 0)
                        break;
                    nodeNum = todo[--todoOffset];
                }
            }

            return hit;
        }