Les cartes d'ombre de variance ne veulent pas s'afficher correctement


8

J'ai implémenté VSM (et aussi ESM) dans mon moteur mais les résultats ne sont pas pour moi comme je m'y attendais et vu dans de nombreux exemples publiés sur le réseau.

J'ai défini le filtrage des mappages d'ombres sur GL_LINEAR mais lorsque je compare le résultat à un mappage d'ombres normal, c'est visiblement pire.

Écran

J'ai essayé de calculer des moments directement dans le nuanceur de points ou de les obtenir à partir de la texture comme dans la plupart des didacticiels, mais les résultats sont les mêmes.

Code:

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);

En utilisant ce code, j'obtiens des résultats comme sur l'image ci-dessus. J'ai aussi essayé de ne pas utiliser samplerCubeShadow mais samplerCube mais les résultats sont encore pires. Tout d'abord, j'ai eu des ombres dures. Deuxièmement, les ombres ne remplissent pas la zone comme elles le devraient lorsque vous obtenez des moments d'une autre texture. Regardez le deuxième écran. Voici également la carte des cubes générée. Ce n'est pas similaire à ce qui est dans la carte en profondeur même si je mets depth / moment1 dans les 3 canaux.

Shader pour obtenir des moments:

// 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 );

Écran

Je suis vraiment coincé. J'espère que vous aiderez mi à résoudre mes problèmes.

ÉDITER:

J'ai trouvé la solution au deuxième problème. J'avais activé le mélange et cela m'a donné une mauvaise carte de profondeur.

J'obtiens également de meilleurs résultats au premier problème, mais maintenant je me bats avec la bonne profondeur pour la comparer avec la profondeur de la carte d'ombre.

En simple SM j'utilise ce code:

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]

où pos est la position dans l'espace de vue. Ensuite, j'ai lu les valeurs de la carte fantôme en utilisant:

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

Dans VSM, je stocke la profondeur dans le canal R dans la texture RG32F. La valeur de profondeur est calculée de cette manière:

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

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

Ensuite, dans le shader pour la lumière ponctuelle, j'utilise le vecteur coord (comme dans le SM standard) pour lire les valeurs de la carte des ombres et cela fonctionne bien. Mais le problème est dans cette partie:

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

Dans quelles coordonnées la distance doit-elle être obtenue? Dans quelles coordonnées j'ai la profondeur de la carte d'ombre? Il devrait être linéaire? Quelqu'un pourrait-il m'expliquer cela? Je suis un peu confus en ce moment, j'ai essayé de nombreuses façons d'obtenir cela et tous les résultats ne sont pas comme je m'y attendais.

EDIT2: Suite à l'astuce JarkkoL et à ce tutoriel, j'ai changé mon code. Maintenant, je stocke la profondeur en utilisant ce code:

// 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;

Et je le compare avec la valeur que j'obtiens de cette façon:

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

Et voici le résultat:

Screen3

Dans le cercle rouge, j'ai marqué des bordures visibles entre les faces de la carte du cube. Il y a encore quelque chose qui ne va pas. Je pense que cela pourrait être quelque chose d'inverser View Matrix mais je ne suis pas sûr.


J'ai ajouté des informations sur mes progrès actuels.
Harry

1
Vous ne devez pas utiliser la profondeur non linéaire que vous utilisez actuellement
JarkkoL

Merci pour le conseil. J'ai essayé de le suivre et j'ai édité le post avec mes nouveaux résultats.
Harry

Essayez de définir le mode d'adresse pour bloquer le cubemap
JarkkoL

Cela aide en effet. J'ai défini GL_REPEAT pour les cubemaps et j'ai complètement oublié cela. Quoi qu'il en soit, les ombres vsm ne s'affichent toujours pas comme une simple carte d'ombre.
Harry

Réponses:


1

En ce qui concerne les coutures cubemap, vous pouvez simplement filtrer sur les bords.

Voir: glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

En ce qui concerne votre qualité réelle d'ombre, tous les avantages des techniques VSM et ESM proviennent de la forme spéciale que prend le test de visibilité. Vous voudrez probablement introduire un facteur constant pour sur ou sous-assombrir les ombres, afin que le bord ne soit pas si dur.

Pour les données ESM, c'est simple:

light = exp(factor * (occluder - receiver));
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.