예제 #1
0
 protected override bool OnHitTest(HitTestContext context, Matrix totalModelMatrix, ref List <HitTestResult> hits)
 {
     return(false);
 }
예제 #2
0
 /// <summary>
 /// Normal hit test from top to bottom
 /// </summary>
 /// <param name="context"></param>
 /// <param name="model"></param>
 /// <param name="modelMatrix"></param>
 /// <param name="hits"></param>
 /// <returns></returns>
 public virtual bool HitTest(HitTestContext context, object model, Matrix modelMatrix, ref List <HitTestResult> hits)
 {
     return(Octree.HitTest(context, model, null, modelMatrix, ref hits));
 }
예제 #3
0
 protected override bool CanHitTest(HitTestContext context)
 {
     return(false);
 }
예제 #4
0
        public virtual bool HitTest(HitTestContext context, Matrix modelMatrix, ref List <HitTestResult> hits, object originalSource)
        {
            if (Positions == null || Positions.Count == 0 ||
                Indices == null || Indices.Count == 0)
            {
                return(false);
            }
            var isHit = false;

            if (Octree != null)
            {
                isHit = Octree.HitTest(context, originalSource, this, modelMatrix, ReturnMultipleHitsOnHitTest, ref hits);
            }
            else
            {
                var result = new HitTestResult
                {
                    Distance = double.MaxValue
                };
                var modelInvert = modelMatrix.Inverted();
                if (modelInvert == Matrix.Zero)//Check if model matrix can be inverted.
                {
                    return(false);
                }
                //transform ray into model coordinates
                var rayModel = new Ray(Vector3.TransformCoordinate(context.RayWS.Position, modelInvert), Vector3.Normalize(Vector3.TransformNormal(context.RayWS.Direction, modelInvert)));

                var b = this.Bound;

                //Do hit test in local space
                if (rayModel.Intersects(ref b))
                {
                    var index       = 0;
                    var minDistance = float.MaxValue;

                    foreach (var t in Triangles)
                    {
                        // Used when geometry size is really small, causes hit test failure due to SharpDX.MathUtils.ZeroTolerance.
                        var scaling   = 1f;
                        var rayScaled = rayModel;
                        if (EnableSmallTriangleHitTestScaling)
                        {
                            if ((t.P0 - t.P1).LengthSquared() < SmallTriangleEdgeLengthSquare ||
                                (t.P1 - t.P2).LengthSquared() < SmallTriangleEdgeLengthSquare ||
                                (t.P2 - t.P0).LengthSquared() < SmallTriangleEdgeLengthSquare)
                            {
                                scaling   = SmallTriangleHitTestScaling;
                                rayScaled = new Ray(rayModel.Position * scaling, rayModel.Direction);
                            }
                        }
                        var v0 = t.P0 * scaling;
                        var v1 = t.P1 * scaling;
                        var v2 = t.P2 * scaling;

                        if (Collision.RayIntersectsTriangle(ref rayScaled, ref v0, ref v1, ref v2, out float d))
                        {
                            d /= scaling;
                            // For CrossSectionMeshGeometryModel3D another hit than the closest may be the valid one, since the closest one might be removed by a crossing plane
                            if (ReturnMultipleHitsOnHitTest)
                            {
                                minDistance = float.MaxValue;
                            }

                            if (d >= 0 && d < minDistance) // If d is NaN, the condition is false.
                            {
                                minDistance     = d;
                                result.IsValid  = true;
                                result.ModelHit = originalSource;
                                // transform hit-info to world space now:
                                var pointWorld = Vector3.TransformCoordinate(rayModel.Position + (rayModel.Direction * d), modelMatrix);
                                result.PointHit = pointWorld;
                                result.Distance = (context.RayWS.Position - pointWorld).Length();
                                var p0 = Vector3.TransformCoordinate(t.P0, modelMatrix);
                                var p1 = Vector3.TransformCoordinate(t.P1, modelMatrix);
                                var p2 = Vector3.TransformCoordinate(t.P2, modelMatrix);
                                var n  = Vector3.Cross(p1 - p0, p2 - p0);
                                n.Normalize();
                                // transform hit-info to world space now:
                                result.NormalAtHit     = n;// Vector3.TransformNormal(n, m).ToVector3D();
                                result.TriangleIndices = new System.Tuple <int, int, int>(Indices[index], Indices[index + 1], Indices[index + 2]);
                                result.Tag             = index / 3;
                                result.Geometry        = this;
                                isHit = true;
                                if (ReturnMultipleHitsOnHitTest)
                                {
                                    hits.Add(result);
                                    result = new HitTestResult();
                                }
                            }
                        }
                        index += 3;
                    }
                }
                if (isHit && result.IsValid && !ReturnMultipleHitsOnHitTest)
                {
                    hits.Add(result);
                }
            }
            return(isHit);
        }
