我在延迟的OpenGL 4.3渲染器中为聚光灯进行阴影映射。
我一直在尝试遵循该主题的一些教程,并在此之后通过片段着色器进行建模,但是我不理解的是用于计算阴影因子的最终比较。我从深度图(“ unifShadowTexture
”)采样的值在[0,1]范围内,因为它直接来自深度缓冲区,但是如何projCoords.z
钳制到[0,1]?是通过将其.w
钳位到[0,1]进行除法吗?我面临的问题是,即使不应该遮挡场景的主要部分,例如下图中的一楼(由于没有偏见,也请忽略光线伪影-重要的是型号已点亮,但底层没有):
const std::string gDirLightFragmentShader =
"#version 430 \n \
\n \
layout(std140) uniform; \n \
\n \
uniform UnifDirLight \n \
{ \n \
mat4 mWVPMatrix; \n \
mat4 mVPMatrix; // light view-projection matrix, pre-multiplied by the bias-matrix \n \
vec4 mLightColor; \n \
vec4 mLightDir; \n \
vec4 mGamma; \n \
vec2 mScreenSize; \n \
} UnifDirLightPass; \n \
\n \
layout (binding = 2) uniform sampler2D unifPositionTexture; \n \
layout (binding = 3) uniform sampler2D unifNormalTexture; \n \
layout (binding = 4) uniform sampler2D unifDiffuseTexture; \n \
layout (binding = 5) uniform sampler2D unifShadowTexture; \n \
\n \
out vec4 fragColor; \n \
\n \
void main() \n \
{ \n \
vec2 texcoord = gl_FragCoord.xy / UnifDirLightPass.mScreenSize; \n \
\n \
vec3 worldPos = texture(unifPositionTexture, texcoord).xyz; \n \
vec3 normal = normalize(texture(unifNormalTexture, texcoord).xyz); \n \
vec3 diffuse = texture(unifDiffuseTexture, texcoord).xyz; \n \
\n \
vec4 lightClipPos = UnifDirLightPass.mVPMatrix * vec4(worldPos, 1.0); \n \
vec3 projCoords = lightClipPos.xyz / lightClipPos.w; \n \
\n \
float depthValue = texture(unifShadowTexture, projCoords.xy).x; \n \
float visibilty = 1.0; \n \
if (depthValue < (projCoords.z)) \n \
visibilty = 0.0; \n \
\n \
float angleNormal = clamp(dot(normal, UnifDirLightPass.mLightDir.xyz), 0, 1); \n \
\n \
fragColor = vec4(diffuse, 1.0) * visibilty * angleNormal * UnifDirLightPass.mLightColor; \n \
} \n";
The division by w
by itself will not clamp it to [0,1]. Technically what you have are clip-space coordinates, and then division by w
transforms them into NDC space. Any point x, y, or z that is < -w or > w is clipped when this operation is performed on geometry. However, when you do it on your texture coordinates you still need to provide an appropriate texture wrap mode (usually GL_CLAMP_TO_EDGE
), because the coordinates are not clamped automatically.
Note that all points that project beyond your shadow map's far plane will exhibit the same behavior since the coordinates are clamped. Usually this manifests itself as everything beyond a certain distance being fully in shadow. This is why you want to match your shadow map's frustum more closely with your attenuated light volume.
Also, in this situation a sampler2DShadow
makes a lot of sense...
float depthValue = texture(unifShadowTexture, projCoords.xy).x;
float visibilty = 1.0;
if (depthValue < (projCoords.z))
visibilty = 0.0;
float visibility = texture (unifShadowTexture, projCoords);
unifShadowTexture
as sampler2DShadow
GL_TEXTURE_COMPARE_MODE
to GL_COMPARE_R_TO_TEXTURE
for your depth textureThis works because for sampler2DShadow
, it requires 3D texture coordinates. s
and t
work as usual, and r
is the value it uses for comparison. The default comparison function is GL_LESS
, so you do not have to change anything in your code. Given a GL_NEAREST
texture function, the return of this will be either 1.0 or 0.0. It will produce exactly the same as your code snippet above, but using a hardware feature for the actual depth test and will often improve performance and get you inexpensive PCF if you enable GL_LINEAR
.
但是,我建议您向纹理坐标的Z分量添加一个偏差。像(0.001)之类的东西,或者您会得到很多“粉刺痤疮”,偏见太高,您会得到“ peting panning”(阴影似乎悬停在它们所附着的物体之上)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句