Billboard Techniken: Hintergrund-Darstellung

In diesem Artikel werden wir uns mit der Billboard-Ausrichtung im Rahmen der Hintergund-Darstellung befassen – doch was genau hat man sich darunter vorzustellen?
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.

Zur Ausrichtung und Positionierung eines Hintergrund-Billboards im 3D-Raum bedarf es zweier Drehungen. Im ersten Schritt erfolgt eine horizontale Drehung um die y-Achse gemäß dem vorgegebenen Horizontalwinkel (angleHorizontal). Im zweiten Schritt wird mithilfe der zu Drehung 1 zugehörigen Rotationsmatrix die horizontale Drehachse für die sich anschließende vertikale Drehung berechnet. Im dritten Schritt wird die Rotationsmatrix für die vertikale Drehung (Drehwinkel: angleVertical) berechnet und im Anschluss daran aus beiden Rotationsmatrizen die Gesamtrotationsmatrix gebildet. Die Gesamtrotationsmatrix wird nun in eine Gesamtrotations-Translations-Matrix überführt, indem man den Matrixelementen _41, _42 und _43 die x-, y- und z-Koordinaten der Billboardposition (aus Sicht der Kamera) zuweist. Im letzten Schritt wird die Skalierungsmatrix mit der Gesamtrotations-Translations-Matrix multipliziert, und man erhält so die gesuchte Kameraraum-Transformationsmatrix (pCameraSpaceTransformationMatrix).

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;
}

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;
}

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;
}