Galaxy Generation – Sterne Teil 2

Die Bedeutung aller für die prozedurale Generierung einer Galaxie benötigen Parameter haben wir im vorangegangenen Beitrag ausführlich besprochen. Im Rahmen des heutigen Artikels werden wir nun die Erzeugung einer neuen Galaxie in Form einer Schritt-für-Schritt-Anleitung in allen Einzelheiten erörtern.







Im ersten Schritt wird die maximal mögliche Anzahl der Sterne innerhalb der zu generierenden Galaxie berechnet, sowie die Startposition festgelegt, von der aus die Positionierung der einzelnen Sterne beginnt.

long NumSunsMax = g_NumSunsMaxXDir*g_NumSunsMaxYDir*g_NumSunsMaxZDir;

D3DXVECTOR3* StellarPosition = new D3DXVECTOR3[NumSunsMax];
bool* UseStellarPosition = new bool[NumSunsMax];

D3DXVECTOR3 CenterPos = g_NullVector;
D3DXVECTOR3 DiffVector;

D3DXVECTOR3 StartPos = D3DXVECTOR3(
                       -0.5f*(g_NumSunsMaxXDir-1)*g_GalaxyParam_DeltaX,
                       -0.5f*(g_NumSunsMaxYDir-1)*g_GalaxyParam_DeltaY,
                       -0.5f*(g_NumSunsMaxZDir-1)*g_GalaxyParam_DeltaZ);


Alle Sterne werden zunächst unter Berücksichtigung der g_GalaxyParam_DeltaX/Y/Z-Parameter in gleichmäßigen Abständen im Raum positioniert. Um die regelmäßige Anordnung der Sterne aufzubrechen, werden die einzelnen Stern-zu-Stern-Abstände in einem zweiten Schritt mithilfe der Min/MaxVarianceX/Y/Z-Parameter nach dem Zufallsprinzip variiert.

long i;
long counter = 0;
float distance;

float maxDistance = g_GalaxyDistanceDecreaseParameter3*
                    D3DXVec3Length(&StartPos);


float varX;
float varY;
float varZ;
 
for(i = 0; i < g_NumSunsMaxXDir; i++)
{
for(j = 0; j < g_NumSunsMaxYDir; j++)
{
for(k = 0; k < g_NumSunsMaxZDir; k++)
{

if(lrnd(2, 4) == 2)
varX = frnd(0.5f*g_GalaxyParam_MaxVarianceX, g_GalaxyParam_MaxVarianceX);
else
varX = frnd(g_GalaxyParam_MinVarianceX, 0.5f*g_GalaxyParam_MinVarianceX);

if(lrnd(2, 4) == 2)
varY = frnd(0.5f*g_GalaxyParam_MaxVarianceY, g_GalaxyParam_MaxVarianceY);
else
varY = frnd(g_GalaxyParam_MinVarianceY, 0.5f*g_GalaxyParam_MinVarianceY);

if(lrnd(2, 4) == 2)
varZ = frnd(0.5f*g_GalaxyParam_MaxVarianceZ, g_GalaxyParam_MaxVarianceZ);
else
varZ = frnd(g_GalaxyParam_MinVarianceZ, 0.5f*g_GalaxyParam_MinVarianceZ);
 
StellarPosition[counter] = StartPos +

                           D3DXVECTOR3(i*g_GalaxyParam_DeltaX,
                                       j*g_GalaxyParam_DeltaY,
                                       k*g_GalaxyParam_DeltaZ)+

                           D3DXVECTOR3(varX, varY, varZ);

    UseStellarPosition[counter] = true;
    counter++;
}}}


Im Anschluss daran erfolgt mithilfe der DistanceDecrease-Parameter eine Modifikation der Sternendichte und Größe der Galaxie durch Aussortieren einer mehr oder weniger großen Anzahl von Sternen (UseStellarPosition[i] = false).

counter = 0;

float randomValue;
float quotient;

for(i = 0; i < NumSunsMax; i++)
{
    DiffVector = StellarPosition[i] - CenterPos;
    distance = D3DXVec3Length(&DiffVector);
    randomValue = frnd(0.0f, 1.0f);
    quotient = distance/maxDistance;

    if(randomValue >= 1.0f-
       pow(quotient,g_GalaxyDistanceDecreaseParameter1*
       pow(1.0f-quotient,g_GalaxyDistanceDecreaseParameter2)))
    {
        UseStellarPosition[i] = false;
    }
    else
        counter++;
}

