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://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); } } }
No comments:
Post a Comment
Send us your comment related to the topic mentioned on the blog