public static Ray UnProject(this Vector2 point2d, ref Matrix view, ref Matrix projection, float nearPlane, float w, float h, bool isPerpective) { var px = point2d.X; var py = point2d.Y; var matrix = MatrixExtensions.PsudoInvert(ref view); var v = new Vector3 { X = (2 * px / w - 1) / projection.M11, Y = -(2 * py / h - 1) / projection.M22, Z = 1 / projection.M33 }; Vector3.TransformCoordinate(ref v, ref matrix, out var zf); Vector3 zn; if (isPerpective) { zn = new Vector3(matrix.M41, matrix.M42, matrix.M43); } else { v.Z = 0; Vector3.TransformCoordinate(ref v, ref matrix, out zn); } var r = zf - zn; r.Normalize(); return(new Ray(zn + r * nearPlane, r)); }
/// <summary> /// Un-project 2D screen point onto 3D space by camera. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="point2d">The point2d.</param> /// <param name="ray">The ray.</param> /// <returns></returns> public static bool UnProject(this IViewport3DX viewport, Vector2 point2d, out Ray ray)//, out Vector3 pointNear, out Vector3 pointFar) { if (viewport.RenderHost != null && viewport.CameraCore is ProjectionCameraCore camera) { var px = point2d.X; var py = point2d.Y; var viewMatrix = camera.CreateViewMatrix(); var matrix = MatrixExtensions.PsudoInvert(ref viewMatrix); float w = viewport.RenderHost.ActualWidth; float h = viewport.RenderHost.ActualHeight; var aspectRatio = w / h; var projMatrix = camera.CreateProjectionMatrix(aspectRatio); Vector3 v = new Vector3 { X = (2 * px / w - 1) / projMatrix.M11, Y = -(2 * py / h - 1) / projMatrix.M22, Z = 1 / projMatrix.M33 }; Vector3.TransformCoordinate(ref v, ref matrix, out Vector3 zf); Vector3 zn; if (camera is PerspectiveCameraCore) { zn = camera.Position; } else { v.Z = 0; Vector3.TransformCoordinate(ref v, ref matrix, out zn); } Vector3 r = zf - zn; r.Normalize(); ray = new Ray(zn + r * camera.NearPlaneDistance, r); return(true); } else { ray = new Ray(); return(false); } }
/// <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 ViewportCore viewport, Vector2 point2d) { var camera = viewport.CameraCore as ProjectionCameraCore; if (camera != null) { var px = (float)point2d.X; var py = (float)point2d.Y; var viewMatrix = camera.CreateViewMatrix(); Vector3 v = new Vector3(); var matrix = MatrixExtensions.PsudoInvert(ref viewMatrix); float w = (float)viewport.ViewportRectangle.Width; float h = (float)viewport.ViewportRectangle.Height; var aspectRatio = w / h; var projMatrix = camera.CreateProjectionMatrix(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 PerspectiveCameraCore) { zn = camera.Position; } else { v.Z = 0; Vector3.TransformCoordinate(ref v, ref matrix, out zn); } Vector3 r = zf - zn; r.Normalize(); return(new Ray(zn + r * camera.NearPlaneDistance, r)); } throw new HelixToolkitException("Unproject camera error."); }
protected override bool OnHitTest(RenderContext context, Matrix totalModelMatrix, ref Ray ray, ref List <HitTestResult> hits) { var p = Vector3.TransformCoordinate(ray.Position, context.ScreenViewProjectionMatrix); var screenSpaceCore = RenderCore as ScreenSpacedMeshRenderCore; float viewportSize = screenSpaceCore.Size * screenSpaceCore.SizeScale; var offx = (float)(context.ActualWidth / 2 * (1 + screenSpaceCore.RelativeScreenLocationX) - viewportSize / 2); var offy = (float)(context.ActualHeight / 2 * (1 + screenSpaceCore.RelativeScreenLocationY) - viewportSize / 2); offx = Math.Max(0, Math.Min(offx, (int)(context.ActualWidth - viewportSize))); offy = Math.Max(0, Math.Min(offy, (int)(context.ActualHeight - viewportSize))); var px = p.X - offx; var py = p.Y - offy; if (px < 0 || py < 0 || px > viewportSize || py > viewportSize) { return(false); } var viewMatrix = screenSpaceCore.GlobalTransform.View; Vector3 v = new Vector3(); var matrix = MatrixExtensions.PsudoInvert(ref viewMatrix); var aspectRatio = screenSpaceCore.ScreenRatio; var projMatrix = screenSpaceCore.GlobalTransform.Projection; Vector3 zn; v.X = (2 * px / viewportSize - 1) / projMatrix.M11; v.Y = (2 * py / viewportSize - 1) / projMatrix.M22; v.Z = 1 / projMatrix.M33; Vector3.TransformCoordinate(ref v, ref matrix, out Vector3 zf); if (screenSpaceCore.IsPerspective) { zn = screenSpaceCore.GlobalTransform.EyePos; } else { v.Z = 0; Vector3.TransformCoordinate(ref v, ref matrix, out zn); } Vector3 r = zf - zn; r.Normalize(); ray = new Ray(zn, r); List <HitTestResult> viewBoxHit = new List <HitTestResult>(); if (base.OnHitTest(context, totalModelMatrix, ref ray, ref viewBoxHit)) { hits?.Clear(); hits = viewBoxHit; Debug.WriteLine("View box hit."); var hit = viewBoxHit[0]; Vector3 normal = Vector3.Zero; int inv = isRightHanded ? 1 : -1; if (hit.ModelHit == ViewBoxMeshModel) { normal = -hit.NormalAtHit * inv; //Fix the normal if returned normal is reversed if (Vector3.Dot(normal, context.Camera.LookDirection) < 0) { normal *= -1; } } else if (hit.Tag is int index) { if (hit.ModelHit == EdgeModel && index < edgeInstances.Length) { Matrix transform = edgeInstances[index]; normal = -transform.TranslationVector; } else if (hit.ModelHit == CornerModel && index < cornerInstances.Length) { Matrix transform = cornerInstances[index]; normal = -transform.TranslationVector; } else { return(false); } } else { return(false); } normal.Normalize(); if (Vector3.Cross(normal, UpDirection).LengthSquared() < 1e-5) { var vecLeft = new Vector3(-normal.Y, -normal.Z, -normal.X); OnViewBoxClicked?.Invoke(this, new ViewBoxClickedEventArgs(normal, vecLeft)); } else { OnViewBoxClicked?.Invoke(this, new ViewBoxClickedEventArgs(normal, UpDirection)); } return(true); } else { return(false); } }
protected override bool OnHitTest(RenderContext context, Matrix totalModelMatrix, ref Ray ray, ref List <HitTestResult> hits) { var p = Vector3.TransformCoordinate(ray.Position, context.ScreenViewProjectionMatrix); var screenSpaceCore = RenderCore as ScreenSpacedMeshRenderCore; float viewportSize = screenSpaceCore.Size * screenSpaceCore.SizeScale; var offx = (float)(context.ActualWidth / 2 * (1 + screenSpaceCore.RelativeScreenLocationX) - viewportSize / 2); var offy = (float)(context.ActualHeight / 2 * (1 + screenSpaceCore.RelativeScreenLocationY) - viewportSize / 2); offx = Math.Max(0, Math.Min(offx, (int)(context.ActualWidth - viewportSize))); offy = Math.Max(0, Math.Min(offy, (int)(context.ActualHeight - viewportSize))); var px = p.X - offx; var py = p.Y - offy; if (px < 0 || py < 0 || px > viewportSize || py > viewportSize) { return(false); } var viewMatrix = screenSpaceCore.GlobalTransform.View; Vector3 v = new Vector3(); var matrix = MatrixExtensions.PsudoInvert(ref viewMatrix); var aspectRatio = screenSpaceCore.ScreenRatio; var projMatrix = screenSpaceCore.GlobalTransform.Projection; Vector3 zn; v.X = (2 * px / viewportSize - 1) / projMatrix.M11; v.Y = (2 * py / viewportSize - 1) / projMatrix.M22; v.Z = 1 / projMatrix.M33; Vector3.TransformCoordinate(ref v, ref matrix, out Vector3 zf); if (screenSpaceCore.IsPerspective) { zn = screenSpaceCore.GlobalTransform.EyePos; } else { v.Z = 0; Vector3.TransformCoordinate(ref v, ref matrix, out zn); } Vector3 r = zf - zn; r.Normalize(); ray = new Ray(zn, r); screenSpaceHits.Clear(); if (base.OnHitTest(context, totalModelMatrix, ref ray, ref screenSpaceHits)) { if (hits == null) { hits = new List <HitTestResult>(); } hits.Clear(); hits.AddRange(screenSpaceHits); return(true); } else { return(false); } }