protected override bool OnHitTest(HitTestContext context, Matrix totalModelMatrix, ref List <HitTestResult> hits) { return(false); }
/// <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)); }
protected override bool CanHitTest(HitTestContext context) { return(false); }
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); }
protected override bool PreHitTestOnBounds(HitTestContext context) { return(true); }
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)); }
/// <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);
/// <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); }
/// <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); }
public sealed override bool HitTest(HitTestContext context, ref List <HitTestResult> hits) { return(false); }
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); }
/// <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); }
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); }
protected override bool PreHitTestOnBounds(HitTestContext context) { return(BoneMatrices.Length == 0 ? base.PreHitTestOnBounds(context) : true); }