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"/>
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.