In einem Weltraumspiel beispielsweise lassen sich so die Hintergrundnebel in Szene setzen. Zu diesem Zweck rendert man ein mit einer entsprechenden Nebel-Textur überzogenes Vertex-Quad, welches zuvor so ausgerichtet wurde, dass Kamera und Spieler senkrecht auf seine Oberfläche blicken. Die gleiche Technik bietet sich bei der Himmelsdarstellung an, beim Rendern von Hintergrundwolken, von Blitzen, der Sonne oder anderen Himmelphänomenen.
Die Transformation der Billboard-Vertices im Rahmen des Renderprozesses erfolgt heutzutage standardmäßig im Vertex Shader. Unsere Aufgabe besteht jetzt darin, die Transformationsmatrizen für die korrekte Darstellung zu finden.
inline void Positioning_2DObject(
D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
D3DXVECTOR3* pCameraSpacePosition,
float &angleHorizontal, float &angleVertical,
float &scaleX, float &scaleY)
{
D3DXMATRIXA16 tempMatrix1, tempMatrix2, RotationTranslationMatrix,
ScaleMatrix;
// Skalierungsmatrix berechnen:
D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);
D3DXVECTOR3 temp1Vektor3;
// horizontale Drehung des Billboards:
D3DXMatrixRotationY(&tempMatrix1, angleHorizontal);
// horizontale Drehachse für die vertikale Drehung berechnen:
Multiply3DVectorWithRotationMatrix(&temp1Vektor3,
&g_CameraHorizontalOriginalNeg,
&tempMatrix1);
// vertikale Drehung des Billboards um die horizontale Drehachse:
D3DXMatrixRotationAxis(&tempMatrix2, &temp1Vektor3, angleVertical);
// Matrix für die komplette Drehung (erst horizontal, dann vertikal)
// berechnen:
RotationTranslationMatrix = tempMatrix1*tempMatrix2;
// Positionierung des Billboards im Kameraraum:
RotationTranslationMatrix._41 = pCameraSpacePosition->x;
RotationTranslationMatrix._42 = pCameraSpacePosition->y;
RotationTranslationMatrix._43 = pCameraSpacePosition->z;
// Gesamttransformationsmatrix berechnen:
*pCameraSpaceTransformationMatrix =
ScaleMatrix*RotationTranslationMatrix;
}
D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
D3DXVECTOR3* pCameraSpacePosition,
float &angleHorizontal, float &angleVertical,
float &scaleX, float &scaleY)
{
D3DXMATRIXA16 tempMatrix1, tempMatrix2, RotationTranslationMatrix,
ScaleMatrix;
// Skalierungsmatrix berechnen:
D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);
D3DXVECTOR3 temp1Vektor3;
// horizontale Drehung des Billboards:
D3DXMatrixRotationY(&tempMatrix1, angleHorizontal);
// horizontale Drehachse für die vertikale Drehung berechnen:
Multiply3DVectorWithRotationMatrix(&temp1Vektor3,
&g_CameraHorizontalOriginalNeg,
&tempMatrix1);
// vertikale Drehung des Billboards um die horizontale Drehachse:
D3DXMatrixRotationAxis(&tempMatrix2, &temp1Vektor3, angleVertical);
// Matrix für die komplette Drehung (erst horizontal, dann vertikal)
// berechnen:
RotationTranslationMatrix = tempMatrix1*tempMatrix2;
// Positionierung des Billboards im Kameraraum:
RotationTranslationMatrix._41 = pCameraSpacePosition->x;
RotationTranslationMatrix._42 = pCameraSpacePosition->y;
RotationTranslationMatrix._43 = pCameraSpacePosition->z;
// Gesamttransformationsmatrix berechnen:
*pCameraSpaceTransformationMatrix =
ScaleMatrix*RotationTranslationMatrix;
}
Unter Umständen sind anstelle der Billboard-Polarwinkel nur die zugehörigen Sinus- und Kosinuswerte bekannt. Machen sie nun nicht den Fehler, die Polarwinkel zu berechnen und diese dann als Parameter der obigen Funktion zu übergeben. Verwenden sie stattdessen eine zweite Funktion, der sie die Sinus- und Kosinuswerte direkt übergeben können.
Bedenken sie in diesem Zusammenhang, dass für die Berechnung der Rotationsmatrizen nicht die Winkel sondern die Sinus- und Kosinuswerte benötigt werden!
Natürlich dürfen sie dann nicht vergessen, sich entsprechende Funktionen für die Berechnung der Rotationsmatrizen zu schreiben (CreateRotYMatrix(), CreateRotAxisMatrix() usw.). Siehe hierzu den Artikel „3D-Programmierung (Mathematik) Teil 6“.
inline void Positioning_2DObject(
D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
D3DXVECTOR3* pCameraSpacePosition,
float &SinAngleHorizontal, float &CosAngleHorizontal,
float &SinAngleVertical, float &CosAngleVertical,
float &scaleX, float &scaleY)
{
D3DXMATRIXA16 tempMatrix1, tempMatrix2, RotationTranslationMatrix,
ScaleMatrix;
// Skalierungsmatrix berechnen:
D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);
D3DXVECTOR3 temp1Vektor3;
// horizontale Drehung des Billboards:
CreateRotYMatrix(&tempMatrix1, SinAngleHorizontal, CosAngleHorizontal);
// horizontale Drehachse für die vertikale Drehung berechnen:
Multiply3DVectorWithRotationMatrix(&temp1Vektor3,
&g_CameraHorizontalOriginalNeg,
&tempMatrix1);
// vertikale Drehung des Billboards um die horizontale Drehachse:
CreateRotAxisMatrix(&tempMatrix2, &temp1Vektor3, SinAngleVertical,
CosAngleVertical);
// Matrix für die komplette Drehung (erst horizontal, dann vertikal)
// berechnen:
RotationTranslationMatrix = tempMatrix1*tempMatrix2;
// Positionierung des Billboards im Kameraraum:
RotationTranslationMatrix._41 = pCameraSpacePosition->x;
RotationTranslationMatrix._42 = pCameraSpacePosition->y;
RotationTranslationMatrix._43 = pCameraSpacePosition->z;
// Gesamttransformationsmatrix berechnen:
*pCameraSpaceTransformationMatrix =
ScaleMatrix*RotationTranslationMatrix;
}
D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
D3DXVECTOR3* pCameraSpacePosition,
float &SinAngleHorizontal, float &CosAngleHorizontal,
float &SinAngleVertical, float &CosAngleVertical,
float &scaleX, float &scaleY)
{
D3DXMATRIXA16 tempMatrix1, tempMatrix2, RotationTranslationMatrix,
ScaleMatrix;
// Skalierungsmatrix berechnen:
D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);
D3DXVECTOR3 temp1Vektor3;
// horizontale Drehung des Billboards:
CreateRotYMatrix(&tempMatrix1, SinAngleHorizontal, CosAngleHorizontal);
// horizontale Drehachse für die vertikale Drehung berechnen:
Multiply3DVectorWithRotationMatrix(&temp1Vektor3,
&g_CameraHorizontalOriginalNeg,
&tempMatrix1);
// vertikale Drehung des Billboards um die horizontale Drehachse:
CreateRotAxisMatrix(&tempMatrix2, &temp1Vektor3, SinAngleVertical,
CosAngleVertical);
// Matrix für die komplette Drehung (erst horizontal, dann vertikal)
// berechnen:
RotationTranslationMatrix = tempMatrix1*tempMatrix2;
// Positionierung des Billboards im Kameraraum:
RotationTranslationMatrix._41 = pCameraSpacePosition->x;
RotationTranslationMatrix._42 = pCameraSpacePosition->y;
RotationTranslationMatrix._43 = pCameraSpacePosition->z;
// Gesamttransformationsmatrix berechnen:
*pCameraSpaceTransformationMatrix =
ScaleMatrix*RotationTranslationMatrix;
}
Die dritte und letzte Funktion, die ich ihnen vorstellen möchte, ermöglicht die Ausrichtung eines Billboards mit einer zusätzlichen Drehung um die Ausrichtungsachse (diese entspricht der normierten Billboardposition im Kameraraum). Durch solch eine Drehung lassen sich beispielsweise die Strahlen der Sonne animieren.
inline void Positioning_2DObjectRotated(
D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
D3DXVECTOR3* pCameraSpacePosition,
float &angleHorizontal, float &angleVertical,
float &scaleX, float &scaleY,
float &rotationAngle)
{
D3DXMATRIXA16 tempMatrix, tempMatrix1, tempMatrix2,
RotationTranslationMatrix, ScaleMatrix;
// Skalierungsmatrix berechnen:
D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);
// Drehung de Billboards um die Ausrichtungsachse. Diese
// entspricht der normierten Position im Kameraraum.
D3DXMatrixRotationAxis(&tempMatrix, pCameraSpacePosition,
rotationAngle);
D3DXVECTOR3 temp1Vektor3;
// horizontale Drehung des Billboards:
D3DXMatrixRotationY(&tempMatrix1, angleHorizontal);
// horizontale Drehachse für die vertikale Drehung berechnen:
Multiply3DVectorWithRotationMatrix(&temp1Vektor3,
&g_CameraHorizontalOriginalNeg,
&tempMatrix1);
// vertikale Drehung des Billboards um die horizontale Drehachse:
D3DXMatrixRotationAxis(&tempMatrix2, &temp1Vektor3, angleVertical);
// Matrix für die komplette Drehung (erst horizontal, dann vertikal
// und schließlich die Drehung um die Ausrichtungsachse)
// berechnen:
RotationTranslationMatrix = tempMatrix1*tempMatrix2*tempMatrix;
// Positionierung des Billboards im Kameraraum:
RotationTranslationMatrix._41 = pCameraSpacePosition->x;
RotationTranslationMatrix._42 = pCameraSpacePosition->y;
RotationTranslationMatrix._43 = pCameraSpacePosition->z;
// Gesamttransformationsmatrix berechnen:
*pCameraSpaceTransformationMatrix =
ScaleMatrix*RotationTranslationMatrix;
}
D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
D3DXVECTOR3* pCameraSpacePosition,
float &angleHorizontal, float &angleVertical,
float &scaleX, float &scaleY,
float &rotationAngle)
{
D3DXMATRIXA16 tempMatrix, tempMatrix1, tempMatrix2,
RotationTranslationMatrix, ScaleMatrix;
// Skalierungsmatrix berechnen:
D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);
// Drehung de Billboards um die Ausrichtungsachse. Diese
// entspricht der normierten Position im Kameraraum.
D3DXMatrixRotationAxis(&tempMatrix, pCameraSpacePosition,
rotationAngle);
D3DXVECTOR3 temp1Vektor3;
// horizontale Drehung des Billboards:
D3DXMatrixRotationY(&tempMatrix1, angleHorizontal);
// horizontale Drehachse für die vertikale Drehung berechnen:
Multiply3DVectorWithRotationMatrix(&temp1Vektor3,
&g_CameraHorizontalOriginalNeg,
&tempMatrix1);
// vertikale Drehung des Billboards um die horizontale Drehachse:
D3DXMatrixRotationAxis(&tempMatrix2, &temp1Vektor3, angleVertical);
// Matrix für die komplette Drehung (erst horizontal, dann vertikal
// und schließlich die Drehung um die Ausrichtungsachse)
// berechnen:
RotationTranslationMatrix = tempMatrix1*tempMatrix2*tempMatrix;
// Positionierung des Billboards im Kameraraum:
RotationTranslationMatrix._41 = pCameraSpacePosition->x;
RotationTranslationMatrix._42 = pCameraSpacePosition->y;
RotationTranslationMatrix._43 = pCameraSpacePosition->z;
// Gesamttransformationsmatrix berechnen:
*pCameraSpaceTransformationMatrix =
ScaleMatrix*RotationTranslationMatrix;
}