Eu implementei o mapeamento básico de sombra pela primeira vez no OpenGL usando shaders e estou enfrentando alguns problemas. Abaixo você pode ver um exemplo da minha cena renderizada:
O processo do mapeamento de sombra que estou seguindo é que eu renderizo a cena para o framebuffer usando uma View Matrix do ponto de vista da luz e as matrizes de projeção e modelo usadas para renderização normal.
Na segunda passagem, envio a matriz MVP acima do ponto de vista da luz para o shader de vértice que transforma a posição no espaço da luz. O sombreador de fragmento divide a perspectiva e altera a posição para coordenar as texturas.
Aqui está o meu vertex shader,
#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);
}
E meu fragmento shader,
#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);
}
Um dos problemas é a auto-sombreamento, como você pode ver na figura, a caixa tem sua própria sombra projetada sobre si mesma. O que tentei é ativar o deslocamento de polígono (por exemplo, glEnable (POLYGON_OFFSET_FILL), glPolygonOffset (GLfloat, GLfloat)), mas não mudou muito. Como você vê no shader de fragmento, coloquei um valor de deslocamento estático de 0,001, mas preciso alterar o valor dependendo da distância da luz para obter efeitos mais desejáveis, o que não é muito útil. Também tentei usar o abate da face frontal quando renderizo ao buffer de moldura, isso também não mudou muito.
O outro problema é que os pixels fora do campo de visão do Light ficam sombreados. O único objeto que deve ser capaz de projetar sombras é o caixote. Acho que devo escolher uma projeção mais apropriada e visualizar matrizes, mas não tenho certeza de como fazer isso. Quais são algumas práticas comuns, devo escolher uma projeção ortográfica?
Ao pesquisar um pouco, entendo que esses problemas não são tão triviais. Alguém tem fácil de implementar soluções para esses problemas. Você poderia me dar algumas dicas adicionais?
Por favor, pergunte-me se você precisar de mais informações sobre o meu código.
Aqui está uma comparação com e sem o mapeamento de sombra de um close da caixa. A auto-sombra é mais visível.