GLSL Shadow Mapping Problem

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
maxx2097
Beiträge: 22
Registriert: 15.03.2011, 19:37

GLSL Shadow Mapping Problem

Beitrag von maxx2097 » 24.03.2011, 02:28

Hallo zusammen,

ich habe jetzt mal versucht ein simples Shadow-Mapping in GLSL Shadern auf dem iPhone zu implementieren und dabei diverse Tutorials durchforstet. Ich verwende also 2 Render-Passes... einmal um die ShadowMap zu generieren (Render to Texture) und dann einen zweiten Pass mit der vorher generierten ShadowMap als Textur. Die z-Werte werden dabei im ersten Durchgang in eine RGB8A Textur verpackt.

Die dazugehörigen FBOs, usw. scheinen soweit zu funktionieren. Das Ergebnis hat aber leider eher nichts mit einem Schatten zu tun :(
Ich habe das Gefühl nah dran zu sein... evtl. kann mir ja hier jemand helfen, wo mein Fehler liegt:

Der erste Render-Durchgang rendert in die ShadowMap-Textur aus Sicht der Lichtquelle:

ShadowMapper.vertexShader

Code: Alles auswählen

uniform mat4 u_modelMatrix;
uniform mat4 u_projectionMatrix;
attribute vec4 a_vertices;

varying vec4 position;

void main()
{
    position = u_projectionMatrix * u_modelMatrix * a_vertices;
    gl_Position = position;    
}
ShadowMapper.fragmentShader

Code: Alles auswählen

const highp vec4 packFactors = vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0);
const highp vec4 bitMask     = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);

varying highp vec4 position;

void main()
{
    
    highp float normalizedDistance  = position.z / position.w;
    normalizedDistance = (normalizedDistance + 1.0) / 2.0;
    
    highp vec4 packedValue = vec4(fract(packFactors*normalizedDistance));
    packedValue -= packedValue.xxyz * bitMask;
    
    gl_FragColor  = packedValue;
}

Im zweiten Durchgang wird dann aus sich der "Kamera" gerendert:

SceneShader.vertexShader:

Code: Alles auswählen

uniform mat4 u_modelMatrix;
uniform mat4 u_projectionMatrix;
uniform mat4 u_lightProjectionMatrix;

attribute vec4 a_vertices;

varying vec4 v_shadowcoords;

void main()
{
    // shadowcoords
    v_shadowcoords = u_lightProjectionMatrix * u_modelMatrix * a_vertices;
    
    // set position
    gl_Position = u_projectionMatrix * u_modelMatrix * a_vertices;    
}
(u_lightProjectionMatrix enthält dabei die gleiche Matrix wie beim ersten Durchgang u_projectionMatrix)

SceneShader.fragmentShader:

Code: Alles auswählen

uniform sampler2D u_shadowmap;

varying highp vec4 v_shadowcoords;

const highp vec4 bitMask = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);

void main()
{
    highp vec4 shadowCoordinateWdivide = v_shadowcoords / v_shadowcoords.w ;
    shadowCoordinateWdivide = 0.5 * shadowCoordinateWdivide + 0.5;
    
    shadowCoordinateWdivide.z += 0.0005;
    
    lowp vec4 shadowdepth = texture2D(u_shadowmap, shadowCoordinateWdivide.xy);
    highp float distanceFromLight = dot(shadowdepth.xyzw , bitMask);
    
    lowp float shadow = 1.0;
    if (distanceFromLight < shadowCoordinateWdivide.z) shadow = 0.5;    
    
    gl_FragColor = vec4(shadow,shadow,shadow,1.0);    
}


Soweit ich das testen konnte, wird die ShadowMap korrekt erzeugt, gepackt und wieder ausgepackt... irgendwas fehlt aber noch, damit ein richtiger Schatten draus wird. Im Moment ist das was man als Schatten bezeichnen könnte an völlig falscher Position auf dem Objekt, das eigentlich den Schatten werfen sollte.

