none
Matrix3D != ProjectionMatrix SL4

    Question

  • After a projection transform the resulting ProjectionMatrix does not equal a valid Matrix3D

    Specifically the X properties are all 0.0.

    Here is xaml to create two planes one with a projection.

        <Canvas x:Name="LayoutRoot" Background="White" Width="800" Height="400" MouseMove="LayoutRoot_MouseMove">
            <Canvas Background="Yellow" Width="400" Height="400" x:Name="testCanvas">
                <Canvas.Projection>
                    <PlaneProjection x:Name="GProj" RotationX="-45" CenterOfRotationY="1.0" />
                </Canvas.Projection>
            </Canvas>
            <Canvas Background="Red" Width="400" Height="400" x:Name="testCanvas2" Canvas.Left="400">
            </Canvas>
            <StackPanel Orientation="Horizontal">
                <Button Content="calc" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click" />
            </StackPanel>
        </Canvas>


    Once the button is clicked the code copies the properties and sets the resulting matix to the second plane.

           private void Button_Click(object sender, RoutedEventArgs e)
            {
                
                Matrix3D m3dp = GProj.ProjectionMatrix;
                Matrix3DProjection matrix3DProjection = new Matrix3DProjection();
                Matrix3D matrix3D = new Matrix3D();
                matrix3D.M11 = m3dp.M11;
                matrix3D.M12 = m3dp.M12;
                matrix3D.M13 = m3dp.M13;
                matrix3D.M14 = m3dp.M14;
    
                matrix3D.M21 = m3dp.M21;
                matrix3D.M22 = m3dp.M22;
                matrix3D.M23 = m3dp.M23;
                matrix3D.M24 = m3dp.M24;
    
                matrix3D.M31 = m3dp.M31;
                matrix3D.M32 = m3dp.M32;
                matrix3D.M33 = m3dp.M33;
                matrix3D.M34 = m3dp.M34;
    
                matrix3D.OffsetX = m3dp.OffsetX;
                matrix3D.OffsetY = m3dp.OffsetY;
                matrix3D.OffsetZ = m3dp.OffsetZ;
                matrix3D.M44 = m3dp.M44;
    
                matrix3DProjection.ProjectionMatrix = matrix3D;
    
                testCanvas2.Projection = matrix3DProjection;
    
            }


    Discovered when trying to perform matrix multiplications where the source matrix was the above projection.

    M11, M21, M31, OffsetX is always 0.0

    Monday, March 07, 2011 8:58 AM

