/// <summary> /// Un-projects a 2D screen point. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="point2d">The input point.</param> /// <returns>The ray.</returns> public static Ray UnProject(this Viewport3DX viewport, Vector2 point2d)//, out Vector3 pointNear, out Vector3 pointFar) { var camera = viewport.Camera as ProjectionCamera; if (camera != null) { var px = (float)point2d.X; var py = (float)point2d.Y; var viewMatrix = camera.GetViewMatrix(); Vector3 v = new Vector3(); var matrix = CameraExtensions.InverseViewMatrix(ref viewMatrix); float w = (float)viewport.ActualWidth; float h = (float)viewport.ActualHeight; var aspectRatio = w / h; var projMatrix = camera.GetProjectionMatrix(aspectRatio); Vector3 zn, zf; v.X = (2 * px / w - 1) / projMatrix.M11; v.Y = -(2 * py / h - 1) / projMatrix.M22; v.Z = 1 / projMatrix.M33; Vector3.TransformCoordinate(ref v, ref matrix, out zf); if (camera is PerspectiveCamera) { zn = camera.Position.ToVector3(); } else { v.Z = 0; Vector3.TransformCoordinate(ref v, ref matrix, out zn); } Vector3 r = zf - zn; r.Normalize(); return(new Ray(zn, r)); } throw new HelixToolkitException("Unproject camera error."); }
/// <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); }