Le mappe d'ombra di varianza non vogliono essere visualizzate correttamente


8

Ho implementato VSM (e anche ESM) nel mio motore, ma i risultati non sono come mi aspettavo e ho visto in molti esempi pubblicati in rete.

Ho impostato il filtro delle mappe d'ombra su GL_LINEAR ma quando confronto i risultati con la normale mappa d'ombra è visibilmente peggiore.

Schermo

Ho provato a calcolare i momenti direttamente nel punto luce shader o ottenerlo dalla trama come nella maggior parte dei tutorial, ma i risultati sono gli stessi.

Codice:

uniform samplerCubeShadow shadowMap;

...

vec4 worldSpace=inverse(ViewMatrix)*vec4(pos,1);

vec4 coord=LightViewMatrix*worldSpace;
vec4 abs_coord=abs(coord);

float fs_z=-max(abs_coord.x, max(abs_coord.y, abs_coord.z));

vec4 clip=LightProjectionMatrix*vec4(0.0,0.0,fs_z,1.0);
float d2=(clip.z / clip.w)*0.5+0.5; // clamp to [0..1]

...

float shadowTexel=texture(shadowMap,vec4(coord.xyz,d2));

// VSM (Variance Shadow Map)
// get partial derivatives
float dx = dFdx(d2);
float dy = dFdy(d2);
vec2 moments = vec2(d2, d2*d2+0.25*(dx*dx+dy*dy));
return chebychevInequality(moments, shadowTexel);

Usando questo codice ottengo risultati come nell'immagine sopra. Ho anche provato a non usare samplerCubeShadow ma samplerCube ma i risultati sono anche peggiori. Innanzitutto, ho le ombre dure. In secondo luogo, le ombre non riempiono l'area come dovrebbero quando si ottengono momenti da un'altra trama. Guarda la seconda schermata. Ecco anche la mappa del cubo generata. Non è simile a ciò che è in profondità mappa anche se inserisco profondità / momento1 in tutti e 3 i canali.

Shader per ottenere momenti:

// Vartex shader
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;

// Fragment shader
float depth = v_position.z / v_position.w ;
depth = depth * 0.5 + 0.5;          //Don't forget to move away from unit cube ([-1,1]) to [0,1] coordinate system

float moment1 = depth;
float moment2 = depth * depth;

// Adjusting moments (this is sort of bias per pixel) using derivative
float dx = dFdx(depth);
float dy = dFdy(depth);
moment2 += 0.25*(dx*dx+dy*dy) ;

FragColor = vec4( moment1,moment2, 0.0, 0.0 );

Schermo

Sono davvero bloccato. Spero che mi aiuterai a risolvere i miei problemi.

MODIFICARE:

Ho trovato la soluzione al secondo problema. Avevo abilitato la fusione e mi dava una mappa di profondità errata.

Ottengo anche un risultato migliore per il primo problema, ma ora sto combattendo con la profondità adeguata per confrontarlo con la profondità della mappa ombra.

In SM semplice uso questo codice:

vec4 worldSpace=inverse(ViewMatrix)*vec4(pos,1);

vec4 coord=LightViewMatrix*worldSpace;
vec4 abs_coord=abs(coord);

float fs_z=-max(abs_coord.x, max(abs_coord.y, abs_coord.z));

vec4 clip=LightProjectionMatrix*vec4(0.0,0.0,fs_z,1.0);
float d=(clip.z / clip.w)*0.5+0.5; // clamp to [0..1]

dove pos è posizione in Visualizza spazio. Quindi ho letto i valori dalla mappa ombra usando:

texture(shadowMap,vec4(coord.xyz,d))

In VSM memorizzo la profondità nel canale R nella trama RG32F. Il valore della profondità viene calcolato in questo modo:

// VS
gl_Position=ModelViewProjectionMatrix*Vertex;
v_position=gl_Position;

// FS
float depth = v_position.z/v_position.w;
depth = depth * 0.5 + 0.5;

Quindi nello shader per punto luce uso il vettore coord (come nella SM standard) per leggere i valori dalla mappa delle ombre e questo funziona bene. Ma il problema è in questa parte:

// No shadow if depth of fragment is in front
if ( moments.x <= distance)
    return 1.0;

In quali coordinate si dovrebbe ottenere la distanza? In quali coordinate ho profondità dalla mappa ombra? Dovrebbe essere lineare? Qualcuno potrebbe spiegarmelo? Sono un po 'confuso in questo momento, ho provato molti modi per ottenere questo e tutti i risultati non sono come mi aspetto.

EDIT2: seguendo il suggerimento JarkkoL e questo tutorial ho cambiato il mio codice. Ora sto memorizzando la profondità usando questo codice:

// VS
v_position=ModelViewMatrix*Vertex;
gl_Position=ProjectionMatrix*v_position;

// FS
const float Near = 0.1;
const float Far = 90.0; // camera far plane
const float LinearDepthConstant = 1.0 / (Far - Near);

float depth = length(v_position)*LinearDepthConstant;

E lo confronto con il valore che ottengo in questo modo:

float dist=length( vec3(inverse(ViewMatrix)*vec4(pos,1.0)) - PointLight.position )*LinearDepthConstant; // pos is read from depth buffer and is in view space so I want invert it to world space as it was in tutorial

E questo è il risultato:

Screen3

Nel cerchio rosso ho segnato i bordi visibili tra le facce della mappa del cubo. C'è ancora qualcosa che non va. Penso che potrebbe essere qualcosa con l'inversione di View Matrix ma non sono sicuro.


Ho aggiunto informazioni sui miei progressi attuali.
Harry,

1
Non dovresti usare la profondità non lineare che stai usando attualmente
JarkkoL

Grazie per il consiglio. Ho provato a seguirlo e ho modificato il post con i miei nuovi risultati.
Harry,

Prova a impostare la modalità indirizzo per bloccare la mappa cubica
JarkkoL,

Questo aiuta davvero. Ho impostato GL_REPEAT per le cubemap e me ne sono completamente dimenticato. Comunque vsm shadows non viene ancora visualizzato come una semplice mappa ombra.
Harry,

Risposte:


1

Per quanto riguarda le cuciture di cubemap, puoi semplicemente filtrare attraverso i bordi.

Vedere: glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

Per quanto riguarda l'effettiva qualità dell'ombra, l'intero vantaggio delle tecniche VSM ed ESM deriva dalla forma speciale adottata dal test di visibilità. Probabilmente vuoi introdurre un fattore costante per scurire o scurire le ombre, in modo che il bordo non sia così duro.

Per i dati ESM è semplice:

light = exp(factor * (occluder - receiver));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.