using System; using System.Windows.Media.Media3D; namespace HelixToolkit { public static class StereoHelper { /// /// Find the focal length given the field of view and the format /// http://en.wikipedia.org/wiki/Angle_of_view /// /// field of view (degrees) /// e.g. 36mm /// The focal length in the same unit as the format public static double FindFocalLength(double fov, double format) { return format / 2 / Math.Tan(fov / 2 * Math.PI / 180); } /// /// Calculate the stereo base using the full Bercovitz formula /// /// Largest distance from the camera lens /// Nearest distance from the camera lens /// Width of screen /// depth ratio 1/30 /// Horizontal field of view /// The stereo base public static double CalculateStereoBase(double L, double N, double screenWidth, double depthRatio, double hfov) { double formatHoriz = screenWidth; double F = FindFocalLength(hfov, formatHoriz); double P = depthRatio * formatHoriz; return CalculateStereoBase(P, L, N, F); } /// /// Calculate the stereo base using the full Bercovitz formula /// B = P(LN/(L-N)) (1/F - (L+N)/2LN) /// http://nzphoto.tripod.com/stereo/3dtake/fbercowitz.htm /// /// Parallax aimed for, in mm on the film /// Largest distance from the camera lens, mm /// Nearest distance from the camera lens, mm /// Focal length of the lens, mm /// The stereo base public static double CalculateStereoBase(double P, double L, double N, double F) { return P * (L * N / (L - N)) * (1 / F - (L + N) / (2 * L * N)); } /// /// Updates the left and right camera based on a center camera. /// /// Center camera (input) /// Left camera (is updated) /// Right camera (is updated) /// Stereo base /// true for cross-viewingm false for parallel-viewing /// use the same UpDirection for both cameras /// use the same LookDirection for both cameras public static void UpdateStereoCameras(PerspectiveCamera centerCamera, PerspectiveCamera leftCamera, PerspectiveCamera rightCamera, double stereoBase, bool crossViewing, bool sameUpDirection, bool sameDirection) { if (centerCamera == null || leftCamera == null || rightCamera == null) return; double sb = stereoBase; if (crossViewing) sb *= -1; var lookAt = centerCamera.Position + centerCamera.LookDirection; var right = Vector3D.CrossProduct(centerCamera.LookDirection, centerCamera.UpDirection); right.Normalize(); leftCamera.Position = centerCamera.Position - right * sb / 2; if (sameDirection) leftCamera.LookDirection = centerCamera.LookDirection; else leftCamera.LookDirection = lookAt - leftCamera.Position; rightCamera.Position = centerCamera.Position + right * sb / 2; if (sameDirection) rightCamera.LookDirection = centerCamera.LookDirection; else rightCamera.LookDirection = lookAt - rightCamera.Position; // TODO: not sure what is best here? if (sameUpDirection) { leftCamera.UpDirection = centerCamera.UpDirection; rightCamera.UpDirection = centerCamera.UpDirection; } else { leftCamera.UpDirection = Vector3D.CrossProduct(right, leftCamera.LookDirection); rightCamera.UpDirection = Vector3D.CrossProduct(right, rightCamera.LookDirection); } leftCamera.FieldOfView = centerCamera.FieldOfView; leftCamera.NearPlaneDistance = centerCamera.NearPlaneDistance; leftCamera.FarPlaneDistance = centerCamera.FarPlaneDistance; rightCamera.FieldOfView = centerCamera.FieldOfView; rightCamera.NearPlaneDistance = centerCamera.NearPlaneDistance; rightCamera.FarPlaneDistance = centerCamera.FarPlaneDistance; } /// /// Create a clone of a Visual3D /// /// a Visual3D /// the clone public static Visual3D CreateClone(Visual3D v) { if (v is ModelUIElement3D) { var m = v as ModelUIElement3D; if (m.Model!= null) { /*if (m.Model.CanFreeze) m.Model.Freeze(); if (m.Model.IsFrozen)*/ { var clonedModel = m.Model.Clone(); var clonedElement = new ModelUIElement3D(); clonedElement.Transform = m.Transform; clonedElement.Model = clonedModel; return clonedElement; } } } if (v is ModelVisual3D) { var m = v as ModelVisual3D; var clone = new ModelVisual3D(); clone.Transform = m.Transform; if (m.Content != null && m.Content.CanFreeze) { m.Content.Freeze(); var clonedModel = m.Content.Clone(); clone.Content = clonedModel; } if (m.Children.Count>0) { foreach (var child in m.Children) { var clonedChild = CreateClone(child); clone.Children.Add(clonedChild); } } return clone; } return null; } } }