예제 #5
0
 protected override bool PreHitTestOnBounds(HitTestContext context)
 {
     return(true);
 }
예제 #6
0
 public override bool HitTest(HitTestContext context, object model, Geometry3D geometry, Matrix modelMatrix, ref List <HitTestResult> hits, float hitThickness)
 {
     needRecalculate = true;
     return(base.HitTest(context, model, geometry, modelMatrix, ref hits, hitThickness));
 }
예제 #7
0
 /// <summary>
 /// Hits the test.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <param name="modelMatrix">The model matrix.</param>
 /// <param name="hits">The hits.</param>
 /// <param name="originalSource">The original source.</param>
 /// <param name="fixedSize">if set to <c>true</c> [fixed size].</param>
 /// <returns></returns>
 public abstract bool HitTest(HitTestContext context, Matrix modelMatrix, ref List <HitTestResult> hits,
                              object originalSource, bool fixedSize);
예제 #8
0
            /// <summary>
            ///
            /// </summary>
            /// <param name="octant"></param>
            /// <param name="context"></param>
            /// <param name="model"></param>
            /// <param name="geometry"></param>
            /// <param name="modelMatrix"></param>
            /// <param name="rayModel"></param>
            /// <param name="returnMultiple"></param>
            /// <param name="hits"></param>
            /// <param name="isIntersect"></param>
            /// <param name="hitThickness"></param>
            /// <returns></returns>
            protected override bool HitTestCurrentNodeExcludeChild(ref Octant octant, HitTestContext context, object model,
                                                                   Geometry3D geometry, Matrix modelMatrix, ref Ray rayModel, bool returnMultiple,
                                                                   ref List <HitTestResult> hits, ref bool isIntersect, float hitThickness)
            {
                isIntersect = false;
                if (!octant.IsBuilt || context == null)
                {
                    return(false);
                }
                var isHit = false;
                var bound = octant.Bound;

                if (rayModel.Intersects(ref bound))
                {
                    isIntersect = true;
                    if (octant.Count == 0)
                    {
                        return(false);
                    }
                    var result = new HitTestResult();
                    result.Distance = double.MaxValue;
                    if (needRecalculate)
                    {
                        var svpm = context.RenderMatrices.ScreenViewProjectionMatrix;
                        smvpm           = modelMatrix * svpm;
                        needRecalculate = false;
                    }
                    var clickPoint = context.HitPointSP.ToVector3() * context.RenderMatrices.DpiScale;
                    isIntersect = true;
                    var dist  = hitThickness;
                    var rayWS = context.RayWS;
                    for (int i = octant.Start; i < octant.End; ++i)
                    {
                        var v0 = Positions[Objects[i]];
                        var p0 = Vector3.TransformCoordinate(v0, smvpm);
                        var pv = p0 - clickPoint;
                        var d  = pv.Length() / context.RenderMatrices.DpiScale;
                        if (returnMultiple)
                        {
                            dist = hitThickness;
                        }
                        if (d < dist) // If d is NaN, the condition is false.
                        {
                            dist            = d;
                            result.IsValid  = true;
                            result.ModelHit = model;
                            var px = Vector3.TransformCoordinate(v0, modelMatrix);
                            result.PointHit = px;
                            result.Distance = (rayWS.Position - px).Length();
                            result.Tag      = Objects[i];
                            result.Geometry = geometry;
                            isHit           = true;
                            if (returnMultiple)
                            {
                                hits.Add(result);
                                result = new HitTestResult();
                            }
                        }
                    }

                    if (isHit && !returnMultiple)
                    {
                        isHit = false;
                        if (hits.Count > 0)
                        {
                            if (hits[0].Distance > result.Distance)
                            {
                                hits[0] = result;
                                isHit   = true;
                            }
                        }
                        else
                        {
                            hits.Add(result);
                            isHit = true;
                        }
                    }
                }

                return(isHit);
            }