Im nächsten Schritt werden die Spiralarme der Galaxie generiert. Hierbei wird zunächst überprüft, ob die zuvor positionierten Sterne innerhalb oder außerhalb des galaktischen Bulge (Ausbuchtung des Kernbereichs) liegen. Für alle Sterne innerhalb des Bulges wird lediglich der Abstand zum Zentrum der Galaxie mithilfe der beiden DistanceIncreaseFactor-Parameter korrigiert. Die übrigen Sterne werden zunächst entlang der Spiralarm-Richtungen neu positioniert. Zusätzlich dazu wird der Abstand der Sterne von der galaktischen Ebene unter Berücksichtigung des g_SpiralGalaxyFlatnessFactor-Parameters mit zunehmender Entfernung vom galaktischen Zentrum verringert.
Die endgültigen Sternenpositionen in den einzelnen Spiralarmen ergeben sich durch Drehungen der zuvor festgelegten Positionen um die galaktische Achse, sofern man die Drehwinkel unter Berücksichtigung der beiden Parameter g_SpiralGalaxyTwistingFactorMin sowie g_SpiralGalaxyTwistingFactorMax mit zunehmendem Abstand vom galaktischen Zentrum kontinuierlich vergrößert.

Generierung einer Galaxie mit 4 Spiralarmen:

D3DXVECTOR3 DiffVectorRotated;
D3DXMATRIXA16 RotationMatrix;
D3DXVECTOR3 GalacticAxis;

// Vektoren für die Beschreibung der galaktischen Ebene:
D3DXVec3Cross(&GalacticAxis, &SpiralGalaxyPlaneDirection1,
              &SpiralGalaxyPlaneDirection2);

float dot1, dot2, dot3;
float distanceFactor;
long randomDir;

if(g_NumOfSpiralArms == 4)
{
for(i = 0; i < NumSunsMax; i++)
{
if(UseStellarPosition[i] == true)
{
    DiffVector = StellarPosition[i] - CenterPos;

    dot1 = D3DXVec3Dot(&DiffVector, &SpiralGalaxyPlaneDirection1);
    dot2 = D3DXVec3Dot(&DiffVector, &SpiralGalaxyPlaneDirection2);
    dot3 = D3DXVec3Dot(&DiffVector, &GalacticAxis);

    distance = sqrtf(dot1*dot1 + dot2*dot2);

// Stern innerhalb des Bulge:
if(distance < g_SpiralGalaxyBulgeRadius)
{
    distanceFactor = pow(distance,g_SpiralGalaxyDistanceExponent);

    DiffVector *= pow(g_GalaxyStellarDistanceIncreaseFactor1,
                      g_GalaxyStellarDistanceIncreaseFactor2*distance);

    StellarPosition[i] = DiffVector + CenterPos;
    continue;
}

// Stern außerhalb des Bulge:

randomDir = lrnd(0, 4);

if(randomDir == 0)
{
    DiffVector = SpiralGalaxyPlaneDirection1*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}
else if(randomDir == 1)
{
    DiffVector = -SpiralGalaxyPlaneDirection1*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}
else if(randomDir == 2)
{
    DiffVector = SpiralGalaxyPlaneDirection2*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}
else if(randomDir == 3)
{
    DiffVector = -SpiralGalaxyPlaneDirection2*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}

distanceFactor = pow(distance,g_SpiralGalaxyDistanceExponent);

CalcRotAxisMatrix(&RotationMatrix, &GalacticAxis,
                  frnd(g_SpiralGalaxyTwistingFactorMin,
                       g_SpiralGalaxyTwistingFactorMax)*distanceFactor);

Multiply3DVectorWithRotationMatrix(&DiffVectorRotated,
                                   &DiffVector,
                                   &RotationMatrix);

DiffVectorRotated *= pow(g_GalaxyStellarDistanceIncreaseFactor1,
                         g_GalaxyStellarDistanceIncreaseFactor2*distance);

StellarPosition[i] = DiffVectorRotated + CenterPos;
}}}


Generierung einer Galaxie mit 3 Spiralarmen:

else if(g_NumOfSpiralArms == 3)
{
D3DXVECTOR3 ThreeSpiralArmsDirection2;
D3DXVECTOR3 ThreeSpiralArmsDirection3;

CalcRotAxisMatrix(&RotationMatrix, &GalacticAxis, 120.0f*g_PI/180.0f);

Multiply3DVectorWithRotationMatrix(&ThreeSpiralArmsDirection2,
                                   &ThreeArmedSpiralGalaxyBaseDirection,
                                   &RotationMatrix);

Multiply3DVectorWithRotationMatrix(&ThreeSpiralArmsDirection3,
                                   &ThreeSpiralArmsDirection2,
                                   &RotationMatrix);
for(i = 0; i < NumSunsMax; i++)
{
if(UseStellarPosition[i] == true)
{
    DiffVector = StellarPosition[i] - CenterPos;

    dot1 = D3DXVec3Dot(&DiffVector, &SpiralGalaxyPlaneDirection1);
    dot2 = D3DXVec3Dot(&DiffVector, &SpiralGalaxyPlaneDirection2);
    dot3 = D3DXVec3Dot(&DiffVector, &GalacticAxis);

    distance = sqrtf(dot1*dot1 + dot2*dot2);

// Stern innerhalb des Bulge:
if(distance < g_SpiralGalaxyBulgeRadius)
{
    distanceFactor = pow(distance, g_SpiralGalaxyDistanceExponent);

    DiffVector *= pow(g_GalaxyStellarDistanceIncreaseFactor1,
                      g_GalaxyStellarDistanceIncreaseFactor2*distance);

    StellarPosition[i] = DiffVector + CenterPos;
    continue;
}

// Stern außerhalb des Bulge:

randomDir = lrnd(0, 3);

if(randomDir == 0)
{
    DiffVector = ThreeArmedSpiralGalaxyBaseDirection*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}
else if(randomDir == 1)
{
    DiffVector = ThreeSpiralArmsDirection2*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}
else if(randomDir == 2)
{
    DiffVector = ThreeSpiralArmsDirection3*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}

distanceFactor = pow(distance, g_SpiralGalaxyDistanceExponent);

CalcRotAxisMatrix(&RotationMatrix, &GalacticAxis,
                  frnd(g_SpiralGalaxyTwistingFactorMin,
                       g_SpiralGalaxyTwistingFactorMax)*distanceFactor);

Multiply3DVectorWithRotationMatrix(&DiffVectorRotated, &DiffVector,
                                   &RotationMatrix);

DiffVectorRotated *= pow(g_GalaxyStellarDistanceIncreaseFactor1,
                         g_GalaxyStellarDistanceIncreaseFactor2*distance);

StellarPosition[i] = DiffVectorRotated + CenterPos;
}}}


Generierung einer Galaxie mit 2 Spiralarmen:

else // if(g_NumOfSpiralArms == 2)
{
for(i = 0; i < NumSunsMax; i++)
{
if(UseStellarPosition[i] == true)
{
    DiffVector = StellarPosition[i] - CenterPos;

    dot1 = D3DXVec3Dot(&DiffVector, &SpiralGalaxyPlaneDirection1);
    dot2 = D3DXVec3Dot(&DiffVector, &SpiralGalaxyPlaneDirection2);
    dot3 = D3DXVec3Dot(&DiffVector, &GalacticAxis);

    distance = sqrtf(dot1*dot1 + dot2*dot2);

// Stern innerhalb des Bulge:
if(distance < g_SpiralGalaxyBulgeRadius)
{
    distanceFactor = pow(distance,g_SpiralGalaxyDistanceExponent);

    DiffVector *= pow(g_GalaxyStellarDistanceIncreaseFactor1,
                      g_GalaxyStellarDistanceIncreaseFactor2*distance);

    StellarPosition[i] = DiffVector + CenterPos;
    continue;
}

// Stern außerhalb des Bulge:

randomDir = lrnd(0, 2);

if(randomDir == 0)
{
    DiffVector = SpiralGalaxyPlaneDirection1*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}
else if(randomDir == 1)
{
    DiffVector = -SpiralGalaxyPlaneDirection1*distance +
                 (g_SpiralGalaxyFlatnessFactor*dot3)*GalacticAxis;
}

distanceFactor = pow(distance,g_SpiralGalaxyDistanceExponent);

CalcRotAxisMatrix(&RotationMatrix, &GalacticAxis,
                  frnd(g_SpiralGalaxyTwistingFactorMin,
                       g_SpiralGalaxyTwistingFactorMax)*distanceFactor);

Multiply3DVectorWithRotationMatrix(&DiffVectorRotated,
                                   &DiffVector,
                                   &RotationMatrix);

DiffVectorRotated *= pow(g_GalaxyStellarDistanceIncreaseFactor1,
                         g_GalaxyStellarDistanceIncreaseFactor2*distance);

StellarPosition[i] = DiffVectorRotated + CenterPos;
}}}