Answers

  • After a projection transform the resulting ProjectionMatrix does not equal a valid Matrix3D

    Hi,

    You are running into a wrong direction. The ProjectionMatrix is for projection only, not the matrix used to see the final result. We need to use multiple Matrix to build the result like a PlaneProjection. Actually for a given 3D objects if you view (camera viewpoint) it on different point you’ll see different results. Below is a sample of using ProjectionMatrix. Please try to adjust the final matrix to revert to whatever you need.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    using System.Windows.Threading;
    
    namespace SilverlightApplication17
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(MainPage_Loaded);
            }
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                DispatcherTimer dt = new DispatcherTimer();
                dt.Interval = TimeSpan.FromMilliseconds(50);
                dt.Tick += new EventHandler(dt_Tick);
                dt.Start();
            }
            double i = 0;
    
            void dt_Tick(object sender, EventArgs e)
            {
                i++;
                if (i >= 10000) i = 0;
                GProj.RotationX = i;
                Sync();
            }
            private Matrix3D TranslationTransform(double tx, double ty, double tz)
           {
                Matrix3D m = new Matrix3D();
    
                m.M11 = 1.0; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
                m.M21 = 0.0; m.M22 = 1.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 = tx; m.OffsetY = ty; m.OffsetZ = tz; m.M44 = 1.0;
    
                return m;
            }
    
            private Matrix3D CreateScaleTransform(double sx, double sy, double sz)
            {
                Matrix3D m = new Matrix3D();
    
                m.M11 = sx; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
                m.M21 = 0.0; m.M22 = sy; m.M23 = 0.0; m.M24 = 0.0;
                m.M31 = 0.0; m.M32 = 0.0; m.M33 = sz; m.M34 = 0.0;
                m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
    
                return m;
            }
    
            private Matrix3D RotateYTransform(double theta)
            {
                double sin = Math.Sin(theta);
                double cos = Math.Cos(theta);
    
                Matrix3D m = new Matrix3D();
    
                m.M11 = cos; m.M12 = 0.0; m.M13 = -sin; m.M14 = 0.0;
                m.M21 = 0.0; m.M22 = 1.0; m.M23 = 0.0; m.M24 = 0.0;
                m.M31 = sin; m.M32 = 0.0; m.M33 = cos; m.M34 = 0.0;
                m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
    
                return m;
            }
    
            private Matrix3D RotateZTransform(double theta)
            {
                double cos = Math.Cos(theta);
                double sin = Math.Sin(theta);
    
                Matrix3D m = new Matrix3D();
                m.M11 = cos; m.M12 = sin; m.M13 = 0.0; m.M14 = 0.0;
                m.M21 = -sin; m.M22 = cos; 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 = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
                return m;
            }
    
            private Matrix3D PerspectiveTransformFovRH(double fieldOfViewY, double aspectRatio, double zNearPlane, double zFarPlane)
            {
                double height = 1.0 / Math.Tan(fieldOfViewY / 2.0);
                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 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;
            }
    
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Sync();
             
    
            }
            private void Sync()
            {
                Matrix3D m3dp = GProj.ProjectionMatrix;
                Matrix3DProjection matrix3DProjection = new Matrix3DProjection();
                Matrix3D matrix3D = new Matrix3D();
                matrix3D.M11 = m3dp.M11;
                matrix3D.M12 = m3dp.M12;
                matrix3D.M13 = m3dp.M13;
                matrix3D.M14 = m3dp.M14;
    
                matrix3D.M21 = m3dp.M21;
                matrix3D.M22 = m3dp.M22;
                matrix3D.M23 = m3dp.M23;
                matrix3D.M24 = m3dp.M24;
    
                matrix3D.M31 = m3dp.M31;
                matrix3D.M32 = m3dp.M32;
                matrix3D.M33 = m3dp.M33;
                matrix3D.M34 = m3dp.M34;
    
                matrix3D.OffsetX = m3dp.OffsetX;
                matrix3D.OffsetY = m3dp.OffsetY;
                matrix3D.OffsetZ = m3dp.OffsetZ;
                matrix3D.M44 = m3dp.M44;
                // far plane
    
                matrix3DProjection.ProjectionMatrix = matrix3D; //* viewport;    
    
                double fovY = Math.PI / 2.0;
                double translationZ = -testCanvas.ActualHeight / Math.Tan(fovY / 2.0);
    
                Matrix3D centerImageAtOrigin = TranslationTransform(
                         -testCanvas.ActualWidth / 2.0,
                         -testCanvas.ActualHeight / 2.0, 0);
    
                Matrix3D rotateAboutX = matrix3D;
                Matrix3D translateAwayFromCamera = TranslationTransform(0, 0, translationZ);
                Matrix3D perspective = PerspectiveTransformFovRH(fovY,
                        LayoutRoot.ActualWidth / LayoutRoot.ActualHeight,   // aspect ratio
                        1.0,                                                // near plane
                        1000.0);                                            // far plane
                Matrix3D viewport = ViewportTransform(LayoutRoot.ActualWidth, LayoutRoot.ActualHeight);
    
                Matrix3D m = centerImageAtOrigin;
                m = m * rotateAboutX;
                m = m * translateAwayFromCamera;
                m = m * perspective;
                m = m * viewport;
    
                testCanvas2.Projection = new Matrix3DProjection()
                {
                    ProjectionMatrix = m
                };
    
            }
        }
    }
    
    <UserControl x:Class="SilverlightApplication17.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        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">
    
        <Canvas x:Name="LayoutRoot" Background="White" Width="800" Height="400" >
            <Canvas Background="Red" Width="400" Height="400" x:Name="testCanvas2" Canvas.Left="400">
            </Canvas>
            <Canvas Background="Yellow" Width="400" Height="400" x:Name="testCanvas">
                <Canvas.Projection>
                    <PlaneProjection x:Name="GProj" RotationX="-85" CenterOfRotationY="1.0" />
                </Canvas.Projection>
            </Canvas>
        
            <StackPanel Orientation="Horizontal">
                <Button Content="calc" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click" />
            </StackPanel>
        </Canvas>
    </UserControl>
    


     

    Thursday, March 10, 2011 3:26 AM