예제 #9
0
            /// <summary>
            ///
            /// </summary>
            /// <param name="octant"></param>
            /// <param name="context"></param>
            /// <param name="sphere"></param>
            /// <param name="result"></param>
            /// <param name="isIntersect"></param>
            /// <returns></returns>
            protected override bool FindNearestPointBySphereExcludeChild(ref Octant octant, HitTestContext context,
                                                                         ref BoundingSphere sphere, ref List <HitTestResult> result, ref bool isIntersect)
            {
                bool isHit      = false;
                var  resultTemp = new HitTestResult();

                resultTemp.Distance = float.MaxValue;
                if (!BoxDisjointSphere(octant.Bound, ref sphere))
                {
                    isIntersect = true;
                    for (int i = octant.Start; i < octant.End; ++i)
                    {
                        var p = Positions[Objects[i]];
                        if (sphere.Contains(ref p) != ContainmentType.Disjoint)
                        {
                            var d = (p - sphere.Center).Length();
                            if (resultTemp.Distance > d)
                            {
                                resultTemp.Distance = d;
                                resultTemp.IsValid  = true;
                                resultTemp.PointHit = p;
                                resultTemp.Tag      = Objects[i];
                                isHit = true;
                            }
                        }
                    }
                    if (isHit)
                    {
                        isHit = false;
                        if (result.Count > 0)
                        {
                            if (result[0].Distance > resultTemp.Distance)
                            {
                                result[0] = resultTemp;
                                isHit     = true;
                            }
                        }
                        else
                        {
                            result.Add(resultTemp);
                            isHit = true;
                        }
                    }
                }
                else
                {
                    isIntersect = false;
                }
                return(isHit);
            }
예제 #10
0
 public sealed override bool HitTest(HitTestContext context, ref List <HitTestResult> hits)
 {
     return(false);
 }
예제 #11
0
            protected override bool OnHitTest(HitTestContext context, Matrix totalModelMatrix, ref List <HitTestResult> hits)
            {
                var hitsBeforeCheck = hits?.Count ?? 0;
                var meshGeometry3d  = Geometry as MeshGeometry3D;

                if (meshGeometry3d == null)
                {
                    return(false);
                }
                if (meshGeometry3d.ReturnMultipleHitsOnHitTest)
                {
                    throw new InvalidOperationException($"All hit tests should be called on the same thread, {nameof(Geometry)}.{nameof(meshGeometry3d.ReturnMultipleHitsOnHitTest)} would not be true if that was the case");
                }
                meshGeometry3d.ReturnMultipleHitsOnHitTest = true;
                var result = meshGeometry3d.HitTest(context, totalModelMatrix, ref hits, this.WrapperSource);

                meshGeometry3d.ReturnMultipleHitsOnHitTest = false;
                var operation = CuttingOperation;

                if (result)
                {
                    switch (operation)
                    {
                    case CuttingOperation.Intersect:
                        // Remove any hit point behinds any of the clip plane.
                        if (EnablePlane1)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane1, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane2)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane2, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane3)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane3, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane4)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane4, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane5)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane5, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane6)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane6, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane7)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane7, hits, hitsBeforeCheck);
                        }
                        if (result && EnablePlane8)
                        {
                            result = RemoveHitPointBehindCrossingPlane(Plane8, hits, hitsBeforeCheck);
                        }
                        break;

                    case CuttingOperation.Subtract:
                        // Remove any hit point in front of all clip planes
                        result = RemoveHitPointInFrontOfAllCrossingPlanes(hits, hitsBeforeCheck);
                        break;
                    }
                    if (result)
                    {
                        RemoveAllButClosest(hits, hitsBeforeCheck);
                    }
                }
                return(result);
            }
