Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

21.02.2010, 13:49

Scattering nach O'Neil

Hallo,

Ich versuche mich momentan an einer Implementierung von Sean O'Neils Scattering (Artikel ,
Quellcode). Er hat es mittels OpenGL und GLSL/Cg geschrieben. Ich benutze DirectX und HLSL.
Ich beschränke mich dabei auf das Zeichnen eines Planeten aus dem Weltall, also Planetenoberfläche + Atmosphäre.
Das Zeichnen der Planetenoberfläche (GroundFromSpace) funktioniert. Aber das Darstellen der Atmosphäre (SkyFromSpace) leider nicht.
Im nachfolgenden Bild habe ich die Planetenoberfläche schwarz gezeichnet, damit man die Atmosphäre besser sieht.

(Link)

Wie zu sehen ist, geht der Farbverlauf (weiss nach blau) um den Planeten herum und nicht von Planeten weg.
Diese Farbverläufe rotieren um den Planeten herum, wenn ich die Kamera um den Planeten bewege.
Ich habe den Code vom Shader (SkyFromSpace) fast komplett übernommen. Ich benutze als Modell eine Einheitskugel(10.000 Punkte),
wodurch ich die untransformierte Vertexposition im VertexShader vor Gebrauch mit dem Radius der Atmosphäre multipliziere.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
VS_OUTPUT mainVS(float3 gl_Vertex : POSITION)
{
    // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
    float3 v3Pos = gl_Vertex.xyz * fOuterRadius;
    float3 v3Ray = v3Pos - v3CameraPos;
    float fFar = length(v3Ray);
    v3Ray /= fFar;

    // Calculate the closest intersection of the ray with the outer atmosphere (which is the near point of the ray passing through the atmosphere)
    float fNear = getNearIntersection(v3CameraPos, v3Ray, fCameraHeight2, fOuterRadius2);

    // Calculate the ray's start and end positions in the atmosphere, then calculate its scattering offset
    float3 v3Start = v3CameraPos + v3Ray * fNear;
    fFar -= fNear;
    float fStartAngle = dot(v3Ray, v3Start) / fOuterRadius;
    float fStartDepth = exp(-fInvScaleDepth);
    float fStartOffset = fStartDepth*scale(fStartAngle);

    // Initialize the scattering loop variables
    float fSampleLength = fFar / fSamples;
    float fScaledLength = fSampleLength * fScale;
    float3 v3SampleRay = v3Ray * fSampleLength;
    float3 v3SamplePoint = v3Start + v3SampleRay * 0.5;

    // Now loop through the sample rays
    float3 v3FrontColor = float3(0.0, 0.0, 0.0);
    for(int i=0; i<nSamples; i++)
    {
        float fHeight = length(v3SamplePoint);
        float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight));
        float fLightAngle = dot(v3LightPos, v3SamplePoint) / fHeight;
        float fCameraAngle = dot(v3Ray, v3SamplePoint) / fHeight;
        float fScatter = (fStartOffset + fDepth*(scale(fLightAngle) - scale(fCameraAngle)));
        float3 v3Attenuate = exp(-fScatter * (v3InvWavelength * fKr4PI + fKm4PI));
        v3FrontColor += v3Attenuate * (fDepth * fScaledLength);
        v3SamplePoint += v3SampleRay;
    }

    // Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
    VS_OUTPUT OUT = (VS_OUTPUT)0;
    OUT.pos = mul(float4(gl_Vertex, 1.0), matWVP);
    
    OUT.c0.rgb = v3FrontColor * (v3InvWavelength * fKrESun);
    OUT.c1.rgb = v3FrontColor * fKmESun;
    OUT.t0 = v3CameraPos - v3Pos;
    return OUT;
}

float4 mainPS(float4 c0 : TEXCOORD0, float4 c1 : TEXCOORD1, float3 v3Direction : TEXCOORD2) : COLOR 
{
    float fCos = dot(v3LightPos, v3Direction) / length(v3Direction);
    float fCos2 = fCos*fCos;
    float4 color = getRayleighPhase(fCos2) * c0 + getMiePhase(fCos, fCos2, g, g2) * c1;
    color.a = 1.0;//color.b;
    return color;
    //return float4(1 - exp(-2.0 * color.rgb), color.b);
}

Die Kugel für die Atmosphäre rendere ich wie O'Neil mit CullMode_CW.
Ich halte mich auch an die Restriktionen der Scale-Funktion (AtmosphärenRadius ist 1.025 * PlanetenRadius und H0 ist 0.25).
Die anderen Werte stimmen auch mit O'Neils Werten überein.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
m_vInvWaveLength.x = 1.0f / powf(0.65f, 4.0f);
    m_vInvWaveLength.y = 1.0f / powf(0.57f, 4.0f);
    m_vInvWaveLength.z = 1.0f / powf(0.475f, 4.0f);

    const float fRayleigh = 0.0025f;
    const float fMie = 0.001f;
    m_vRayleighSun = vSunColor * fRayleigh;
    m_vMieSun = vSunColor * fMie;
    m_fRayleigh4Pi = 4.0f * D3DX_PI * fRayleigh;
    m_fMie4Pi = 4.0f * D3DX_PI * fMie;

    m_fHeightScale = 1.0f / (m_fAtmosphereRadius - m_fPlanetRadius);
    m_fScaleOverScaleDepth = m_fHeightScale * 4.0f;

    m_fMieSymmetry = -0.99f; 

Die Demo von O'Neil läuft bei mir einwandfrei. Es muss also am Code liegen.
Ich weiss, dass eine Fehlerdiagnose ziemlich schwer wird. Aber vielleicht hat jemand bei seiner Implementierung
ähnliche Probleme gehabt. Sieht jemand eine Lösung für das Problem?

Gruss
Gameco

BlazeX

Alter Hase

Beiträge: 478

Wohnort: DD

Beruf: Maschinenbau-Student

  • Private Nachricht senden

2

21.02.2010, 19:59

Re: Scattering nach O'Neil

Zitat von »"Gameco"«

AtmosphärenRadius ist 1.025 * PlanetenRadius


Hast du schonmal testweise den Radius der Atmosphäre vergrößert?

Renderst du mit eingeschaltetem AlphaBlending die Atmosphäre?

3

22.02.2010, 09:48

Re: Scattering nach O'Neil

Zitat von »"BlazeX"«

Hast du schonmal testweise den Radius der Atmosphäre vergrößert?

Wenn ich den Radius der Atmosphäre im Verhältnis zum Planetenradius vergrössere, müsste ich die Werte für die "optische Tiefe" (optical depth) in alle Richtungen von verschiedenen Höhen neu berechnen. Ich könnte also nicht mehr die scale-Funktion dafür verwenden.
Was ich schon gemacht habe, ist für den Planetenradius verschiedene Werte zu verwenden. Darunter auch 10.0 wie O'Neil. Aber da hat sich nichts am Problem geändert.

Zitat von »"BlazeX"«

Renderst du mit eingeschaltetem AlphaBlending die Atmosphäre?

Im Quellcode von sponeil.net wird srcBlend_One und destBlend_One verwendet. Im Quellcode von der GPU Gems 2 CD wurde das auskommentiert. Ich habe beides versucht, es hat aber keine Änderungen mt sich gebracht. Das liegt wohl daran, dass hinter der Atmosphäre nur der schwarze Hintergrund ist. Insofern ist es egal ob destBlend_One oder DestBlend_Zero.

Gruss
Gameco

Werbeanzeige