All replies

  • After a projection transform the resulting ProjectionMatrix does not equal a valid Matrix3D

    Hi,

    You are running into a wrong direction. The ProjectionMatrix is for projection only, not the matrix used to see the final result. We need to use multiple Matrix to build the result like a PlaneProjection. Actually for a given 3D objects if you view (camera viewpoint) it on different point you’ll see different results. Below is a sample of using ProjectionMatrix. Please try to adjust the final matrix to revert to whatever you need.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Media.Media3D;
    using System.Windows.Threading;
    
    namespace SilverlightApplication17
    {
        public partial class MainPage : UserControl
        {
            public MainPage()
            {
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(MainPage_Loaded);
            }
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                DispatcherTimer dt = new DispatcherTimer();
                dt.Interval = TimeSpan.FromMilliseconds(50);
                dt.Tick += new EventHandler(dt_Tick);
                dt.Start();
            }
            double i = 0;
    
            void dt_Tick(object sender, EventArgs e)
            {
                i++;
                if (i >= 10000) i = 0;
                GProj.RotationX = i;
                Sync();
            }
            private Matrix3D TranslationTransform(double tx, double ty, double tz)
           {
                Matrix3D m = new Matrix3D();
    
                m.M11 = 1.0; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
                m.M21 = 0.0; m.M22 = 1.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 = tx; m.OffsetY = ty; m.OffsetZ = tz; m.M44 = 1.0;
    
                return m;
            }
    
            private Matrix3D CreateScaleTransform(double sx, double sy, double sz)
            {
                Matrix3D m = new Matrix3D();
    
                m.M11 = sx; m.M12 = 0.0; m.M13 = 0.0; m.M14 = 0.0;
                m.M21 = 0.0; m.M22 = sy; m.M23 = 0.0; m.M24 = 0.0;
                m.M31 = 0.0; m.M32 = 0.0; m.M33 = sz; m.M34 = 0.0;
                m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
    
                return m;
            }
    
            private Matrix3D RotateYTransform(double theta)
            {
                double sin = Math.Sin(theta);
                double cos = Math.Cos(theta);
    
                Matrix3D m = new Matrix3D();
    
                m.M11 = cos; m.M12 = 0.0; m.M13 = -sin; m.M14 = 0.0;
                m.M21 = 0.0; m.M22 = 1.0; m.M23 = 0.0; m.M24 = 0.0;
                m.M31 = sin; m.M32 = 0.0; m.M33 = cos; m.M34 = 0.0;
                m.OffsetX = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
    
                return m;
            }
    
            private Matrix3D RotateZTransform(double theta)
            {
                double cos = Math.Cos(theta);
                double sin = Math.Sin(theta);
    
                Matrix3D m = new Matrix3D();
                m.M11 = cos; m.M12 = sin; m.M13 = 0.0; m.M14 = 0.0;
                m.M21 = -sin; m.M22 = cos; 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 = 0.0; m.OffsetY = 0.0; m.OffsetZ = 0.0; m.M44 = 1.0;
                return m;
            }
    
            private Matrix3D PerspectiveTransformFovRH(double fieldOfViewY, double aspectRatio, double zNearPlane, double zFarPlane)
            {
                double height = 1.0 / Math.Tan(fieldOfViewY / 2.0);
                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 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;
            }
    
    
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Sync();
             
    
            }
            private void Sync()
            {
                Matrix3D m3dp = GProj.ProjectionMatrix;
                Matrix3DProjection matrix3DProjection = new Matrix3DProjection();
                Matrix3D matrix3D = new Matrix3D();
                matrix3D.M11 = m3dp.M11;
                matrix3D.M12 = m3dp.M12;
                matrix3D.M13 = m3dp.M13;
                matrix3D.M14 = m3dp.M14;
    
                matrix3D.M21 = m3dp.M21;
                matrix3D.M22 = m3dp.M22;
                matrix3D.M23 = m3dp.M23;
                matrix3D.M24 = m3dp.M24;
    
                matrix3D.M31 = m3dp.M31;
                matrix3D.M32 = m3dp.M32;
                matrix3D.M33 = m3dp.M33;
                matrix3D.M34 = m3dp.M34;
    
                matrix3D.OffsetX = m3dp.OffsetX;
                matrix3D.OffsetY = m3dp.OffsetY;
                matrix3D.OffsetZ = m3dp.OffsetZ;
                matrix3D.M44 = m3dp.M44;
                // far plane
    
                matrix3DProjection.ProjectionMatrix = matrix3D; //* viewport;    
    
                double fovY = Math.PI / 2.0;
                double translationZ = -testCanvas.ActualHeight / Math.Tan(fovY / 2.0);
    
                Matrix3D centerImageAtOrigin = TranslationTransform(
                         -testCanvas.ActualWidth / 2.0,
                         -testCanvas.ActualHeight / 2.0, 0);
    
                Matrix3D rotateAboutX = matrix3D;
                Matrix3D translateAwayFromCamera = TranslationTransform(0, 0, translationZ);
                Matrix3D perspective = PerspectiveTransformFovRH(fovY,
                        LayoutRoot.ActualWidth / LayoutRoot.ActualHeight,   // aspect ratio
                        1.0,                                                // near plane
                        1000.0);                                            // far plane
                Matrix3D viewport = ViewportTransform(LayoutRoot.ActualWidth, LayoutRoot.ActualHeight);
    
                Matrix3D m = centerImageAtOrigin;
                m = m * rotateAboutX;
                m = m * translateAwayFromCamera;
                m = m * perspective;
                m = m * viewport;
    
                testCanvas2.Projection = new Matrix3DProjection()
                {
                    ProjectionMatrix = m
                };
    
            }
        }
    }
    
    <UserControl x:Class="SilverlightApplication17.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        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">
    
        <Canvas x:Name="LayoutRoot" Background="White" Width="800" Height="400" >
            <Canvas Background="Red" Width="400" Height="400" x:Name="testCanvas2" Canvas.Left="400">
            </Canvas>
            <Canvas Background="Yellow" Width="400" Height="400" x:Name="testCanvas">
                <Canvas.Projection>
                    <PlaneProjection x:Name="GProj" RotationX="-85" CenterOfRotationY="1.0" />
                </Canvas.Projection>
            </Canvas>
        
            <StackPanel Orientation="Horizontal">
                <Button Content="calc" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click" />
            </StackPanel>
        </Canvas>
    </UserControl>
    


     

    Thursday, March 10, 2011 3:26 AM
  • thanks for that, I will digest all that scary math.

    The example works great.

    Friday, March 11, 2011 9:32 AM