Los maps de sombras de varianza no quieren representarse correctamente

Implementé VSM (y también ESM) en mi motor, pero los resultados son para mí no como esperaba y vi en muchos ejemplos publicados en la networking.

Establecí el filtrado de maps de sombra en GL_LINEAR, pero cuando comparo el resultado con el map de sombras normal, es visiblemente peor.

Pantalla

Intenté calcular los momentos directamente en el sombreador de puntos o getlos de la textura, como en la mayoría de los tutoriales, pero los resultados son los mismos.

Código:

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 este código obtengo resultados como en la image de arriba. Intenté también no usar samplerCubeShadow, pero samplerCube pero los resultados son aún peores. Primero, tengo sombras duras. Segundo, las sombras no llenan el área como deberían cuando obtienen momentos de otra textura. Mira la segunda pantalla. Aquí también se observa el map de cubos generado. No es similar a lo que está en el map de profundidad incluso si pongo depth / moment1 en los 3 canales.

Shader para get momentos:

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

Pantalla

Estoy realmente atrapado. Espero que ayudes a mi a resolver mis problemas.

EDITAR:

Encontré la solución al segundo problema. He habilitado la mezcla y me da un map de profundidad incorrecto.

También obtengo un mejor resultado al primer problema, pero ahora estoy luchando con la profundidad adecuada para compararlo con la profundidad del map de sombras.

En SM simple utilizo este código:

 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] 

donde pos es la position en View Space. Luego leo los valores del map de sombras usando:

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

En VSM, almaceno profundidad en el canal R en textura RG32F. El valor de profundidad se calcula de esta manera:

 // VS gl_Position=ModelViewProjectionMatrix*Vertex; v_position=gl_Position; // FS float depth = v_position.z/v_position.w; depth = depth * 0.5 + 0.5; 

Luego, en sombreado para la luz puntual uso el vector coord (como en SM estándar) para leer los valores del map sombra y esto funciona bien. Pero el problema está en esta parte:

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

¿En qué coorderadas debe llegar la distancia? ¿En qué coorderadas tengo profundidad desde el map de sombras? Debe ser lineal? ¿Podría alguien explicarme eso? Estoy un poco confundido ahora, probé muchas forms de get esto y todos los resultados no son como esperaba.

EDIT2: Siguiendo el consejo de JarkkoL y este tutorial, cambié mi código. Ahora estoy almacenando profundidad usando este código:

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

Y lo comparo con el valor que obtengo de esta manera:

 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 

Y aqui esta el resultado:

Pantalla3

En el círculo rojo, marqué los bordes visibles entre las caras del map del cubo. Todavía hay algo mal. Creo que podría ser algo con la inversión de View Matrix, pero no estoy seguro.

En cuanto a las juntas del map de cubos, puedes filtrar por los bordes.

Ver: glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);

En cuanto a su calidad de sombra real, el beneficio total de las técnicas de VSM y ESM proviene de la forma especial que toma la testing de visibilidad. Probablemente desee introducir un factor constante para oscurecer demasiado o poco las sombras, de modo que el borde no sea tan difícil.

Para los datos de ESM es sencillo:

 light = exp(factor * (occluder - receiver));