定向光的全向阴影
Omnidirectional shadows for directional light
当使用阴影贴图时,光投影(正交)按以下方式使用(其他行星类似):
const glm::mat4 lightProjection = glm::ortho(-saturn->GetRadius() * 3.0f, saturn->GetRadius() * 3.0f, -saturn->GetRadius() * 3.0f, saturn->GetRadius() * 3.0f, camera.GetNear(), camera.GetFar());
const glm::mat4 lightView = glm::lookAt(_sun->GetPosition(), saturn->GetPosition(), glm::vec3(0.0, 1.0, 0.0));
const glm::mat4 lightSpaceMatrix = lightProjection * lightView;
saturn->SetLightSpaceMatrix(lightSpaceMatrix);
在渲染行星时,我更改了 lightSpaceMatrix,尝试通过以下方式重新创建伪全向光(在某些方向):
void Application::RenderPlanetsAndSatellites(const Shader& shader) {
shader.Use();
for (const auto& renderableComponentPS : _renderableComponentsPS) {
shader.SetMat4("lightSpaceMatrix", renderableComponentPS.planet->GetLightSpaceMatrix());
...
renderableComponentPS.planet->SetShader(shader);
renderableComponentPS.planet->AdjustToParent(isTimeRun);
renderableComponentPS.planet->Render();
for (const auto& satellite : renderableComponentPS.satellites) {
satellite->SetShader(shader);
satellite->AdjustToParent(isTimeRun);
satellite->Render();
}
}
}
顶点着色器:
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;
out VS_OUT {
vec3 FragPos;
vec2 TexCoords;
vec3 TangentLightPos;
vec3 TangentViewPos;
vec3 TangentFragPos;
vec4 FragPosLightSpace;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform float zCoef; // For log z-buffer (2.0 / log2(farPlane + 1.0))
void main() {
vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
vs_out.TexCoords = aTexCoords;
mat3 normalMatrix = mat3(transpose(inverse(model)));
vec3 T = normalize(normalMatrix * aTangent);
vec3 N = normalize(normalMatrix * aNormal);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N, T);
mat3 TBN = transpose(mat3(T, B, N));
vs_out.TangentLightPos = TBN * lightPos;
vs_out.TangentViewPos = TBN * viewPos;
vs_out.TangentFragPos = TBN * vs_out.FragPos;
vs_out.FragPosLightSpace = lightSpaceMatrix * vec4(vs_out.FragPos, 1.0);
gl_Position = projection * view * vec4(vs_out.FragPos, 1.0f);
// Log z-buffer [логарифмический z-буфер]
gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * zCoef - 1.0;
gl_Position.z *= gl_Position.w;
}
片段着色器中的阴影计算:
float CalculateShadow(vec4 fragPosLightSpace) {
// Perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// Transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(shadowMap, projCoords.xy).r;
// Get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
vec3 lightDir = lightPos - fs_in.FragPos;
vec3 lightDirNorm = normalize(lightDir);
float shadow;
ApplyPCF(shadow, projCoords, currentDepth);
return shadow;
}
但由于某种原因,这不起作用。离太阳最近的行星似乎开始覆盖所有其他行星:
伙计们,我解决了这个问题...
想法是将一个场景组件(行星、它的卫星、光环等)渲染成阴影贴图,然后立即进入常规缓冲区,然后清除阴影贴图(深度缓冲区),这样行星离太阳最近的不会覆盖所有其他的,等等
清理是必要的,因为只使用一张阴影贴图,如果不清理,深度将被来自场景各处的对象重叠。
因此,通过改变lightSpaceMatrix,可以营造出场景中使用全向光源的印象。
当使用阴影贴图时,光投影(正交)按以下方式使用(其他行星类似):
const glm::mat4 lightProjection = glm::ortho(-saturn->GetRadius() * 3.0f, saturn->GetRadius() * 3.0f, -saturn->GetRadius() * 3.0f, saturn->GetRadius() * 3.0f, camera.GetNear(), camera.GetFar());
const glm::mat4 lightView = glm::lookAt(_sun->GetPosition(), saturn->GetPosition(), glm::vec3(0.0, 1.0, 0.0));
const glm::mat4 lightSpaceMatrix = lightProjection * lightView;
saturn->SetLightSpaceMatrix(lightSpaceMatrix);
在渲染行星时,我更改了 lightSpaceMatrix,尝试通过以下方式重新创建伪全向光(在某些方向):
void Application::RenderPlanetsAndSatellites(const Shader& shader) {
shader.Use();
for (const auto& renderableComponentPS : _renderableComponentsPS) {
shader.SetMat4("lightSpaceMatrix", renderableComponentPS.planet->GetLightSpaceMatrix());
...
renderableComponentPS.planet->SetShader(shader);
renderableComponentPS.planet->AdjustToParent(isTimeRun);
renderableComponentPS.planet->Render();
for (const auto& satellite : renderableComponentPS.satellites) {
satellite->SetShader(shader);
satellite->AdjustToParent(isTimeRun);
satellite->Render();
}
}
}
顶点着色器:
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
layout (location = 3) in vec3 aTangent;
layout (location = 4) in vec3 aBitangent;
out VS_OUT {
vec3 FragPos;
vec2 TexCoords;
vec3 TangentLightPos;
vec3 TangentViewPos;
vec3 TangentFragPos;
vec4 FragPosLightSpace;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform float zCoef; // For log z-buffer (2.0 / log2(farPlane + 1.0))
void main() {
vs_out.FragPos = vec3(model * vec4(aPos, 1.0));
vs_out.TexCoords = aTexCoords;
mat3 normalMatrix = mat3(transpose(inverse(model)));
vec3 T = normalize(normalMatrix * aTangent);
vec3 N = normalize(normalMatrix * aNormal);
T = normalize(T - dot(T, N) * N);
vec3 B = cross(N, T);
mat3 TBN = transpose(mat3(T, B, N));
vs_out.TangentLightPos = TBN * lightPos;
vs_out.TangentViewPos = TBN * viewPos;
vs_out.TangentFragPos = TBN * vs_out.FragPos;
vs_out.FragPosLightSpace = lightSpaceMatrix * vec4(vs_out.FragPos, 1.0);
gl_Position = projection * view * vec4(vs_out.FragPos, 1.0f);
// Log z-buffer [логарифмический z-буфер]
gl_Position.z = log2(max(1e-6, gl_Position.w + 1.0)) * zCoef - 1.0;
gl_Position.z *= gl_Position.w;
}
片段着色器中的阴影计算:
float CalculateShadow(vec4 fragPosLightSpace) {
// Perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// Transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// Get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(shadowMap, projCoords.xy).r;
// Get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
vec3 lightDir = lightPos - fs_in.FragPos;
vec3 lightDirNorm = normalize(lightDir);
float shadow;
ApplyPCF(shadow, projCoords, currentDepth);
return shadow;
}
但由于某种原因,这不起作用。离太阳最近的行星似乎开始覆盖所有其他行星:
伙计们,我解决了这个问题...
想法是将一个场景组件(行星、它的卫星、光环等)渲染成阴影贴图,然后立即进入常规缓冲区,然后清除阴影贴图(深度缓冲区),这样行星离太阳最近的不会覆盖所有其他的,等等
清理是必要的,因为只使用一张阴影贴图,如果不清理,深度将被来自场景各处的对象重叠。
因此,通过改变lightSpaceMatrix,可以营造出场景中使用全向光源的印象。