Evtl. hat ja jemand einen Fingerzeig in die richtige Richtung.

Vielen Dank... Prost!

Dirk Schulz
Establishment
Beiträge: 130
Registriert: 01.03.2009, 15:21
Alter Benutzername: frittentuete

Re: GLSL Shadow Mapping Problem

Beitrag von Dirk Schulz » 24.03.2011, 15:35

Hi,

da du dir sicher bist, dass die Shadowmap richtig erzeugt wurde und nur bei der Projektion Fehler auftreten, hab ich mal mit meinem HLSL-Shader verglichen.

Der einzige gröbere Unterschied der mir auffällt ist:

Code: Alles auswählen

float2 samplecoord = (vPosLight.xy * float2(0.5, -0.5)) + 0.5;
was in deinem Code dem:

Code: Alles auswählen

shadowCoordinateWdivide.xy = (shadowCoordinateWdivide.xy * vec2(0.5, -0.5)) + 0.5;
entsprechen würde. Also die y-Coordinate der Shadowmap wird gespiegelt.


Falls das nicht das Problem löst, zeig mal nen Screen. ;)

maxx2097
Beiträge: 22
Registriert: 15.03.2011, 19:37

Re: GLSL Shadow Mapping Problem

Beitrag von maxx2097 » 24.03.2011, 21:20

Hi!

Vielen Dank erstmal für Deine Antwort. Also leider sieht es damit auch nicht viel besser aus:
Screen shot 2011-03-24 at 7.32.46 PM.png
Der "Schatten" auf dem Boden bleibt immer an der gleichen Position wenn sich der Torus dreht. Der "Schatten" auf dem Torus sieht auch so aus, als würde ein größeres Objekt (der Boden?) immer an die gleiche Stelle einen Schatten werfen.

Irgendwie habe ich den Verdacht, dass bei meinen Renderdurchgängen noch eine Projektion in die Schattenebene fehlt.
Im ersten Durchgang mache ich folgendes:

Code: Alles auswählen

        ESVEC3 lightPosition = (ESVEC3) {4.0f, 7.0f, 3.0f};
       ESMatrix projection;
        
        
        esMatrixLoadIdentity(&projection);
        esPerspective(&projection, 45.0f, 1.0f, 0.1f, 100.0f);
        esLookAt(&projection, lightPosition.x, lightPosition.y, lightPosition.z, 
                 0.0f, 0.0f, 0.0f, 
                 0.0f, 1.0f, 0.0f);
projection landet dann in u_projectionMatrix des ShadowMapping shaders.

Die gleiche Matrix verwende ich dann auch in u_lightProjectionMatrix des SceneShaders... es ist also immer exakt so, als würde ich durch die "Kamera" gucken (bis auf den Aspect Ratio natürlich).

Dirk Schulz
Establishment
Beiträge: 130
Registriert: 01.03.2009, 15:21
Alter Benutzername: frittentuete

Re: GLSL Shadow Mapping Problem

Beitrag von Dirk Schulz » 25.03.2011, 03:03

Hi,

Also erstes Problem: scheinbar werden die Tiefenwerte vom Torus mit denen vom Boden überschrieben.
Wie sehen denn deine Depth-Buffer Einstellungen aus? Du renderst den Torus aber auch im Shadowpass, oder?


Zweites Problem: Die "Ecke", die keinen Schatten hat, lässt sich wohl auf den Anfang/das Ende der Shadowmap zurückführen?!
Abhilfe schafft da entweder: das Licht weiter entfernt platzieren, das FOV größer machen oder eine orthogonale Projektion zu wählen.
Alle drei Möglichkeiten verschlechtern allerdings die Qualität des Schattens.


Desweiteren ist mir noch etwas bei deinem ShadowMapper.fragmentShader aufgefallen:

Was soll das packedValue -= packedValue.xxyz * bitMask ? Es sollte doch eigentlich reichen packedValue so auszuspucken.


edit: Zur Not lass den Boden aus dem ShadowPass erstmal raus. ;)

Antworten