示例#1
0
        //
        // Hits the ray against the mesh
        //
        internal override void RayHitTestCore(
            RayHitTestParameters rayParams,
            FaceType hitTestableFaces)
        {
            Debug.Assert(hitTestableFaces != FaceType.None,
                         "Caller should make sure we're trying to hit something");

            Point3DCollection positions = Positions;

            if (positions == null)
            {
                return;
            }

            Point3D  origin;
            Vector3D direction;

            rayParams.GetLocalLine(out origin, out direction);

            Int32Collection indices = TriangleIndices;

            // In the line case, we want to hit test all faces because we don't
            // have a direction. This may differ from what faces we want to
            // accept.
            FaceType facesToHit;

            if (rayParams.IsRay)
            {
                facesToHit = hitTestableFaces;
            }
            else
            {
                facesToHit = FaceType.Front | FaceType.Back;
            }


            //
            // This code duplication is unfortunate but necessary. Breaking it down into methods
            // further significantly impacts performance. About 5% improvement could be made
            // by unrolling this code below even more.
            //
            // If futher perf investigation is done with this code, be sure to test NGEN assemblies only
            // as JIT produces different, faster code than NGEN.
            //

            if (indices == null || indices.Count == 0)
            {
                FrugalStructList <Point3D> ps = positions._collection;
                int count = ps.Count - (ps.Count % 3);

                for (int i = count - 1; i >= 2; i -= 3)
                {
                    int i0 = i - 2;
                    int i1 = i - 1;
                    int i2 = i;

                    Point3D v0 = ps[i0];
                    Point3D v1 = ps[i1];
                    Point3D v2 = ps[i2];

                    double hitTime;
                    Point  barycentric;

                    // The line hit test is equivalent to a double sided
                    // triangle hit because it doesn't cull triangles based
                    // on winding
                    if (LineUtil.ComputeLineTriangleIntersection(
                            facesToHit,
                            ref origin,
                            ref direction,
                            ref v0,
                            ref v1,
                            ref v2,
                            out barycentric,
                            out hitTime
                            )
                        )
                    {
                        if (rayParams.IsRay)
                        {
                            ValidateRayHit(
                                rayParams,
                                ref origin,
                                ref direction,
                                hitTime,
                                i0,
                                i1,
                                i2,
                                ref barycentric
                                );
                        }
                        else
                        {
                            ValidateLineHit(
                                rayParams,
                                hitTestableFaces,
                                i0,
                                i1,
                                i2,
                                ref v0,
                                ref v1,
                                ref v2,
                                ref barycentric
                                );
                        }
                    }
                }
            }
            else // indexed mesh
            {
                FrugalStructList <Point3D> ps   = positions._collection;
                FrugalStructList <int>     idcs = indices._collection;

                int count = idcs.Count;
                int limit = ps.Count;

                for (int i = 2; i < count; i += 3)
                {
                    int i0 = idcs[i - 2];
                    int i1 = idcs[i - 1];
                    int i2 = idcs[i];

                    // Quit if we encounter an index out of range.
                    // This is okay because the triangles we ignore are not rendered.
                    //  (see: CMilMeshGeometry3DDuce::Realize)
                    if ((0 > i0 || i0 >= limit) ||
                        (0 > i1 || i1 >= limit) ||
                        (0 > i2 || i2 >= limit))
                    {
                        break;
                    }

                    Point3D v0 = ps[i0];
                    Point3D v1 = ps[i1];
                    Point3D v2 = ps[i2];

                    double hitTime;
                    Point  barycentric;

                    if (LineUtil.ComputeLineTriangleIntersection(
                            facesToHit,
                            ref origin,
                            ref direction,
                            ref v0,
                            ref v1,
                            ref v2,
                            out barycentric,
                            out hitTime
                            )
                        )
                    {
                        if (rayParams.IsRay)
                        {
                            ValidateRayHit(
                                rayParams,
                                ref origin,
                                ref direction,
                                hitTime,
                                i0,
                                i1,
                                i2,
                                ref barycentric
                                );
                        }
                        else
                        {
                            ValidateLineHit(
                                rayParams,
                                hitTestableFaces,
                                i0,
                                i1,
                                i2,
                                ref v0,
                                ref v1,
                                ref v2,
                                ref barycentric
                                );
                        }
                    }
                }
            }
        }