延迟着色中的定向阴影映射
Directional shadow mapping in deferred shading
我正在延迟着色中实现定向阴影贴图。
首先,我从光视图(正交投影)渲染深度图。
我打算做 VSM 所以上面的缓冲区是 R32G32 存储深度和深度 * 深度。
然后对于阴影的全屏着色通道(在照明通道之后),我编写了以下像素着色器:
#version 330
in vec2 texCoord; // screen coordinate
out vec3 fragColor; // output color on the screen
uniform mat4 lightViewProjMat; // lightView * lightProjection (ortho)
uniform sampler2D sceneTexture; // lit scene with one directional light
uniform sampler2D shadowMapTexture;
uniform sampler2D scenePosTexture; // store fragment's 3D position
void main() {
vec3 fragPos = texture(scenePosTexture, texCoord).xyz; // get 3D position of pixel
vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0); // project it to light-space view: lightView * lightProjection
// projective texture mapping
vec3 coord = fragPosLightSpace.xyz / fragPosLightSpace.w;
coord = coord * 0.5 + 0.5;
float lightViewDepth; // depth value in the depth buffer - the maximum depth that light can see
float currentDepth; // depth of screen pixel, maybe not visible to the light, that's how shadow mapping works
vec2 moments; // depth and depth * depth for later variance shadow mapping
moments = texture(shadowMapTexture, coord.xy).xy;
lightViewDepth = moments.x;
currentDepth = fragPosLightSpace.z;
float lit_factor = 0;
if (currentDepth <= lightViewDepth)
lit_factor = 1; // pixel is visible to the light
else
lit_factor = 0; // the light doesn't see this pixel
// I don't do VSM yet, just want to see black or full-color pixels
fragColor = texture(sceneTexture, texCoord).rgb * lit_factor;
}
渲染结果是黑屏,但是如果我硬编码lit_factor为1,结果是:
基本上这就是 sceneTexture 的样子。
所以我认为要么我的深度值错误,这不太可能,要么我的投影(上面着色器/投影纹理映射中的光 space 投影)错误。你能帮我验证一下吗?
我的阴影贴图生成代码是:
// vertex shader
#version 330 compatibility
uniform mat4 lightViewMat; // lightView
uniform mat4 lightViewProjMat; // lightView * lightProj
in vec3 in_vertex;
out float depth;
void main() {
vec4 vert = vec4(in_vertex, 1.0);
depth = (lightViewMat * vert).z / (500 * 0.2); // 500 is far value, this line tunes the depth precision
gl_Position = lightViewProjMat * vert;
}
// pixel shader
#version 330
in float depth;
out vec2 out_depth;
void main() {
out_depth = vec2(depth, depth * depth);
}
这是您存储在阴影贴图中的深度:
depth = (lightViewMat * vert).z / (500 * 0.2);
这是您将回读值与以下深度进行比较的深度:
vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0);
currentDepth = fragPosLightSpace.z;
如果 fragPos
在世界 space 中,那么我假设 lightViewMat * vert == fragPos
。您通过除以 500 * 0.2
来压缩深度,但这不等于 fragPosLightSpace.z
。
提示:写出一个通道中的 currentDepth 值和另一个通道中阴影贴图的值,然后您可以在视觉上或在 RenderDoc 或类似文件中比较它们。
内置变量 gl_FragCoord
的片段着色器的 z
组件包含 [0.0, 1.0] 范围内的深度值。这是您应该存储到深度图的值:
out_depth = vec2(gl_FragCoord.z, depth * depth);
经过计算
vec3 fragPos = texture(scenePosTexture, texCoord).xyz; // get 3D position of pixel
vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0); // project it to light-space view: lightView * lightProjection
vec3 ndc_coord = fragPosLightSpace.xyz / fragPosLightSpace.w;
变量 ndc_coord
包含标准化设备坐标,其中所有分量都在 [-1.0, 1.0] 范围内。
标准化设备坐标的z
分量可以转换为深度值(如果depth range是[0.0,1.0]),通过
float currentDepth = ndc_coord.z * 0.5 + 0.5;
这个值可以与深度图的值进行比较,因为currentDepth
和lightViewDepth
是由相同的视图矩阵和投影矩阵计算的:
moments = texture(shadowMapTexture, coord.xy).xy;
lightViewDepth = moments.x;
if (currentDepth <= lightViewDepth)
lit_factor = 1; // pixel is visible to the light
else
lit_factor = 0; // the light doesn't see this pixel
我正在延迟着色中实现定向阴影贴图。
首先,我从光视图(正交投影)渲染深度图。
我打算做 VSM 所以上面的缓冲区是 R32G32 存储深度和深度 * 深度。
然后对于阴影的全屏着色通道(在照明通道之后),我编写了以下像素着色器:
#version 330
in vec2 texCoord; // screen coordinate
out vec3 fragColor; // output color on the screen
uniform mat4 lightViewProjMat; // lightView * lightProjection (ortho)
uniform sampler2D sceneTexture; // lit scene with one directional light
uniform sampler2D shadowMapTexture;
uniform sampler2D scenePosTexture; // store fragment's 3D position
void main() {
vec3 fragPos = texture(scenePosTexture, texCoord).xyz; // get 3D position of pixel
vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0); // project it to light-space view: lightView * lightProjection
// projective texture mapping
vec3 coord = fragPosLightSpace.xyz / fragPosLightSpace.w;
coord = coord * 0.5 + 0.5;
float lightViewDepth; // depth value in the depth buffer - the maximum depth that light can see
float currentDepth; // depth of screen pixel, maybe not visible to the light, that's how shadow mapping works
vec2 moments; // depth and depth * depth for later variance shadow mapping
moments = texture(shadowMapTexture, coord.xy).xy;
lightViewDepth = moments.x;
currentDepth = fragPosLightSpace.z;
float lit_factor = 0;
if (currentDepth <= lightViewDepth)
lit_factor = 1; // pixel is visible to the light
else
lit_factor = 0; // the light doesn't see this pixel
// I don't do VSM yet, just want to see black or full-color pixels
fragColor = texture(sceneTexture, texCoord).rgb * lit_factor;
}
渲染结果是黑屏,但是如果我硬编码lit_factor为1,结果是:
基本上这就是 sceneTexture 的样子。
所以我认为要么我的深度值错误,这不太可能,要么我的投影(上面着色器/投影纹理映射中的光 space 投影)错误。你能帮我验证一下吗?
我的阴影贴图生成代码是:
// vertex shader
#version 330 compatibility
uniform mat4 lightViewMat; // lightView
uniform mat4 lightViewProjMat; // lightView * lightProj
in vec3 in_vertex;
out float depth;
void main() {
vec4 vert = vec4(in_vertex, 1.0);
depth = (lightViewMat * vert).z / (500 * 0.2); // 500 is far value, this line tunes the depth precision
gl_Position = lightViewProjMat * vert;
}
// pixel shader
#version 330
in float depth;
out vec2 out_depth;
void main() {
out_depth = vec2(depth, depth * depth);
}
这是您存储在阴影贴图中的深度:
depth = (lightViewMat * vert).z / (500 * 0.2);
这是您将回读值与以下深度进行比较的深度:
vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0);
currentDepth = fragPosLightSpace.z;
如果 fragPos
在世界 space 中,那么我假设 lightViewMat * vert == fragPos
。您通过除以 500 * 0.2
来压缩深度,但这不等于 fragPosLightSpace.z
。
提示:写出一个通道中的 currentDepth 值和另一个通道中阴影贴图的值,然后您可以在视觉上或在 RenderDoc 或类似文件中比较它们。
内置变量 gl_FragCoord
的片段着色器的 z
组件包含 [0.0, 1.0] 范围内的深度值。这是您应该存储到深度图的值:
out_depth = vec2(gl_FragCoord.z, depth * depth);
经过计算
vec3 fragPos = texture(scenePosTexture, texCoord).xyz; // get 3D position of pixel
vec4 fragPosLightSpace = lightViewProjMat * vec4(fragPos, 1.0); // project it to light-space view: lightView * lightProjection
vec3 ndc_coord = fragPosLightSpace.xyz / fragPosLightSpace.w;
变量 ndc_coord
包含标准化设备坐标,其中所有分量都在 [-1.0, 1.0] 范围内。
标准化设备坐标的z
分量可以转换为深度值(如果depth range是[0.0,1.0]),通过
float currentDepth = ndc_coord.z * 0.5 + 0.5;
这个值可以与深度图的值进行比较,因为currentDepth
和lightViewDepth
是由相同的视图矩阵和投影矩阵计算的:
moments = texture(shadowMapTexture, coord.xy).xy;
lightViewDepth = moments.x;
if (currentDepth <= lightViewDepth)
lit_factor = 1; // pixel is visible to the light
else
lit_factor = 0; // the light doesn't see this pixel