pGalaxy->Set_NumSunsMax(counter);


Im letzten Schritt wird für jeden Stern der Sternentyp sowie seine Größe festgelegt. Zur Auswahl stehen hierbei die folgenden Sternentypen und Spektralklassen:

  • Roter Riese (Spektralklasse M)
  • Roter Zwerg (Spektralklasse M)
  • Oranger Stern (Spektralklasse K)
  • Gelber Stern (Spektralklasse G)
  • Weißer Stern (Spektralklasse F)
  • Blauer Riese (Spektralklasse B)
  • Blauer Überriese (Spektralklasse O)


float RandomSpectralValue;
long SpectralType;

float SunScale;

for(i = 0; i < NumSunsMax; i++)
{
if(UseStellarPosition[i] == true)
{
RandomSpectralValue = frnd(0.0f, 1.0);

if(RandomSpectralValue >= g_SunBlue_DistributionValueMin &&
   RandomSpectralValue < g_SunBlue_DistributionValueMax)
{
    SpectralType = 0;
    SunScale = frnd(g_SunBlue_MinScale, g_SunBlue_MaxScale);
}
else if(RandomSpectralValue >= g_SunOrange_DistributionValueMin &&
        RandomSpectralValue < g_SunOrange_DistributionValueMax)
{
    SpectralType = 1;
    SunScale = frnd(g_SunOrange_MinScale, g_SunOrange_MaxScale);
}
else if(RandomSpectralValue >= g_SunRedDwarf_DistributionValueMin &&
        RandomSpectralValue < g_SunRedDwarf_DistributionValueMax)
{
    SpectralType = 2;
    SunScale = frnd(g_SunRedDwarf_MinScale, g_SunRedDwarf_MaxScale);
}
else if(RandomSpectralValue >= g_SunRedGiant_DistributionValueMin &&
        RandomSpectralValue < g_SunRedGiant_DistributionValueMax)
{
    SpectralType = 3;
    SunScale = frnd(g_SunRedGiant_MinScale, g_SunRedGiant_MaxScale);
}
else if(RandomSpectralValue >= g_SunYello_DistributionValueMin &&
        RandomSpectralValue < g_SunYello_DistributionValueMax)
{
    SpectralType = 4;
    SunScale = frnd(g_SunYello_MinScale, g_SunYello_MaxScale);
}
else if(RandomSpectralValue >= g_SunWhite_DistributionValueMin &&
        RandomSpectralValue < g_SunWhite_DistributionValueMax)
{
    SpectralType = 5;
    SunScale = frnd(g_SunWhite_MinScale, g_SunWhite_MaxScale);
}
else if(RandomSpectralValue >= g_SunBlueGiant_DistributionValueMin &&
        RandomSpectralValue < g_SunBlueGiant_DistributionValueMax)
{
    SpectralType = 6;
    SunScale = frnd(g_SunBlueGiant_MinScale, g_SunBlueGiant_MaxScale);
}
else if(RandomSpectralValue >= g_SunBlueHyperGiant_DistributionValueMin &&
        RandomSpectralValue < g_SunBlueHyperGiant_DistributionValueMax)
{
    SpectralType = 7;
    SunScale = frnd(g_SunBlueHyperGiant_MinScale, g_SunBlueHyperGiant_MaxScale);
}
else
{
    SpectralType = 4;
    SunScale = frnd(g_SunYello_MinScale, g_SunYello_MaxScale);
}

pGalaxy->Init_Sun(&StellarPosition[i], SunScale, SpectralType);
}}