Billboard Techniken: Bewegte Wolken und Blitze in der Planetenatmosphäre

Der nachfolgende Artikel dürfte für all diejenigen von Interesse sein, die an einem Weltraumspiel arbeiten und sich gerade darüber den Kopf zerbrechen, wie sich Planeten und Monde ein wenig interessanter gestalten lassen. Für Gasriesen mit ihren oftmals turbulenten Atmosphären würde sich beispielsweise die Darstellung von animierten Blitzen und Wolken anbieten.
Im zweiten Artikel über den Einsatz von Billboard-Techniken haben wir die Verwendung von Billboards (Wolken, Blitze, die Sonne, usw.) im Rahmen der Hintergrund-Darstellung diskutiert. Ausgerichtet wurden die einzelnen Billboards anhand ihrer Polarkoordinaten. Die gleiche Vorgehensweise bietet sich auch an dieser Stelle an, mit dem Unterschied, dass nun nicht mehr die Kamera im Zentrum der Darstellung liegt sondern der Mittelpunkt des jeweiligen Planeten oder Mondes.
Dies hat zur Folge, dass sich zum einen die Multiplikationsreihenfolge bei der Aufstellung der Gesamtrotationsmatrix ändert (erst den korrekten Billboard-Blickwinkel einstellen, das Billboard dann horizontal und schließlich vertikal ausrichten) und dass zum anderen die Drehung des Billboards beim Festlegen des Blickwinkels um die positive z-Achse erfolgt.

inline void Positioning_PlanetaryCloud(
            D3DXMATRIXA16* pCameraSpaceTransformationMatrix,
            D3DXVECTOR3* pCameraSpacePosition,
            float &SinAngleHorizontal, float &CosAngleHorizontal,
            float &SinAngleVertical, float &CosAngleVertical,
            float &scaleX, float &scaleY, float &rotationAngle)
{
    D3DXMATRIXA16 tempMatrix, tempMatrix1, tempMatrix2,
                  RotationTranslationMatrix, ScaleMatrix;

    // Skalierungsmatrix berechnen:
    D3DXMatrixScaling(&ScaleMatrix, scaleX, scaleY, 1.0f);

    D3DXVECTOR3 temp1Vektor3;

    // Die erste Matrix legt den Blickwinkel des Billboards fest:
    D3DXMatrixRotationZ(&tempMatrix, rotationAngle);

    // 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 berechnen (
erst den korrekten
    // Billboard-Blickwinkel einstellen, das Billboard dann horizontal
    // und schließlich vertikal ausrichten
):
    RotationTranslationMatrix = tempMatrix*tempMatrix1*tempMatrix2;

    // Positionierung des Billboards im Kameraraum:
    RotationTranslationMatrix._41 = pCameraSpacePosition->x;
    RotationTranslationMatrix._42 = pCameraSpacePosition->y;
    RotationTranslationMatrix._43 = pCameraSpacePosition->z;

    // Gesamttransformationsmatrix berechnen:
    *pCameraSpaceTransformationMatrix = ScaleMatrix*
                                        RotationTranslationMatrix;
}

Nun müssen wir noch eine wichtige Frage klären – wie berechnet man eigentlich die Positionen der Wolken-Billboards und der Blitze, während diese sich um einen Planeten herumbewegen?

Beginnen wir zunächst damit, die normierte Position eines Wolken-Billboards im Modellkoordinatensystem eines Planeten nach dem Zufallsprinzip festzulegen:

CloudModelPos = D3DXVECTOR3(frnd(-1.0f, 1.0f),
                            frnd(-0.7f, 0.7f),
                            frnd(-1.0f, 1.0f));

D3DXVec3Normalize(&CloudModelPos, &CloudModelPos);

Mit der Zeit bewegt sich das Wolken-Billboard um den Planeten herum. Diese Bewegung kann als Rotation um die Planetenachse aufgefasst und mithilfe der CloudTotalRotationMatrix beschrieben werden:

Multiply3DVectorWithRotationMatrix(&CloudModelPos_Rotated, &CloudModelPos,
                                   &CloudTotalRotationMatrix);

Im Anschluss daran muss die noch normierte Billboard-Position korrekt skaliert werden. Hierbei kommt der PlanetAtmosphereScaleFactor zum Einsatz:

CloudModelPos_Rotated *= PlanetAtmosphereScaleFactor;

Im letzten Schritt kann die Position des Wolken-Billboards im Kameraraum unter Berücksichtigung der Planetenposition berechnet werden:

CloudCameraSpacePosition = CloudModelPos_Rotated +
                           Planet->CameraSpacePosition;