예제 #12
0
 /// <summary>
 /// Determines whether this instance [can hit test] the specified context.
 /// </summary>
 /// <param name="context">The context.</param>
 /// <returns>
 ///   <c>true</c> if this instance [can hit test] the specified context; otherwise, <c>false</c>.
 /// </returns>
 protected override bool CanHitTest(HitTestContext context)
 {
     return(base.CanHitTest(context) && Geometries != null && Geometries.Length > 0 && Materials != null && Materials.Length > 0);
 }
예제 #13
0
        public virtual bool HitTestWithSkinnedVertices(HitTestContext context, Vector3[] skinnedVertices, Matrix modelMatrix,
                                                       ref List <HitTestResult> hits, object originalSource)
        {
            if (skinnedVertices == null || skinnedVertices.Length == 0 ||
                Indices == null || Indices.Count == 0)
            {
                return(false);
            }
            var isHit  = false;
            var result = new HitTestResult
            {
                Distance = double.MaxValue
            };
            var modelInvert = modelMatrix.Inverted();

            if (modelInvert == Matrix.Zero)//Check if model matrix can be inverted.
            {
                return(false);
            }
            var rayWS = context.RayWS;
            //transform ray into model coordinates
            var rayModel = new Ray(Vector3.TransformCoordinate(rayWS.Position, modelInvert), Vector3.Normalize(Vector3.TransformNormal(rayWS.Direction, modelInvert)));

            var index       = 0;
            var minDistance = float.MaxValue;

            foreach (var t in skinnedTriangles(skinnedVertices))
            {
                // Used when geometry size is really small, causes hit test failure due to SharpDX.MathUtils.ZeroTolerance.
                var scaling   = 1f;
                var rayScaled = rayModel;
                if (EnableSmallTriangleHitTestScaling)
                {
                    if ((t.P0 - t.P1).LengthSquared() < SmallTriangleEdgeLengthSquare ||
                        (t.P1 - t.P2).LengthSquared() < SmallTriangleEdgeLengthSquare ||
                        (t.P2 - t.P0).LengthSquared() < SmallTriangleEdgeLengthSquare)
                    {
                        scaling   = SmallTriangleHitTestScaling;
                        rayScaled = new Ray(rayModel.Position * scaling, rayModel.Direction);
                    }
                }
                var v0 = t.P0 * scaling;
                var v1 = t.P1 * scaling;
                var v2 = t.P2 * scaling;

                if (Collision.RayIntersectsTriangle(ref rayScaled, ref v0, ref v1, ref v2, out float d))
                {
                    if (d >= 0 && d < minDistance) // If d is NaN, the condition is false.
                    {
                        minDistance     = d;
                        result.IsValid  = true;
                        result.ModelHit = originalSource;
                        var pointWorld = Vector3.TransformCoordinate(rayModel.Position + (rayModel.Direction * d), modelMatrix);
                        result.PointHit = pointWorld;
                        result.Distance = (rayWS.Position - pointWorld).Length();
                        var p0 = Vector3.TransformCoordinate(v0, modelMatrix);
                        var p1 = Vector3.TransformCoordinate(v1, modelMatrix);
                        var p2 = Vector3.TransformCoordinate(v2, modelMatrix);
                        var n  = Vector3.Cross(p1 - p0, p2 - p0);
                        n.Normalize();
                        // transform hit-info to world space now:
                        result.NormalAtHit     = n;// Vector3.TransformNormal(n, m).ToVector3D();
                        result.TriangleIndices = new System.Tuple <int, int, int>(Indices[index], Indices[index + 1], Indices[index + 2]);
                        result.Tag             = index / 3;
                        result.Geometry        = this;
                        isHit = true;
                        if (ReturnMultipleHitsOnHitTest)
                        {
                            hits.Add(result);
                            result = new HitTestResult();
                        }
                    }
                }
                index += 3;
            }
            if (isHit)
            {
                hits.Add(result);
            }
            return(isHit);
        }
예제 #14
0
 protected override bool PreHitTestOnBounds(HitTestContext context)
 {
     return(BoneMatrices.Length == 0 ? base.PreHitTestOnBounds(context) : true);
 }