cool IT Team-Blog

Darstellung von PerspectiveCamera und OrthographicCamera als MatrixCamera in WPF

OrthographicCamera

<OrthographicCamera x:Key="Camera"
 Position="0, 0, 4"
 LookDirection="0, 0, -4"
 UpDirection="0, 1, 0"/>


PerspectiveCamera

<PerspectiveCamera x:Key="Camera"
 Position="0, 0, 4"
 LookDirection="0, 0, -4"
 UpDirection="0, 1, 0"
 FieldOfView="30"/>

PerspectiveCamera

MatrixCamera

Eine MatrixCamera besteht aus 2 Matrizen, die beim Zeichnen miteinander multipliziert werden: der ViewMatrix und der ProjectionMatrix.

            <Viewport3D.Camera>
              <MatrixCamera x:Name="mainCamera">
                <MatrixCamera.ViewMatrix>
                  <Matrix3D
                M11="0.89" M12="0.98"  M13="-0.44" M14="0"
                M21="0"    M22="0.98"  M23="0.22"  M24="0"
                M31="0.45" M32="-0.20" M33="0.87"  M34="0"
                OffsetX="0" OffsetY="-0.98" OffsetZ="-4.8" M44="1" />
                </MatrixCamera.ViewMatrix>
                <MatrixCamera.ProjectionMatrix>
                  <Matrix3D
                M11="0.89" M12="0.98"  M13="-0.44" M14="0"
                M21="0"    M22="0.98"  M23="0.22"  M24="0"
                M31="0.45" M32="-0.20" M33="0.87"  M34="0"
                OffsetX="0" OffsetY="-0.98" OffsetZ="-4.8" M44="1" />
                </MatrixCamera.ProjectionMatrix>
              </MatrixCamera>
            </Viewport3D.Camera>

Der Code behind

Die im XAML eingesetzten Werte sind beliebig, denn wir verwenden Position, LookDirection, UpDirection und FieldView, sowie NearPlane- und FarPlaneDistance für die Berechnung der eigentlichen Kamerakoordinaten.

Wir halten also im CodeBehind Properties für alle gängigen Kamereingenschaften:
   
    ' Kameraeinstellungen
    Private _fieldOfView As Integer = 40
    Private _upDirection As Vector3D = New Vector3D(0, 1, 0)
    Private _lookDirection As Vector3D = New Vector3D(0, 0, -1)
    Private _position As Point3D = New Point3D(0, 0, 0)
    Private _nearPlaneDistance As Integer = 200
    Private _farPlaneDistance As Integer = 4000


Die View- und Projectionmatrix werden nun bei jeder Änderung eines dieser Werte neu berechnet. Dazu dienen folgende Funktionen:

    Private Sub PerformCameraPositioning()
      CalculateViewMatrix()
      CalculateProjectionMatrix()
   
End Sub

    Private Sub CalculateViewMatrix()
      Dim zAxis As Vector3D, xAxis As Vector3D, yAxis As Vector3D
      GetCameraAxis(xAxis, yAxis, zAxis)

      Dim pos As Vector3D = New Vector3D(_position.X, _position.Y, _position.Z)
      Dim offsetX As Double = -Vector3D.DotProduct(xAxis, pos)
      Dim offsetY As Double = -Vector3D.DotProduct(yAxis, pos)
      Dim offsetZ As Double = -Vector3D.DotProduct(zAxis, pos)

      If (tbOrthographic.IsChecked) Then
        Dim scale As Double = Math.Abs(offsetZ / 2) / mainViewport3D.ActualWidth
        mainCamera.ViewMatrix = New Matrix3D(xAxis.X, yAxis.X, zAxis.X, 0,
                           xAxis.Y, yAxis.Y, zAxis.Y, 0,
                           xAxis.Z, yAxis.Z, zAxis.Z, 0,
                           offsetX, offsetY, offsetZ, scale)
      Else
        mainCamera.ViewMatrix = New Matrix3D(xAxis.X, yAxis.X, zAxis.X, 0,
                           xAxis.Y, yAxis.Y, zAxis.Y, 0,
                           xAxis.Z, yAxis.Z, zAxis.Z, 0,
                           offsetX, offsetY, offsetZ, 1)
      End If
   
End Sub

    Private Sub CalculateProjectionMatrix()
      Dim aspectRatio As Double = mainViewport3D.ActualWidth / mainViewport3D.ActualHeight

      If (tbOrthographic.IsChecked) Then
        Dim xScale As Double = 2 / mainViewport3D.ActualWidth
        Dim yScale As Double = aspectRatio * xScale
        Dim zScale As Double = DirectCast(IIf((_nearPlaneDistance - _farPlaneDistance) = 0, 1, 1 / (_nearPlaneDistance - _farPlaneDistance)), Double)

        Dim zOffset As Double = _nearPlaneDistance * zScale

        mainCamera.ProjectionMatrix = New Matrix3D(xScale, 0, 0, 0,
                             0, yScale, 0, 0,
                             0, 0, zScale, 0,
                             0, 0, zOffset, 1)
      Else
        Dim xScale As Double = 1 / Math.Tan(Math.PI * _fieldOfView / 360)
        Dim yScale As Double = aspectRatio * xScale
        Dim zScale As Double = DirectCast(IIf(_farPlaneDistance = Double.PositiveInfinity, -1, _farPlaneDistance / (_nearPlaneDistance - _farPlaneDistance)), Double)

        Dim zOffset As Double = _nearPlaneDistance * zScale

        mainCamera.ProjectionMatrix = New Matrix3D(xScale, 0, 0, 0,
                             0, yScale, 0, 0,
                             0, 0, zScale, -1,
                             0, 0, zOffset, 0)
      End If
   
End Sub

   Private Sub
GetCameraAxis(ByRef xAxis As Vector3D, ByRef yAxis As Vector3D, ByRef zAxis As Vector3D)
      zAxis = -_lookDirection
      xAxis = Vector3D.CrossProduct(_upDirection, zAxis)
      yAxis = Vector3D.CrossProduct(zAxis, xAxis)

      xAxis.Normalize() : yAxis.Normalize() ' zAxis is already normalized
    End Sub


Mit diesen Code-Stückchen lässt sich nun eine MatrixCamera genauso natürlich bewegen wie eine Orthographic- oder PerspectiveCamera.

Ist doch cool. oder?

LG,
Sabine.

Verfasst: 13.02.2011 15:51:56 von Sabine Stiller
Tags: MatrixCamera, OrthographicCamera, PerspectiveCamera, ProjectionMatrix, ViewMatrix, WPF3D

1


Kommentare
Für diesen Blogbeitrag liegen zurzeit keine Kommentare vor.
Einen Kommentar schreiben



 Security code