He implementado el mapeo básico de sombras por primera vez en OpenGL usando sombreadores y estoy enfrentando algunos problemas. A continuación puede ver un ejemplo de mi escena renderizada:
El proceso del mapeo de sombras que estoy siguiendo es que renderizo la escena al framebuffer usando una matriz de vista desde el punto de vista de la luz y las matrices de proyección y modelo utilizadas para el renderizado normal.
En la segunda pasada, envío la matriz MVP anterior desde el punto de vista de la luz al sombreador de vértices que transforma la posición en espacio de luz. El sombreador de fragmentos divide la perspectiva y cambia la posición a coordenadas de textura.
Aquí está mi sombreador de vértices,
#version 150 core
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 MVPMatrix;
uniform mat4 lightMVP;
uniform float scale;
in vec3 in_Position;
in vec3 in_Normal;
in vec2 in_TexCoord;
smooth out vec3 pass_Normal;
smooth out vec3 pass_Position;
smooth out vec2 TexCoord;
smooth out vec4 lightspace_Position;
void main(void){
pass_Normal = NormalMatrix * in_Normal;
pass_Position = (ModelViewMatrix * vec4(scale * in_Position, 1.0)).xyz;
lightspace_Position = lightMVP * vec4(scale * in_Position, 1.0);
TexCoord = in_TexCoord;
gl_Position = MVPMatrix * vec4(scale * in_Position, 1.0);
}
Y mi sombreador de fragmentos,
#version 150 core
struct Light{
vec3 direction;
};
uniform Light light;
uniform sampler2D inSampler;
uniform sampler2D inShadowMap;
smooth in vec3 pass_Normal;
smooth in vec3 pass_Position;
smooth in vec2 TexCoord;
smooth in vec4 lightspace_Position;
out vec4 out_Color;
float CalcShadowFactor(vec4 lightspace_Position){
vec3 ProjectionCoords = lightspace_Position.xyz / lightspace_Position.w;
vec2 UVCoords;
UVCoords.x = 0.5 * ProjectionCoords.x + 0.5;
UVCoords.y = 0.5 * ProjectionCoords.y + 0.5;
float Depth = texture(inShadowMap, UVCoords).x;
if(Depth < (ProjectionCoords.z + 0.001)) return 0.5;
else return 1.0;
}
void main(void){
vec3 Normal = normalize(pass_Normal);
vec3 light_Direction = -normalize(light.direction);
vec3 camera_Direction = normalize(-pass_Position);
vec3 half_vector = normalize(camera_Direction + light_Direction);
float diffuse = max(0.2, dot(Normal, light_Direction));
vec3 temp_Color = diffuse * vec3(1.0);
float specular = max( 0.0, dot( Normal, half_vector) );
float shadowFactor = CalcShadowFactor(lightspace_Position);
if(diffuse != 0 && shadowFactor > 0.5){
float fspecular = pow(specular, 128.0);
temp_Color += fspecular;
}
out_Color = vec4(shadowFactor * texture(inSampler, TexCoord).xyz * temp_Color, 1.0);
}
Uno de los problemas es el auto sombreado, como puede ver en la imagen, la caja tiene su propia sombra proyectada sobre sí misma. Lo que he intentado es habilitar el desplazamiento del polígono (es decir, glEnable (POLYGON_OFFSET_FILL), glPolygonOffset (GLfloat, GLfloat)) pero no cambió mucho. Como puede ver en el sombreador de fragmentos, puse un valor de desplazamiento estático de 0.001 pero tengo que cambiar el valor dependiendo de la distancia de la luz para obtener efectos más deseables, lo que no es muy útil. También intenté usar el sacrificio de la cara frontal cuando renderizo al framebuffer, eso tampoco cambió mucho.
El otro problema es que los píxeles fuera del tronco de la vista de la Luz se sombrean. El único objeto que se supone que puede proyectar sombras es la caja. Supongo que debería elegir una proyección más apropiada y ver matrices, pero no estoy seguro de cómo hacerlo. ¿Cuáles son algunas prácticas comunes, debo elegir una proyección ortográfica?
Al buscar en Google un poco, entiendo que estos problemas no son tan triviales. ¿Alguien tiene alguna solución fácil de implementar para estos problemas? ¿Me podría dar algunos consejos adicionales?
Pregúnteme si necesita más información sobre mi código.
Aquí hay una comparación con y sin mapeo de sombras de un primer plano de la caja. El auto-sombreado es más visible.