Sunday, January 13, 2013

How to create a Matrix3DProjection equivalent to a PlaneProjection

How to create a Matrix3DProjection equivalent to a PlaneProjection

I have been trying this for a while and I am pretty close most of the time, but I must be doing something wrong since the scale of some elements is wrong for certain element dimensions.

I looked at these articles to get some insight, but it seems like I am still doing something wrong in that Sync() method. The 2 groups of the 3 red and yellow rectangles should render in the same positions, but they don't. Also - since the PlaneProjection.ProjectionMatrix isn't set immediately - I can't use it when the app starts (drag a slider back and forth to recalculate the matrices).

http://social.msdn.microsoft.com/Forums/en-US/silverlightbugs/thread/8060cdd4-5528-4768-b004-884480c6456c/

http://blogs.msdn.com/b/jaimer/archive/2009/06/03/silverlight3-planeprojection-primer.aspx

My XAML

<UserControl     x:Class="App88.MyUserControl"     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"     xmlns:local="using:App88"     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"     mc:Ignorable="d"     d:DesignHeight="300"     d:DesignWidth="400">      <Grid>         <Grid             Width="300"             Height="300"             Background="#80FF0000">             <Grid.Projection>                 <PlaneProjection                     x:Name="P1"                     LocalOffsetZ="-100"                     RotationX="90" />             </Grid.Projection>         </Grid>         <Grid             Width="300"             Height="300"             Background="#80FF0000">             <Grid.Projection>                 <PlaneProjection                     x:Name="P2"                     LocalOffsetZ="-100"                     RotationX="-90" />             </Grid.Projection>         </Grid>         <Grid             Width="300"             Height="200"             Background="#80FF0000">             <Grid.Projection>                 <PlaneProjection                     x:Name="P3"                     LocalOffsetZ="-150"                     RotationY="0" />             </Grid.Projection>         </Grid>          <Grid             x:Name="R1"             Width="300"             Height="300"             Background="#80FFFF00">             <Grid.Projection>                 <Matrix3DProjection                     x:Name="M1" />             </Grid.Projection>         </Grid>         <Grid             x:Name="R2"             Height="300"             Width="300"             Background="#80FFFF00">             <Grid.Projection>                 <Matrix3DProjection                     x:Name="M2" />             </Grid.Projection>         </Grid>         <Grid             x:Name="R3"             Grid.Row="2"             Width="300"             Height="200"             Background="#80FFFF00">             <Grid.Projection>                 <Matrix3DProjection                     x:Name="M3" />             </Grid.Projection>         </Grid>            <Slider             x:Name="slider"             ValueChanged="Slider_OnValueChanged"             Minimum="0"             Maximum="90"             SmallChange="0.1"             LargeChange="1"></Slider>         <Slider             x:Name="slider2"             ValueChanged="Slider_OnValueChanged"             Minimum="0"             Maximum="90"             SmallChange="0.1"             LargeChange="1"></Slider>     </Grid> </UserControl> 

Code behind

using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Media3D;  namespace App88 {     public sealed partial class MyUserControl : UserControl     {         public MyUserControl()         {             this.InitializeComponent();         }          private void Slider_OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)         {             Sync(R1, P1, M1);             Sync(R2, P2, M2);             Sync(R3, P3, M3);         }          private void Sync(FrameworkElement element, PlaneProjection pp, Matrix3DProjection mp)         {             double fovY = 57 * Math.PI / 180;             //double translationZ = -r.ActualHeight / Math.Tan(fovY / 2.0);              Matrix3D perspective = PerspectiveTransformFovRH(                 fovY / 5,                 element.ActualWidth / element.ActualHeight,   // aspect ratio                 1.0,                                                // near plane                 1000.0);                                            // far plane             Matrix3D viewport =                 ViewportTransform(                     element.ActualWidth,                     element.ActualHeight);              Matrix3D m = Matrix3D.Identity.Translate(                     -element.ActualWidth / 2.0,                     -element.ActualHeight / 2.0,                     0);             m = m.RotateAboutX(slider2.Value * Math.PI / 180);             m = m.RotateAboutY(slider.Value * Math.PI / 180);             m = m * pp.ProjectionMatrix;              m = m.Scale(1, -1, 1);             // translate away from the camera             m = m.Translate(                     0,                     0,                     -999);             m = m * perspective;             m = m * viewport;              mp.ProjectionMatrix = m;         }          private static Matrix3D PerspectiveTransformFovRH(double fieldOfViewY, double aspectRatio, double zNearPlane, double zFarPlane)         {             double height = 1.0 / Math.Tan(fieldOfViewY * 0.5);             double width = height / aspectRatio;             double d = zNearPlane - zFarPlane;              Matrix3D m = new Matrix3D();             m.M11 = width; m.M12 = 0; m.M13 = 0; m.M14 = 0;             m.M21 = 0; m.M22 = height; m.M23 = 0; m.M24 = 0;             m.M31 = 0; m.M32 = 0; m.M33 = zFarPlane / d; m.M34 = -1;             m.OffsetX = 0; m.OffsetY = 0; m.OffsetZ = zNearPlane * zFarPlane / d; m.M44 = 0;              return m;         }          private static Matrix3D ViewportTransform(double width, double height)         {             Matrix3D m = new Matrix3D();              m.M11 = width / 2.0; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;             m.M21 = 0.0; m.M22 = -height / 2.0; m.M23 = 0.0; m.M24 = 0.0;             m.M31 = 0.0; m.M32 = 0.0; m.M33 = 1.0; m.M34 = 0.0;             m.OffsetX = width / 2.0; m.OffsetY = height / 2.0; m.OffsetZ = 0.0; m.M44 = 1.0;              return m;         }     }      public static class Matrix3DExtensions     {         public static Matrix3D Translate(this Matrix3D source, double x, double y, double z)         {             return source * new Matrix3D(1, 0, 0, 0,                               0, 1, 0, 0,                               0, 0, 1, 0,                               x, y, z, 1);         }          public static Matrix3D Scale(this Matrix3D source, double x, double y, double z)         {             return source * new Matrix3D(                 x, 0, 0, 0,                 0, y, 0, 0,                 0, 0, z, 0,                 0, 0, 0, 1);         }          public static Matrix3D RotateAboutX(this Matrix3D source, double theta)         {             double s = Math.Sin(theta);             double c = Math.Cos(theta);              return source * new Matrix3D(                 1, 0, 0, 0,                 0, c, s, 0,                 0, -s, c, 0,                 0, 0, 0, 1);         }          public static Matrix3D RotateAboutY(this Matrix3D source, double theta)         {             double s = Math.Sin(theta);             double c = Math.Cos(theta);              return source * new Matrix3D(                 c, 0, -s, 0,                 0, 1, 0, 0,                 s, 0, c, 0,                 0, 0, 0, 1);         }           public static Matrix3D RotateAboutZ(this Matrix3D source, double theta)         {             double s = Math.Sin(theta);             double c = Math.Cos(theta);              return source * new Matrix3D(                  c, s, 0, 0,                 -s, c, 0, 0,                  0, 0, 1, 0,                  0, 0, 0, 1);         }     } } 

Answers & Comments...




No comments:

Post a Comment

Send us your comment related to the topic mentioned on the blog