using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Media3D; namespace Demo.StreetView { public class PanoramaViewer : Viewport3D { public double FieldOfView { get { return (double) GetValue(FieldOfViewProperty); } set { SetValue(FieldOfViewProperty, value); } } // Using a DependencyProperty as the backing store for FieldOfView. This enables animation, styling, binding, etc... public static readonly DependencyProperty FieldOfViewProperty = DependencyProperty.Register("FieldOfView", typeof(double), typeof(PanoramaViewer), new PropertyMetadata( (double) 0, new PropertyChangedCallback(OnFieldOfViewChanged))); internal static void OnFieldOfViewChanged(Object sender, DependencyPropertyChangedEventArgs e) { PanoramaViewer Viewer = ((PanoramaViewer) sender); PerspectiveCamera Camera = Viewer.Camera as PerspectiveCamera; Camera.FieldOfView = Viewer.FieldOfView; } public ImageSource PanoramaImage { get { return (ImageSource) GetValue(PanoramaImageProperty); } set { SetValue(PanoramaImageProperty, value); } } // Using a DependencyProperty as the backing store for PanoramaImage. This enables animation, styling, binding, etc... public static readonly DependencyProperty PanoramaImageProperty = DependencyProperty.Register("PanoramaImage", typeof(ImageSource), typeof(PanoramaViewer), new PropertyMetadata( null, new PropertyChangedCallback(OnPanoramaImageChanged))); internal static void OnPanoramaImageChanged(Object sender, DependencyPropertyChangedEventArgs e) { PanoramaViewer Viewer = ((PanoramaViewer) sender); ImageBrush PanoramaBrush = new ImageBrush(Viewer.PanoramaImage); Viewer.PanoramaGeometry.BackMaterial = new DiffuseMaterial(PanoramaBrush); } #region Rotation static private readonly Vector3D AxisX = new Vector3D(1, 0, 0); static private readonly Vector3D AxisY = new Vector3D(0, 1, 0); static private readonly Vector3D AxisZ = new Vector3D(0, 0, 1); public static readonly DependencyProperty RotationXProperty = DependencyProperty.Register("RotationX", typeof(double), typeof(PanoramaViewer), new UIPropertyMetadata(0.0, (d, args) => ((PanoramaViewer) d).UpdateRotation())); public static readonly DependencyProperty RotationYProperty = DependencyProperty.Register("RotationY", typeof(double), typeof(PanoramaViewer), new UIPropertyMetadata(0.0, (d, args) => ((PanoramaViewer) d).UpdateRotation())); public static readonly DependencyProperty RotationZProperty = DependencyProperty.Register("RotationZ", typeof(double), typeof(PanoramaViewer), new UIPropertyMetadata(0.0, (d, args) => ((PanoramaViewer) d).UpdateRotation())); public double RotationX { get { return (double) GetValue(RotationXProperty); } set { SetValue(RotationXProperty, value); } } public double RotationY { get { return (double) GetValue(RotationYProperty); } set { SetValue(RotationYProperty, value); } } public double RotationZ { get { return (double) GetValue(RotationZProperty); } set { SetValue(RotationZProperty, value); } } private void UpdateRotation() { Quaternion qx = new Quaternion(AxisX, RotationX); Quaternion qy = new Quaternion(AxisY, RotationY); Quaternion qz = new Quaternion(AxisZ, RotationZ); PanoramaRotation.Quaternion = qx * qy * qz; } QuaternionRotation3D PanoramaRotation { get; set; } #endregion public PanoramaViewer() { InitializeViewer(); } public ModelVisual3D PanoramaObject { get; set; } public GeometryModel3D PanoramaGeometry { get; set; } public void InitializeViewer() { /////////////////////////////////////////// // Camera Initialize /////////////////////////////////////////// PerspectiveCamera PanoramaCamera = new PerspectiveCamera(); PanoramaCamera.Position = new Point3D(0, -0.0, 0); PanoramaCamera.UpDirection = new Vector3D(0, 1, 0); PanoramaCamera.LookDirection = new Vector3D(0, 0, 1); PanoramaCamera.FieldOfView = 80; this.Camera = PanoramaCamera; FieldOfView = 80; /////////////////////////////////////////// // Light Initialize /////////////////////////////////////////// ModelVisual3D LightModel = new ModelVisual3D(); LightModel.Content = new DirectionalLight(Colors.White, new Vector3D(0, 0, 1)); this.Children.Add(LightModel); /////////////////////////////////////////// // Panorama Object Initialize /////////////////////////////////////////// PanoramaObject = new ModelVisual3D(); PanoramaGeometry = new GeometryModel3D(); PanoramaGeometry.Geometry = CreateGeometry(); PanoramaObject.Content = PanoramaGeometry; RotateTransform3D RotateTransform = new RotateTransform3D(); double x = 1.0; ScaleTransform3D ScaleTransform = new ScaleTransform3D() { ScaleX = x*1, ScaleY = x*1.65, ScaleZ = x*1 }; Transform3DGroup Group = new Transform3DGroup(); PanoramaRotation = new QuaternionRotation3D(); Group.Children.Add(ScaleTransform); Group.Children.Add(RotateTransform); RotateTransform.Rotation = PanoramaRotation; PanoramaObject.Transform = Group; this.Children.Add(PanoramaObject); } private Geometry3D CreateGeometry() { int tDiv = 64; int yDiv = 64; double maxTheta = (360.0 / 180.0) * Math.PI; double minY = -1.0; double maxY = 1.0; double dt = maxTheta / tDiv; double dy = (maxY - minY) / yDiv; MeshGeometry3D mesh = new MeshGeometry3D(); for(int yi = 0; yi <= yDiv; yi++) { double y = minY + yi * dy; for(int ti = 0; ti <= tDiv; ti++) { double t = ti * dt; mesh.Positions.Add(GetPosition(t, y)); mesh.Normals.Add(GetNormal(t, y)); mesh.TextureCoordinates.Add(GetTextureCoordinate(t, y)); } } for(int yi = 0; yi < yDiv; yi++) { for(int ti = 0; ti < tDiv; ti++) { int x0 = ti; int x1 = (ti + 1); int y0 = yi * (tDiv + 1); int y1 = (yi + 1) * (tDiv + 1); mesh.TriangleIndices.Add(x0 + y0); mesh.TriangleIndices.Add(x0 + y1); mesh.TriangleIndices.Add(x1 + y0); mesh.TriangleIndices.Add(x1 + y0); mesh.TriangleIndices.Add(x0 + y1); mesh.TriangleIndices.Add(x1 + y1); } } mesh.Freeze(); return mesh; } internal Point3D GetPosition(double t, double y) { double r = Math.Sqrt(1 - y * y); double x = r * Math.Cos(t); double z = r * Math.Sin(t); return new Point3D(x, y, z); } private Vector3D GetNormal(double t, double y) { return (Vector3D) GetPosition(t, y); } private Point GetTextureCoordinate(double t, double y) { Matrix TYtoUV = new Matrix(); TYtoUV.Scale(1 / (2 * Math.PI), -0.5); Point p = new Point(t, y); p = p * TYtoUV; return p; } } }