// alternative way, 3.36 times slower protected bool MyHitTest(Ray rayWS, ref List <HitTestResult> hits) { LineGeometry3D lineGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null || (lineGeometry3D = this.Geometry as LineGeometry3D) == null) { return(false); } var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var lastDist = double.MaxValue; var index = 0; foreach (var line in lineGeometry3D.Lines) { var t0 = Vector3.TransformCoordinate(line.P0, this.ModelMatrix); var t1 = Vector3.TransformCoordinate(line.P1, this.ModelMatrix); Vector3 sp, tp; float sc, tc; var distance = LineBuilder.GetRayToLineDistance(rayWS, t0, t1, out sp, out tp, out sc, out tc); var svpm = viewport.GetScreenViewProjectionMatrix(); Vector4 sp4; Vector4 tp4; Vector3.Transform(ref sp, ref svpm, out sp4); Vector3.Transform(ref tp, ref svpm, out tp4); var sp3 = sp4.ToVector3(); var tp3 = tp4.ToVector3(); var tv2 = new Vector2(tp3.X - sp3.X, tp3.Y - sp3.Y); var dist = tv2.Length(); if (dist < lastDist && dist <= this.HitTestThickness) { lastDist = dist; result.PointHit = sp.ToPoint3D(); result.NormalAtHit = (sp - tp).ToVector3D(); // not normalized to get length result.Distance = distance; result.ModelHit = this; result.IsValid = true; result.Tag = index; // ToDo: LineHitTag with additional info } index++; } if (result.IsValid) { hits.Add(result); } return(result.IsValid); }
// alternative way, 3.36 times slower protected bool MyHitTest(Ray rayWS, ref List<HitTestResult> hits) { LineGeometry3D lineGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null || (lineGeometry3D = this.Geometry as LineGeometry3D) == null) { return false; } var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var lastDist = double.MaxValue; var index = 0; foreach (var line in lineGeometry3D.Lines) { var t0 = Vector3.TransformCoordinate(line.P0, this.ModelMatrix); var t1 = Vector3.TransformCoordinate(line.P1, this.ModelMatrix); Vector3 sp, tp; float sc, tc; var distance = LineBuilder.GetRayToLineDistance(rayWS, t0, t1, out sp, out tp, out sc, out tc); var svpm = viewport.GetScreenViewProjectionMatrix(); Vector4 sp4; Vector4 tp4; Vector3.Transform(ref sp, ref svpm, out sp4); Vector3.Transform(ref tp, ref svpm, out tp4); var sp3 = sp4.ToVector3(); var tp3 = tp4.ToVector3(); var tv2 = new Vector2(tp3.X - sp3.X, tp3.Y - sp3.Y); var dist = tv2.Length(); if (dist < lastDist && dist <= this.HitTestThickness) { lastDist = dist; result.PointHit = sp.ToPoint3D(); result.NormalAtHit = (sp - tp).ToVector3D(); // not normalized to get length result.Distance = distance; result.ModelHit = this; result.IsValid = true; result.Tag = index; // ToDo: LineHitTag with additional info } index++; } if (result.IsValid) { hits.Add(result); } return result.IsValid; }
public override bool HitTest(Ray rayWS, ref List <HitTestResult> hits) { LineGeometry3D lineGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null || (lineGeometry3D = this.Geometry as LineGeometry3D) == null) { return(false); } // revert unprojection; probably better: overloaded HitTest() for LineGeometryModel3D? var svpm = viewport.GetScreenViewProjectionMatrix(); var smvpm = this.modelMatrix * svpm; var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1); Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4); var clickPoint = clickPoint4.ToVector3(); var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var maxDist = this.HitTestThickness; var lastDist = double.MaxValue; var index = 0; foreach (var line in lineGeometry3D.Lines) { var p0 = Vector3.TransformCoordinate(line.P0, smvpm); var p1 = Vector3.TransformCoordinate(line.P1, smvpm); Vector3 hitPoint; float t; var dist = LineBuilder.GetPointToLineDistance2D(ref clickPoint, ref p0, ref p1, out hitPoint, out t); if (dist < lastDist && dist <= maxDist) { lastDist = dist; Vector4 res; var lp0 = line.P0; Vector3.Transform(ref lp0, ref this.modelMatrix, out res); lp0 = res.ToVector3(); var lp1 = line.P1; Vector3.Transform(ref lp1, ref this.modelMatrix, out res); lp1 = res.ToVector3(); var lv = lp1 - lp0; var hitPointWS = lp0 + lv * t; result.Distance = (rayWS.Position - hitPointWS).Length(); result.PointHit = hitPointWS.ToPoint3D(); result.ModelHit = this; result.IsValid = true; result.Tag = index; // ToDo: LineHitTag with additional info } index++; } if (result.IsValid) { hits.Add(result); } return(result.IsValid); }
public MouseMove3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null) : base(GeometryModel3D.MouseMove3DEvent, source, hitTestResult, position, viewport) { }
/// <summary> /// Initial implementation of hittest for billboard. Needs further improvement. /// </summary> /// <param name="rayWS"></param> /// <param name="hits"></param> /// <returns></returns> public override bool HitTest(Ray rayWS, ref List <HitTestResult> hits) { if (this.Visibility == Visibility.Collapsed || this.Visibility == Visibility.Hidden) { return(false); } if (this.IsHitTestVisible == false) { return(false); } var g = this.Geometry as IBillboardText; var h = false; var result = new HitTestResult(); result.Distance = double.MaxValue; Viewport3DX viewport; if ((viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null || g.Width == 0 || g.Height == 0) { return(false); } if (g != null) { var visualToScreen = viewport.GetViewProjectionMatrix() * viewport.GetViewportMatrix(); float heightScale = 1; var screenToVisual = visualToScreen.Inverted(); var center = new Vector4(g.Positions[0], 1); var screenPoint = Vector4.Transform(center, visualToScreen); var spw = screenPoint.W; var spx = screenPoint.X; var spy = screenPoint.Y; var spz = screenPoint.Z; var left = -g.Width / 2; var right = g.Width / 2; var top = -g.Height / 2 * heightScale; var bottom = g.Height / 2 * heightScale; Debug.WriteLine(spw); Debug.WriteLine(string.Format("Z={0}; W={1}", spz, spw)); var bl = new Vector4(spx + left * spw, spy + bottom * spw, spz, spw); bl = Vector4.Transform(bl, screenToVisual); bl /= bl.W; var br = new Vector4(spx + right * spw, spy + bottom * spw, spz, spw); br = Vector4.Transform(br, screenToVisual); br /= br.W; var tr = new Vector4(spx + right * spw, spy + top * spw, spz, spw); tr = Vector4.Transform(tr, screenToVisual); tr /= tr.W; var tl = new Vector4(spx + left * spw, spy + top * spw, spz, spw); tl = Vector4.Transform(tl, screenToVisual); tl /= tl.W; var b = BoundingBox.FromPoints(new Vector3[] { tl.ToVector3(), tr.ToVector3(), bl.ToVector3(), br.ToVector3() }); // this all happens now in world space now: Debug.WriteLine(string.Format("RayPosition:{0}; Direction:{1};", rayWS.Position, rayWS.Direction)); if (rayWS.Intersects(ref b)) { float distance; if (Collision.RayIntersectsBox(ref rayWS, ref b, out distance)) { h = true; result.ModelHit = this; result.IsValid = true; result.PointHit = (rayWS.Position + (rayWS.Direction * distance)).ToPoint3D(); result.Distance = distance; Debug.WriteLine(string.Format("Hit; HitPoint:{0}; Bound={1}; Distance={2}", result.PointHit, b, distance)); } } } if (h) { hits.Add(result); } return(h); }
public Mouse3DEventArgs(RoutedEvent routedEvent, object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null) : base(routedEvent, source) { this.HitTestResult = hitTestResult; this.Position = position; this.Viewport = viewport; }
private void SetSelectedElement(Helix.HitTestResult hit) { var model = hit?.ModelHit as Helix.Element3D; SetSelectedElement(model); }
public MouseMove3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null, InputEventArgs originalInputEventArgs = null) : base(Element3D.MouseMove3DEvent, source, hitTestResult, position, viewport, originalInputEventArgs) { }
/// <summary> /// Checks if the ray hits the geometry of the model. /// If there a more than one hit, result returns the hit which is nearest to the ray origin. /// </summary> /// <param name="rayWS">Hitring ray from the camera.</param> /// <param name="result">results of the hit.</param> /// <returns>True if the ray hits one or more times.</returns> public override bool HitTest(Ray rayWS, ref List<HitTestResult> hits) { PointGeometry3D pointGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null || (pointGeometry3D = this.Geometry as PointGeometry3D) == null) { return false; } var svpm = viewport.GetScreenViewProjectionMatrix(); var smvpm = this.modelMatrix * svpm; var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1); var pos4 = new Vector4(rayWS.Position, 1); var dir3 = new Vector3(); Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4); Vector4.Transform(ref pos4, ref svpm, out pos4); Vector3.TransformNormal(ref rayWS.Direction, ref svpm, out dir3); dir3.Normalize(); var clickPoint = clickPoint4.ToVector3(); var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var maxDist = this.HitTestThickness; var lastDist = double.MaxValue; var index = 0; foreach (var point in pointGeometry3D.Points) { var p0 = Vector3.TransformCoordinate(point.P0, smvpm); var pv = p0 - clickPoint; var dist = pv.Length(); if (dist < lastDist && dist <= maxDist) { lastDist = dist; Vector4 res; var lp0 = point.P0; Vector3.Transform(ref lp0, ref this.modelMatrix, out res); var pvv = res.ToVector3(); var dst = DistanceRayToPoint(rayWS, pvv); result.Distance = dst; result.PointHit = pvv.ToPoint3D(); result.ModelHit = this; result.IsValid = true; result.Tag = index; } index++; } if (result.IsValid) { hits.Add(result); } return result.IsValid; }
public MouseUp3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null) : base(Element3D.MouseUp3DEvent, source, hitTestResult, position, viewport) { }
/// <summary> /// Checks if the ray hits the geometry of the model. /// If there a more than one hit, result returns the hit which is nearest to the ray origin. /// </summary> /// <param name="rayWS">Hitring ray from the camera.</param> /// <param name="result">results of the hit.</param> /// <returns>True if the ray hits one or more times.</returns> public override bool HitTest(Ray rayWS, ref List <HitTestResult> hits) { PointGeometry3D pointGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null || (pointGeometry3D = this.Geometry as PointGeometry3D) == null) { return(false); } var svpm = viewport.GetScreenViewProjectionMatrix(); var smvpm = this.modelMatrix * svpm; var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1); var pos4 = new Vector4(rayWS.Position, 1); var dir3 = new Vector3(); Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4); Vector4.Transform(ref pos4, ref svpm, out pos4); Vector3.TransformNormal(ref rayWS.Direction, ref svpm, out dir3); dir3.Normalize(); var clickPoint = clickPoint4.ToVector3(); var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var maxDist = this.HitTestThickness; var lastDist = double.MaxValue; var index = 0; foreach (var point in pointGeometry3D.Points) { var p0 = Vector3.TransformCoordinate(point.P0, smvpm); var pv = p0 - clickPoint; var dist = pv.Length(); if (dist < lastDist && dist <= maxDist) { lastDist = dist; Vector4 res; var lp0 = point.P0; Vector3.Transform(ref lp0, ref this.modelMatrix, out res); var pvv = res.ToVector3(); var dst = DistanceRayToPoint(rayWS, pvv); result.Distance = dst; result.PointHit = pvv.ToPoint3D(); result.ModelHit = this; result.IsValid = true; result.Tag = index; } index++; } if (result.IsValid) { hits.Add(result); } return(result.IsValid); }
protected override bool OnHitTest(IRenderMatrices context, Ray rayWS, ref List <HitTestResult> hits) { var g = this.geometryInternal as MeshGeometry3D; bool isHit = false; if (g.Octree != null) { isHit = g.Octree.HitTest(context, this, ModelMatrix, rayWS, ref hits); } else { var result = new HitTestResult(); result.Distance = double.MaxValue; if (g != null) { var modelInvert = this.modelMatrix.Inverted(); //transform ray into model coordinates var rayModel = new Ray(Vector3.TransformCoordinate(rayWS.Position, modelInvert), Vector3.TransformNormal(rayWS.Direction, modelInvert)); var b = Bounds; //Do hit test in local space if (rayModel.Intersects(ref b)) { int index = 0; foreach (var t in g.Triangles) { float d; var v0 = t.P0; var v1 = t.P1; var v2 = t.P2; if (Collision.RayIntersectsTriangle(ref rayModel, ref v0, ref v1, ref v2, out d)) { if (d > 0 && d < result.Distance) // If d is NaN, the condition is false. { result.IsValid = true; result.ModelHit = this; // transform hit-info to world space now: var pointWorld = Vector3.TransformCoordinate(rayModel.Position + (rayModel.Direction * d), modelMatrix); result.PointHit = pointWorld.ToPoint3D(); 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.ToVector3D();// Vector3.TransformNormal(n, m).ToVector3D(); result.TriangleIndices = new System.Tuple <int, int, int>(g.Indices[index], g.Indices[index + 1], g.Indices[index + 2]); result.Tag = index / 3; isHit = true; } } index += 3; } } } if (isHit) { hits.Add(result); } } return(isHit); }
public override bool HitTest(Ray rayWS, ref List<HitTestResult> hits) { LineGeometry3D lineGeometry3D; Viewport3DX viewport; if (this.Visibility == Visibility.Collapsed || this.IsHitTestVisible == false || (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null || (lineGeometry3D = this.Geometry as LineGeometry3D) == null) { return false; } // revert unprojection; probably better: overloaded HitTest() for LineGeometryModel3D? var svpm = viewport.GetScreenViewProjectionMatrix(); var smvpm = this.modelMatrix * svpm; var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1); Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4); var clickPoint = clickPoint4.ToVector3(); var result = new HitTestResult { IsValid = false, Distance = double.MaxValue }; var maxDist = this.HitTestThickness; var lastDist = double.MaxValue; var index = 0; foreach (var line in lineGeometry3D.Lines) { var p0 = Vector3.TransformCoordinate(line.P0, smvpm); var p1 = Vector3.TransformCoordinate(line.P1, smvpm); Vector3 hitPoint; float t; var dist = LineBuilder.GetPointToLineDistance2D(ref clickPoint, ref p0, ref p1, out hitPoint, out t); if (dist < lastDist && dist <= maxDist) { lastDist = dist; Vector4 res; var lp0 = line.P0; Vector3.Transform(ref lp0, ref this.modelMatrix, out res); lp0 = res.ToVector3(); var lp1 = line.P1; Vector3.Transform(ref lp1, ref this.modelMatrix, out res); lp1 = res.ToVector3(); var lv = lp1 - lp0; var hitPointWS = lp0 + lv * t; result.Distance = (rayWS.Position - hitPointWS).Length(); result.PointHit = hitPointWS.ToPoint3D(); result.ModelHit = this; result.IsValid = true; result.Tag = index; // ToDo: LineHitTag with additional info } index++; } if (result.IsValid) { hits.Add(result); } return result.IsValid; }
/// <summary> /// Checks if the ray hits the geometry of the model. /// If there a more than one hit, result returns the hit which is nearest to the ray origin. /// </summary> /// <param name="rayWS">Hitring ray from the camera.</param> /// <param name="result">results of the hit.</param> /// <returns>True if the ray hits one or more times.</returns> public virtual bool HitTest(Ray rayWS, ref List<HitTestResult> hits) { if (this.Visibility == Visibility.Collapsed) { return false; } if (this.IsHitTestVisible == false) { return false; } var g = this.Geometry as MeshGeometry3D; var isHit = false; var result = new HitTestResult(); result.Distance = double.MaxValue; if (g != null) { var m = this.modelMatrix; // put bounds to world space var b = BoundingBox.FromPoints(this.Bounds.GetCorners().Select(x => Vector3.TransformCoordinate(x, m)).ToArray()); //var b = this.Bounds; // this all happens now in world space now: if (rayWS.Intersects(ref b)) { int index = 0; foreach (var t in g.Triangles) { float d; var p0 = Vector3.TransformCoordinate(t.P0, m); var p1 = Vector3.TransformCoordinate(t.P1, m); var p2 = Vector3.TransformCoordinate(t.P2, m); if (Collision.RayIntersectsTriangle(ref rayWS, ref p0, ref p1, ref p2, out d)) { if (d > 0 && d < result.Distance) // If d is NaN, the condition is false. { result.IsValid = true; result.ModelHit = this; // transform hit-info to world space now: result.PointHit = (rayWS.Position + (rayWS.Direction * d)).ToPoint3D(); result.Distance = d; var n = Vector3.Cross(p1 - p0, p2 - p0); n.Normalize(); // transform hit-info to world space now: result.NormalAtHit = n.ToVector3D();// Vector3.TransformNormal(n, m).ToVector3D(); result.TriangleIndices = new System.Tuple<int, int, int>(g.Indices[index], g.Indices[index + 1], g.Indices[index + 2]); isHit = true; } } index += 3; } } } if (isHit) { hits.Add(result); } return isHit; }
/// <summary> /// Initial implementation of hittest for billboard. Needs further improvement. /// </summary> /// <param name="rayWS"></param> /// <param name="hits"></param> /// <returns></returns> protected override bool OnHitTest(IRenderMatrices context, Ray rayWS, ref List <HitTestResult> hits) { var g = this.geometryInternal as IBillboardText; var h = false; var result = new HitTestResult(); result.Distance = double.MaxValue; if (context == null || g.Width == 0 || g.Height == 0) { return(false); } if (g != null) { BoundingBox b = new BoundingBox(); var left = -g.Width / 2; var right = -left; var top = -g.Height / 2; var bottom = -top; if (FixedSize) { var viewportMatrix = context.ViewportMatrix; var projectionMatrix = context.ProjectionMatrix; var viewMatrix = context.ViewMatrix; var visualToScreen = viewMatrix * projectionMatrix * viewportMatrix; var center = new Vector4(g.Positions[0], 1); var screenPoint = Vector4.Transform(center, visualToScreen); var spw = screenPoint.W; var spx = screenPoint.X; var spy = screenPoint.Y; var spz = screenPoint.Z / spw / projectionMatrix.M33; var matrix = CameraExtensions.InverseViewMatrix(ref viewMatrix); var width = (float)context.ActualWidth; var height = (float)context.ActualHeight; Vector3 v = new Vector3(); var x = spx + left * spw; var y = spy + bottom * spw; v.X = (2 * x / width / spw - 1) / projectionMatrix.M11; v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22; v.Z = spz; Vector3 bl; Vector3.TransformCoordinate(ref v, ref matrix, out bl); x = spx + right * spw; y = spy + bottom * spw; v.X = (2 * x / width / spw - 1) / projectionMatrix.M11; v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22; v.Z = spz; Vector3 br; Vector3.TransformCoordinate(ref v, ref matrix, out br); x = spx + right * spw; y = spy + top * spw; v.X = (2 * x / width / spw - 1) / projectionMatrix.M11; v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22; v.Z = spz; Vector3 tr; Vector3.TransformCoordinate(ref v, ref matrix, out tr); x = spx + left * spw; y = spy + top * spw; v.X = (2 * x / width / spw - 1) / projectionMatrix.M11; v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22; v.Z = spz; Vector3 tl; Vector3.TransformCoordinate(ref v, ref matrix, out tl); b = BoundingBox.FromPoints(new Vector3[] { tl, tr, bl, br }); /* * var visualToScreen = viewport.GetViewProjectionMatrix() * viewport.GetViewportMatrix(); * * var screenToVisual = visualToScreen.Inverted(); * * var center = new Vector4(g.Positions[0], 1); * var screenPoint = Vector4.Transform(center, visualToScreen); * var spw = screenPoint.W; * var spx = screenPoint.X; * var spy = screenPoint.Y; * var spz = screenPoint.Z; * * //Debug.WriteLine(spw); * // Debug.WriteLine(string.Format("Z={0}; W={1}", spz, spw)); * var bl = new Vector4(spx + left * spw, spy + bottom * spw, spz, spw); * bl = Vector4.Transform(bl, screenToVisual); * bl /= bl.W; * * var br = new Vector4(spx + right * spw, spy + bottom * spw, spz, spw); * br = Vector4.Transform(br, screenToVisual); * br /= br.W; * * var tr = new Vector4(spx + right * spw, spy + top * spw, spz, spw); * tr = Vector4.Transform(tr, screenToVisual); * tr /= tr.W; * * var tl = new Vector4(spx + left * spw, spy + top * spw, spz, spw); * tl = Vector4.Transform(tl, screenToVisual); * tl /= tl.W; * * b = BoundingBox.FromPoints(new Vector3[] { tl.ToVector3(), tr.ToVector3(), bl.ToVector3(), br.ToVector3() }); */ } else { var center = new Vector4(g.Positions[0], 1); var viewMatrix = context.ViewMatrix; var vcenter = Vector4.Transform(center, viewMatrix); var vcX = vcenter.X; var vcY = vcenter.Y; var bl = new Vector4(vcX + left, vcY + bottom, vcenter.Z, vcenter.W); var br = new Vector4(vcX + right, vcY + bottom, vcenter.Z, vcenter.W); var tr = new Vector4(vcX + right, vcY + top, vcenter.Z, vcenter.W); var tl = new Vector4(vcX + left, vcY + top, vcenter.Z, vcenter.W); var invViewMatrix = CameraExtensions.InverseViewMatrix(ref viewMatrix); bl = Vector4.Transform(bl, invViewMatrix); bl /= bl.W; br = Vector4.Transform(br, invViewMatrix); br /= br.W; tr = Vector4.Transform(tr, invViewMatrix); tr /= tr.W; tl = Vector4.Transform(tl, invViewMatrix); tl /= tl.W; b = BoundingBox.FromPoints(new Vector3[] { tl.ToVector3(), tr.ToVector3(), bl.ToVector3(), br.ToVector3() }); } // this all happens now in world space now: //Debug.WriteLine(string.Format("RayPosition:{0}; Direction:{1};", rayWS.Position, rayWS.Direction)); if (rayWS.Intersects(ref b)) { float distance; if (Collision.RayIntersectsBox(ref rayWS, ref b, out distance)) { h = true; result.ModelHit = this; result.IsValid = true; result.PointHit = (rayWS.Position + (rayWS.Direction * distance)).ToPoint3D(); result.Distance = distance; Debug.WriteLine(string.Format("Hit; HitPoint:{0}; Bound={1}; Distance={2}", result.PointHit, b, distance)); } } } if (h) { hits.Add(result); } return(h); }
/// <summary> /// Checks if the ray hits the geometry of the model. /// If there a more than one hit, result returns the hit which is nearest to the ray origin. /// </summary> /// <param name="rayWS">Hitring ray from the camera.</param> /// <param name="result">results of the hit.</param> /// <returns>True if the ray hits one or more times.</returns> public virtual bool HitTest(Ray rayWS, ref List <HitTestResult> hits) { if (this.Visibility == Visibility.Collapsed) { return(false); } if (this.IsHitTestVisible == false) { return(false); } var g = this.Geometry as MeshGeometry3D; var isHit = false; var result = new HitTestResult(); result.Distance = double.MaxValue; if (g != null) { var m = this.modelMatrix; // put bounds to world space var b = BoundingBox.FromPoints(this.Bounds.GetCorners().Select(x => Vector3.TransformCoordinate(x, m)).ToArray()); //var b = this.Bounds; // this all happens now in world space now: if (rayWS.Intersects(ref b)) { int index = 0; foreach (var t in g.Triangles) { float d; var p0 = Vector3.TransformCoordinate(t.P0, m); var p1 = Vector3.TransformCoordinate(t.P1, m); var p2 = Vector3.TransformCoordinate(t.P2, m); if (Collision.RayIntersectsTriangle(ref rayWS, ref p0, ref p1, ref p2, out d)) { if (d > 0 && d < result.Distance) // If d is NaN, the condition is false. { result.IsValid = true; result.ModelHit = this; // transform hit-info to world space now: result.PointHit = (rayWS.Position + (rayWS.Direction * d)).ToPoint3D(); result.Distance = d; var n = Vector3.Cross(p1 - p0, p2 - p0); n.Normalize(); // transform hit-info to world space now: result.NormalAtHit = n.ToVector3D();// Vector3.TransformNormal(n, m).ToVector3D(); result.TriangleIndices = new System.Tuple <int, int, int>(g.Indices[index], g.Indices[index + 1], g.Indices[index + 2]); isHit = true; } } index += 3; } } } if (isHit) { hits.Add(result); } return(isHit); }