В моей реализации карты теней для направленных источников света у меня есть коллекция элементов, которые я повторяю для отображения их глубины в буфере глубины, а затем повторяю их снова для нормального отображения с помощью сгенерированной карты теней, каждый элемент имеет bool
свойство называется castShadow
который я проверяю, если true, добавьте его в буфер глубины, проблема в том, что если элемент отбрасывает тень и визуализируется в буфер глубины, он вообще не может получать тени, как только я установил в false значение, тогда он не будет отображаться при глубине начала получать тени без проблем.
поэтому в функции рендеринга сначала я визуализирую буфер глубины следующим образом:
Когда объект отбрасывает тень, он не получает тени
Когда объект не отбрасывает тень, он получает тени
void Engine::renderDepthMaps() {
if (sun != nullptr) {
if (sun->castShadow) {
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO);
glClear(GL_DEPTH_BUFFER_BIT);
glm::vec3 pos = -500.0f * sun->direction;
glm::mat4 lightSpaceProjection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 1000.0f);
glm::mat4 lightSpaceView = glm::lookAt(pos, player->getPosition(), glm::vec3(0, 1, 0));
lightSpaceMatrix = lightSpaceProjection * lightSpaceView;
Shader& shader = shaders.getShader(DEPTH);
shader.use();
shaders.setDepthLightSpaceUniform(shader, lightSpaceMatrix);
for (item_it it = engineItems.begin(); it != engineItems.end(); ++it) {
if (it->get()->castShadow)
it->get()->renderDepth(deltaFirst);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
}
и функция рендеринга:
void Engine::renderMeshes() {
glViewport(0, 0, width, height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Shader& basicShader = shaders.getShader(BASIC);
basicShader.use();
sun->setUniforms(basicShader.getProgramID(), "directLights");
shaders.setLightSpaceUniform(basicShader, sun, lightSpaceMatrix, depthMap);
shaders.setShaderViewUniforms(basicShader, camera);
terrain->render(basicShader, deltaFirst);
for (item_it it = basicItems.begin(); it != basicItems.end(); ++it) {
if (it->get()->type != "terrain")
it->get()->render(basicShader, deltaFirst);
}
}
и шейдеры:
вершина:
#version 300 es
precision highp float;
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform mat4 lightSpaceMatrix;
uniform mat3 normalMatrix;
out vec4 FragPosLightSpace;
out vec2 TexCoords;
out vec3 Normal;
out vec3 viewPos;
out vec3 fragPos;
void main(){
TexCoords = texCoord;
Normal=normalMatrix*normal;
fragPos = vec3(model * vec4(position,1.0f));
FragPosLightSpace =lightSpaceMatrix * model * vec4(position,1.0f);
gl_Position = projection * view * model * vec4(position,1.0f);
}
фрагмент:
#version 300 es
precision highp float;
out vec4 glFragColor;
vec2 poissonDisk[4] = vec2[](
vec2( -0.94201624, -0.39906216 ),
vec2( 0.94558609, -0.76890725 ),
vec2( -0.094184101, -0.92938870 ),
vec2( 0.34495938, 0.29387760 )
);
struct DirectLight {
vec3 direction;
vec3 color;
float intensity;
};
in vec3 Normal;
in vec2 TexCoords;
in vec3 fragPos;
in vec4 FragPosLightSpace;
uniform int has_texture;
uniform vec3 matDiffuse;
uniform sampler2D shadowMap;
uniform sampler2D mat_diffuse;
uniform sampler2D mat_specular;
uniform vec3 matSpecular;
uniform float shininess;
uniform DirectLight sun;
uniform int castShadow;
uniform vec3 viewPos;
void main(){
vec3 tex=vec3(1),spe=vec3(1);
if(has_texture==1){
tex=vec3(texture(mat_diffuse, TexCoords));
spe=vec3(texture(mat_specular,TexCoords));
}
vec3 diffColor = matDiffuse * tex;
vec3 specColor = matSpecular * spe;
vec3 ambient = vec3(0.4,0.4,0.4)*diffColor;
vec3 lightDir = normalize(-sun.direction);
float diff = max(dot(Normal,lightDir), 0.0);
vec3 diffuse = sun.color * diff * diffColor;
vec3 viewDir = normalize(viewPos - fragPos);
vec3 reflectDir = reflect(-lightDir, Normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), shininess);
vec3 specular = spec * specColor * sun.color;
vec3 color = ambient + diffuse + specular;
float gamma = 2.2;
color.rgb = pow(color.rgb, vec3(1.0/gamma));
if(castShadow==1){
vec3 projCoords = FragPosLightSpace.xyz / FragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
float shadow = 1.0;
for (int i=0;i<4;i++){
shadow -= 0.2*(1.0-texture( shadowMap, projCoords.xy + poissonDisk[i]/700.0).r);
}
if(projCoords.z > 1.0)
shadow = 0.0;
color *=shadow;
}
glFragColor=vec4(color,1.0f);
}
Другая проблема: светлая космическая перспективная матрица glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, -10.0f, 1000.0f)
и размер карты теней равен 1024, когда объект находится за пределами этой матрицы, он создает очень длинную тень и имеет неправильное направление, как показано на следующем рисунке:
Задача ещё не решена.
Других решений пока нет …