Example #1
0
            public IEnumerable <HitInfo <V> > Raycast(RayDescription ray)
            {
                if (mesh.Topology != Topology.Triangles)
                {
                    yield break;
                }

                Ray3D r = new Ray3D(ray.Origin, ray.Direction + 0.000000001f); // epsilon deviation of the direction to avoid indefinitions

                float minT, maxT;

                if (!box.Intersect(r, out minT, out maxT))
                {
                    yield break;
                }

                maxT = min(maxT, ray.MaxT);

                float t = max(ray.MinT, minT);

                float3 P = r.X + r.D * t;

                int3 cell = (int3)min(((P - box.Minimum) * resolution / (box.Maximum - box.Minimum)), resolution - 1);


                float3 side = r.D > 0;

                int3 cellInc = (r.D > 0) * 2 - 1;

                float3 corner = box.Minimum + (cell + side) * (box.Maximum - box.Minimum) / resolution;

                float3 alphas   = (corner - r.X) / r.D;
                float3 alphaInc = (box.Maximum - box.Minimum) / abs(resolution * r.D);

                while (t < maxT)
                {
                    float nextT = min(alphas.x, min(alphas.y, alphas.z));

                    if (any(cell < 0) || any(cell >= resolution))
                    {
                        yield break; // just for numerical problems, traversal could go outside grid.
                    }
                    // check current cell
                    if (triangleHash[cell.z, cell.y, cell.x] != null)
                    {
                        List <HitInfo <V> > hits = new List <HitInfo <V> >();

                        foreach (var i in triangleHash[cell.z, cell.y, cell.x])
                        {
                            V          v1  = mesh.Vertices[mesh.Indices[i * 3 + 0]];
                            V          v2  = mesh.Vertices[mesh.Indices[i * 3 + 1]];
                            V          v3  = mesh.Vertices[mesh.Indices[i * 3 + 2]];
                            Triangle3D tri = new Triangle3D(v1.Position, v2.Position, v3.Position);
                            float      triT;
                            float3     baricenter;
                            if (tri.Intersect(r, out triT, out baricenter))
                            {
                                if (triT >= t && triT <= nextT)
                                {
                                    hits.Add(new HitInfo <V>
                                    {
                                        T         = triT,
                                        Attribute = v1.Mul(baricenter.x).Add(v2.Mul(baricenter.y)).Add(v3.Mul(baricenter.z))
                                    });
                                }
                            }
                        }

                        hits.Sort((h1, h2) => h1.T.CompareTo(h2.T)); // only need to sort hits inside a cell, because cells are iterated in ray-order

                        foreach (var hi in hits)
                        {
                            yield return(hi);
                        }
                    }

                    // advance ray to next cell
                    int3 movement = new int3(alphas.x <= alphas.y && alphas.x <= alphas.z, alphas.y < alphas.x && alphas.y <= alphas.z, alphas.z < alphas.x && alphas.z < alphas.y);
                    cell   += movement * cellInc;
                    alphas += movement * alphaInc;
                    t       = nextT;
                }
            }