/// <summary> /// Gets the projection matrix for the specified camera. /// </summary> /// <param name="camera">The camera.</param> /// <param name="aspectRatio">The aspect ratio.</param> /// <returns>The projection matrix.</returns> public static Matrix GetProjectionMatrix(this Camera camera, double aspectRatio) { if (camera == null) { throw new ArgumentNullException("camera"); } var perspectiveCamera = camera as PerspectiveCamera; if (perspectiveCamera != null) { return(Matrix.PerspectiveFovRH( (float)perspectiveCamera.FieldOfView, (float)(aspectRatio), (float)perspectiveCamera.NearPlaneDistance, (float)perspectiveCamera.FarPlaneDistance)); } var orthographicCamera = camera as OrthographicCamera; if (orthographicCamera != null) { return(Matrix.OrthoRH( (float)orthographicCamera.Width, (float)(orthographicCamera.Width / aspectRatio), (float)orthographicCamera.NearPlaneDistance, (float)orthographicCamera.FarPlaneDistance)); } throw new HelixToolkitException("Unknown camera type."); }
/// <summary> /// Gets the inverse camera transform. /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <param name="aspectRatio"> /// The aspect ratio. /// </param> /// <returns> /// The inverse transform. /// </returns> public static Matrix GetInverseViewProjectionMatrix(this Camera camera, double aspectRatio) { var m = GetViewProjectionMatrix(camera, aspectRatio); m.Invert(); return(m); }
/// <summary> /// Copies the specified camera, converts field of view/width if necessary. /// </summary> /// <param name="source"> /// The source camera. /// </param> /// <param name="dest"> /// The destination camera. /// </param> public static void CopyTo(this Camera source, Camera dest) { var projectionSource = source as ProjectionCamera; var projectionDest = dest as ProjectionCamera; if (projectionSource == null || projectionDest == null) { return; } projectionDest.LookDirection = projectionSource.LookDirection; projectionDest.Position = projectionSource.Position; projectionDest.UpDirection = projectionSource.UpDirection; var psrc = source as PerspectiveCamera; var osrc = source as OrthographicCamera; var pdest = dest as PerspectiveCamera; var odest = dest as OrthographicCamera; if (pdest != null) { projectionDest.NearPlaneDistance = projectionSource.NearPlaneDistance > 0 ? projectionSource.NearPlaneDistance : 1e-1; projectionDest.FarPlaneDistance = projectionSource.FarPlaneDistance; double fov = 45; if (psrc != null) { fov = psrc.FieldOfView; } if (osrc != null) { double dist = projectionSource.LookDirection.Length; fov = Math.Atan2(osrc.Width / 2, dist) * (180 / Math.PI); } pdest.FieldOfView = fov; } if (odest != null) { projectionDest.NearPlaneDistance = projectionSource.NearPlaneDistance; projectionDest.FarPlaneDistance = projectionSource.FarPlaneDistance; double width = 100; if (psrc != null) { double dist = projectionSource.LookDirection.Length; width = Math.Tan(psrc.FieldOfView / 180 * Math.PI) * 2 * dist; } if (osrc != null) { width = osrc.Width; } odest.Width = width; } }
/// <summary> /// Get the combined view and projection transform /// </summary> /// <param name="camera">The camera.</param> /// <param name="aspectRatio">The aspect ratio.</param> /// <returns>The total view and projection transform.</returns> public static Matrix GetViewProjectionMatrix(this Camera camera, double aspectRatio) { if (camera == null) { throw new ArgumentNullException("camera"); } return(GetViewMatrix(camera) * GetProjectionMatrix(camera, aspectRatio)); }
/// <summary> /// Animates the camera position and directions. /// </summary> /// <param name="camera"> /// The camera to animate. /// </param> /// <param name="newPosition"> /// The position to animate to. /// </param> /// <param name="newDirection"> /// The direction to animate to. /// </param> /// <param name="newUpDirection"> /// The up direction to animate to. /// </param> /// <param name="animationTime"> /// Animation time in milliseconds. /// </param> public static void AnimateTo( this Camera camera, Point3D newPosition, Vector3D newDirection, Vector3D newUpDirection, double animationTime) { var projectionCamera = camera as ProjectionCamera; if (projectionCamera == null) { return; } var fromPosition = projectionCamera.Position; var fromDirection = projectionCamera.LookDirection; var fromUpDirection = projectionCamera.UpDirection; projectionCamera.Position = newPosition; projectionCamera.LookDirection = newDirection; projectionCamera.UpDirection = newUpDirection; if (animationTime > 0) { var a1 = new Point3DAnimation( fromPosition, newPosition, new Duration(TimeSpan.FromMilliseconds(animationTime))) { AccelerationRatio = 0.3, DecelerationRatio = 0.5, FillBehavior = FillBehavior.Stop }; a1.Completed += (s, a) => { camera.BeginAnimation(ProjectionCamera.PositionProperty, null); }; camera.BeginAnimation(ProjectionCamera.PositionProperty, a1); var a2 = new Vector3DAnimation( fromDirection, newDirection, new Duration(TimeSpan.FromMilliseconds(animationTime))) { AccelerationRatio = 0.3, DecelerationRatio = 0.5, FillBehavior = FillBehavior.Stop }; a2.Completed += (s, a) => { camera.BeginAnimation(ProjectionCamera.LookDirectionProperty, null); }; camera.BeginAnimation(ProjectionCamera.LookDirectionProperty, a2); var a3 = new Vector3DAnimation( fromUpDirection, newUpDirection, new Duration(TimeSpan.FromMilliseconds(animationTime))) { AccelerationRatio = 0.3, DecelerationRatio = 0.5, FillBehavior = FillBehavior.Stop }; a3.Completed += (s, a) => { camera.BeginAnimation(ProjectionCamera.UpDirectionProperty, null); }; camera.BeginAnimation(ProjectionCamera.UpDirectionProperty, a3); } }
/// <summary> /// Set the camera target point without changing the look direction. /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="animationTime"> /// The animation time. /// </param> public static void LookAt(this Camera camera, Point3D target, double animationTime) { var projectionCamera = camera as ProjectionCamera; if (projectionCamera == null) { return; } LookAt(camera, target, projectionCamera.LookDirection, animationTime); }
/// <summary> /// Zooms to fit the extents of the specified viewport. /// </summary> /// <param name="camera"> /// The actual camera. /// </param> /// <param name="viewport"> /// The viewport. /// </param> /// <param name="animationTime"> /// The animation time. /// </param> public static void ZoomExtents( this Camera camera, Viewport3DX viewport, double animationTime = 0) { var bounds = viewport.FindBounds(); var diagonal = new Vector3D(bounds.SizeX, bounds.SizeY, bounds.SizeZ); if (bounds.IsEmpty || diagonal.LengthSquared.Equals(0)) { return; } ZoomExtents(camera as ProjectionCamera, viewport, bounds, animationTime); }
/// <summary> /// Set the camera target point and camera distance. /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <param name="target"> /// The target point. /// </param> /// <param name="distance"> /// The distance to the camera. /// </param> /// <param name="animationTime"> /// The animation time. /// </param> public static void LookAt(this Camera camera, Point3D target, double distance, double animationTime) { var projectionCamera = camera as ProjectionCamera; if (projectionCamera == null) { return; } var d = projectionCamera.LookDirection; d.Normalize(); LookAt(projectionCamera, target, d * distance, animationTime); }
/// <summary> /// Zooms to fit the specified bounding rectangle. /// </summary> /// <param name="camera"> /// The actual camera. /// </param> /// <param name="viewport"> /// The viewport. /// </param> /// <param name="bounds"> /// The bounding rectangle. /// </param> /// <param name="animationTime"> /// The animation time. /// </param> public static void ZoomExtents( this Camera camera, Viewport3DX viewport, Rect3D bounds, double animationTime = 0) { var projectionCamera = camera as ProjectionCamera; if (projectionCamera == null) { return; } var diagonal = new Vector3D(bounds.SizeX, bounds.SizeY, bounds.SizeZ); var center = bounds.Location + (diagonal * 0.5); double radius = diagonal.Length * 0.5; ZoomExtents(projectionCamera, viewport, center, radius, animationTime); }
/// <summary> /// Resets the specified camera. /// </summary> /// <param name="camera"> /// The camera. /// </param> public static void Reset(this Camera camera) { var projectionCamera = camera as PerspectiveCamera; if (projectionCamera != null) { Reset(projectionCamera); } var ocamera = camera as OrthographicCamera; if (ocamera != null) { Reset(ocamera); } }
/// <summary> /// Obtains the view transform matrix for a camera. (see page 327) /// </summary> /// <param name="camera"> /// Camera to obtain the ViewMatrix for /// </param> /// <returns> /// A Matrix object with the camera view transform matrix, or a Matrix with all zeros if the "camera" is null. /// </returns> public static Matrix GetViewMatrix(this Camera camera) { if (camera == null) { throw new ArgumentNullException("camera"); } if (camera is ProjectionCamera) { var projcam = camera as ProjectionCamera; return(Matrix.LookAtRH( projcam.Position.ToVector3(), (projcam.Position + projcam.LookDirection).ToVector3(), projcam.UpDirection.ToVector3())); } throw new HelixToolkitException("Unknown camera type."); }
/// <summary> /// Set the camera target point and directions /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <param name="target"> /// The target. /// </param> /// <param name="newLookDirection"> /// The new look direction. /// </param> /// <param name="newUpDirection"> /// The new up direction. /// </param> /// <param name="animationTime"> /// The animation time. /// </param> public static void LookAt( this Camera camera, Point3D target, Vector3D newLookDirection, Vector3D newUpDirection, double animationTime) { Point3D newPosition = target - newLookDirection; if (camera is PerspectiveCamera) { AnimateTo(camera as PerspectiveCamera, newPosition, newLookDirection, newUpDirection, animationTime); } if (camera is OrthographicCamera) { AnimateTo(camera as OrthographicCamera, newPosition, newLookDirection, newUpDirection, animationTime); } }
/// <summary> /// Moves the camera position. /// </summary> /// <param name="camera">The camera.</param> /// <param name="delta">The delta.</param> public static void MoveCameraPosition(this Camera camera, Vector3D delta) { var pcam = camera as ProjectionCamera; if (pcam == null) { return; } var z = pcam.LookDirection; z.Normalize(); var x = Vector3D.CrossProduct(pcam.LookDirection, pcam.UpDirection); var y = Vector3D.CrossProduct(x, z); y.Normalize(); x = Vector3D.CrossProduct(z, y); // delta *= this.ZoomSensitivity; pcam.Position += (x * delta.X) + (y * delta.Y) + (z * delta.Z); }
/// <summary> /// Finds the pan vector. /// </summary> /// <param name="camera">The camera.</param> /// <param name="dx">The delta x.</param> /// <param name="dy">The delta y.</param> /// <returns> /// The <see cref="Vector3D" /> . /// </returns> public static Vector3D FindPanVector(this Camera camera, double dx, double dy) { var projectionCamera = camera as ProjectionCamera; if (projectionCamera == null) { return(default(Vector3D)); } var axis1 = Vector3D.CrossProduct(projectionCamera.LookDirection, projectionCamera.UpDirection); var axis2 = Vector3D.CrossProduct(axis1, projectionCamera.LookDirection); axis1.Normalize(); axis2.Normalize(); double l = projectionCamera.LookDirection.Length; double f = l * 0.001; var move = (-axis1 * f * dx) + (axis2 * f * dy); // this should be dependent on distance to target? return(move); }
/// <summary> /// Zooms to fit the specified sphere. /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <param name="viewport"> /// The viewport. /// </param> /// <param name="center"> /// The center of the sphere. /// </param> /// <param name="radius"> /// The radius of the sphere. /// </param> /// <param name="animationTime"> /// The animation time. /// </param> public static void ZoomExtents( this Camera camera, Viewport3DX viewport, Point3D center, double radius, double animationTime = 0) { var projectionCamera = camera as ProjectionCamera; if (projectionCamera == null) { return; } // var target = Camera.Position + Camera.LookDirection; if (camera is PerspectiveCamera) { var pcam = camera as PerspectiveCamera; double disth = radius / Math.Tan(0.5 * pcam.FieldOfView * Math.PI / 180); double vfov = pcam.FieldOfView / viewport.ActualWidth * viewport.ActualHeight; double distv = radius / Math.Tan(0.5 * vfov * Math.PI / 180); double dist = Math.Max(disth, distv); var dir = projectionCamera.LookDirection; dir.Normalize(); LookAt(projectionCamera, center, dir * dist, animationTime); } if (camera is OrthographicCamera) { LookAt(projectionCamera, center, projectionCamera.LookDirection, animationTime); double newWidth = radius * 2; if (viewport.ActualWidth > viewport.ActualHeight) { newWidth = radius * 2 * viewport.ActualWidth / viewport.ActualHeight; } AnimateWidth(camera as OrthographicCamera, newWidth, animationTime); } }
/// <summary> /// Zooms the camera to the specified rectangle. /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <param name="viewport"> /// The viewport. /// </param> /// <param name="zoomRectangle"> /// The zoom rectangle. /// </param> public static void ZoomToRectangle(this Camera camera, Viewport3DX viewport, Rect zoomRectangle) { var pcam = camera as ProjectionCamera; if (pcam == null) { return; } var topLeftRay = viewport.UnProjectToRay(zoomRectangle.TopLeft); var topRightRay = viewport.UnProjectToRay(zoomRectangle.TopRight); var centerRay = viewport.UnProjectToRay( new Point( (zoomRectangle.Left + zoomRectangle.Right) * 0.5, (zoomRectangle.Top + zoomRectangle.Bottom) * 0.5)); if (topLeftRay == null || topRightRay == null || centerRay == null) { // could not invert camera matrix return; } var u = topLeftRay.Direction; var v = topRightRay.Direction; var w = centerRay.Direction; u.Normalize(); v.Normalize(); w.Normalize(); var perspectiveCamera = camera as PerspectiveCamera; if (perspectiveCamera != null) { var distance = pcam.LookDirection.Length; // option 1: change distance var newDistance = distance * zoomRectangle.Width / viewport.ActualWidth; var newLookDirection = newDistance * w; var newPosition = perspectiveCamera.Position + ((distance - newDistance) * w); var newTarget = newPosition + newLookDirection; LookAt(pcam, newTarget, newLookDirection, 200); // option 2: change fov // double newFieldOfView = Math.Acos(Vector3D.DotProduct(u, v)); // var newTarget = camera.Position + distance * w; // pcamera.FieldOfView = newFieldOfView * 180 / Math.PI; // LookAt(camera, newTarget, distance * w, 0); } var orthographicCamera = camera as OrthographicCamera; if (orthographicCamera != null) { orthographicCamera.Width *= zoomRectangle.Width / viewport.ActualWidth; var oldTarget = pcam.Position + pcam.LookDirection; var distance = pcam.LookDirection.Length; var newTarget = centerRay.PlaneIntersection(oldTarget, w); if (newTarget != null) { orthographicCamera.LookDirection = w * distance; orthographicCamera.Position = newTarget.Value - orthographicCamera.LookDirection; } } }
/// <summary> /// Gets an information string about the specified camera. /// </summary> /// <param name="camera"> /// The camera. /// </param> /// <returns> /// The get info. /// </returns> public static string GetInfo(this Camera camera) { var matrixCamera = camera as MatrixCamera; var perspectiveCamera = camera as PerspectiveCamera; var projectionCamera = camera as ProjectionCamera; var orthographicCamera = camera as OrthographicCamera; var sb = new StringBuilder(); sb.AppendLine(camera.GetType().Name); if (projectionCamera != null) { sb.AppendLine( string.Format( CultureInfo.InvariantCulture, "LookDirection:\t{0:0.000},{1:0.000},{2:0.000}", projectionCamera.LookDirection.X, projectionCamera.LookDirection.Y, projectionCamera.LookDirection.Z)); sb.AppendLine( string.Format( CultureInfo.InvariantCulture, "UpDirection:\t{0:0.000},{1:0.000},{2:0.000}", projectionCamera.UpDirection.X, projectionCamera.UpDirection.Y, projectionCamera.UpDirection.Z)); sb.AppendLine( string.Format( CultureInfo.InvariantCulture, "Position:\t\t{0:0.000},{1:0.000},{2:0.000}", projectionCamera.Position.X, projectionCamera.Position.Y, projectionCamera.Position.Z)); var target = projectionCamera.Position + projectionCamera.LookDirection; sb.AppendLine( string.Format( CultureInfo.InvariantCulture, "Target:\t\t{0:0.000},{1:0.000},{2:0.000}", target.X, target.Y, target.Z)); sb.AppendLine( string.Format( CultureInfo.InvariantCulture, "NearPlaneDist:\t{0}", projectionCamera.NearPlaneDistance)); sb.AppendLine( string.Format(CultureInfo.InvariantCulture, "FarPlaneDist:\t{0}", projectionCamera.FarPlaneDistance)); } if (perspectiveCamera != null) { sb.AppendLine( string.Format(CultureInfo.InvariantCulture, "FieldOfView:\t{0:0.#}°", perspectiveCamera.FieldOfView)); } if (orthographicCamera != null) { sb.AppendLine( string.Format(CultureInfo.InvariantCulture, "Width:\t{0:0.###}", orthographicCamera.Width)); } if (matrixCamera != null) { sb.AppendLine("ProjectionMatrix:"); sb.AppendLine(matrixCamera.ProjectionMatrix.ToString(CultureInfo.InvariantCulture)); sb.AppendLine("ViewMatrix:"); sb.AppendLine(matrixCamera.ViewMatrix.ToString(CultureInfo.InvariantCulture)); } return(sb.ToString().Trim()); }
/// <summary> /// Obtains the view transform matrix for a camera. (see page 327) /// </summary> /// <param name="camera"> /// Camera to obtain the ViewMatrix for /// </param> /// <returns> /// A Matrix object with the camera view transform matrix, or a Matrix with all zeros if the "camera" is null. /// </returns> public static Matrix3D GetViewMatrix3D(this Camera camera) { return(GetViewMatrix(camera).ToMatrix3D()); }
/// <summary> /// Get the combined view and projection transform /// </summary> /// <param name="camera">The camera.</param> /// <param name="aspectRatio">The aspect ratio.</param> /// <returns>The total view and projection transform.</returns> public static Matrix3D GetViewProjectionMatrix3D(this Camera camera, double aspectRatio) { return(GetProjectionMatrix(camera, aspectRatio).ToMatrix3D()); }