OrthographicCamera

<OrthographicCamera x_Key="Camera"
      Position="0, 0, 4"
      LookDirection="0, 0, -4"
      UpDirection="0, 1, 0"/>

Orthographic

PerspectiveCamera

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

Perspective

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.