Я не могу получить отображение теней для работы в моем приложении. Я пытаюсь сделать квадроцикл и посмотреть его тень на полу под ним.
Вот немного моего кода.
Создание текстуры:
// Create a depth texture
glGenTextures(1, &depth_texture);
glBindTexture(GL_TEXTURE_2D, depth_texture);
// Allocate storage for the texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32 ,1600, 900, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
// Set the default filtering modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Set up wrapping modes
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
// Create FBO to render depth into
glGenFramebuffers(1, &depth_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
// Attach the depth texture to it
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
depth_texture, 0);
// Disable color rendering as there are no color attachments
glDrawBuffer(GL_NONE);
//check fbo status
GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(result != GL_FRAMEBUFFER_COMPLETE)
throw std::runtime_error("shadow mapping framebuffer error");
//bind default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
отрендерить до глубины текстуру:
progShadow.Use();
glBindFramebuffer(GL_FRAMEBUFFER, depth_fbo);
glClear(GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowProjection = glm::frustum(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 100.0f);
glm::mat4 shadowView = glm::lookAt(light.position, glm::vec3(0,0,0), glm::vec3(0,1,0));
glm::mat4 shadowModel(1);
if(g_rotate)
shadowModel = glm::rotate((float)clock() / (float)CLOCKS_PER_SEC, glm::vec3(0,1,0));
glm::mat4 shadowMVP = shadowProjection * shadowView * shadowModel;
progShadow.SetUniform("MVPMatrix", shadowMVP);
quadBike.Draw();
Я также использую «тестовую» шейдерную программу, которая визуализирует мою текстуру глубины. Вот как это выглядит.
Так что, думаю, я в порядке до сих пор.
Теперь я отрисовываю сцену нормально.
glBindTexture(GL_TEXTURE_2D, depth_texture);
prog.Use();//main program
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 shadowBias = glm::mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
glm::mat4 ShadowBiasMVP = shadowBias * shadowMVP;
prog.SetUniform("ShadowBiasMVP", ShadowBiasMVP);
//draw quadBike and floor
...
Соответствующие части моего вершинного шейдера:
#version 430
...
out vec4 shadowCoord;
void main()
{
gl_Position = ProjectionMatrix * CameraMatrix * ModelMatrix * vec4(vertex, 1.0);
shadowCoord = ShadowBiasMVP * vec4(vertex, 1.0);
...
}
Соответствующие части моего фрагмента шейдера:
#version 430
...
uniform sampler2D shadowMap;
in vec4 shadowCoord;
void main()
{
...
float visibility = 1.0;
if ( texture(shadowMap, shadowCoord.xy).z < shadowCoord.z)
visibility = 0.0;
...
}
Теперь проблема в том, что я получаю полностью темную сцену, как если бы она была покрыта тенью. Только когда свет действительно близко к квадроциклу, он делает это нормально. (Текстура глубины видна с правой стороны, потому что она отображается другой программой. Я использую ее для тестирования)
Что я делаю неправильно?
Вы должны прочитать текстуру глубины серого в первом компоненте.
texture(shadowMap, shadowCoord.xy).r
или же
texture(shadowMap, shadowCoord.xy).x
Теневые координаты должны быть дегомогенизированы (разделены на w) после интерполяции.
-> во фрагментном шейдере: shadowPos = shadowPos/shadowPos.w;
Если никакие другие методы, такие как смещение многоугольника, не используются, вам нужно вычесть смещение из значения глубины тени, чтобы предотвратить самозатенение.
Вот пример функции для вычисления теней во фрагментном шейдере. Примечание: это часть отложенного рендеринга, поэтому умножение матриц выполняется в фрагментном шейдере.
float calculateShadow(vec3 position){
vec4 shadowPos = depthBiasMV * vec4(position,1);
shadowPos = shadowPos/shadowPos.w;float bias = 0.0012;
float visibility = 1.0f;
if ((shadowPos.x < 0 || shadowPos.x > 1 || shadowPos.y < 0 || shadowPos.y > 1 || shadowPos.z < 0 || shadowPos.z > 1)){
visibility = 1.0f;
}else{
float shadowDepth = texture(depthTex, shadowPos.xy).r;
if(shadowDepth<shadowPos.z-bias)
visibility = 0.0f;
}
return visibility;
}