从深度纹理采样总是结果为 0
Sampling from depth texture always results 0
我正在尝试使用 opengl 和定向光实现阴影贴图。
我已确认深度纹理已正确渲染,如下所示:
为了进行视觉检查,我还输出了世界 space 坐标,转换为光透视:
又一次,似乎没问题。
然而,当我对深度纹理进行采样时,使用:
vec3 coord = vec3(shadowCoords.xy,shadowCoords.z/shadowCoords.w);
float depth = texture( shadowMap, coord);
我发现比较总是失败。如果我将 uniform sampler2DShadow shadowMap;
更改为 uniform sampler2D shadowMap;
,并直接使用 texture( shadowMap, coord.xy).r
对纹理进行采样,我发现采样值始终为零,将此结果输出到屏幕。
我是这样创建深度纹理的:
glGenTextures(1, &m_DepthTexture);
glBindTexture(GL_TEXTURE_2D, m_DepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_DepthTexture, 0);
我的着色器代码如下(顶点):
#version 430
// Some drivers require the following
precision highp float;
layout (location = 0)in vec3 MSVertex;
layout (location = 4)in vec2 MSTexCoord;
out xferBlock
{
vec3 VSVertex;
vec2 VSTexCoord;
} outdata;
void main()
{
outdata.VSVertex = MSVertex;
outdata.VSTexCoord = MSTexCoord;
gl_Position = vec4(MSVertex,1.0);
}
和片段着色器:
#version 430 core
// Some drivers require the following
precision highp float;
layout (location = 0) uniform sampler2D positionMap;
layout (location = 1) uniform sampler2D normalMap;
layout (location = 2) uniform sampler2D colourMap;
layout (location = 3) uniform sampler2D specularMap;
layout (location = 4) uniform sampler2DShadow shadowMap;
struct DirLightData
{
vec4 colour;
float intensity;
vec4 direction;
};
uniform mat4 ShadowTransform;
uniform DirLightData dirLight;
out vec4 colour;
uniform vec3 WSCamPos;
in xferBlock
{
vec3 VSVertex;
vec2 VSTexCoord;
} indata;
vec3 computeLight(vec3 Ldirection, vec3 Vdirection, vec3 Lcolour, vec3 normal, float Lintensity, float specular)
{
vec3 diffCol = Lcolour * max(0.0,dot(normalize(normal),-Ldirection));
vec3 reflectVec = normalize(reflect(Ldirection,normal));
float specFactor = max(dot(reflectVec,Vdirection),0);
float specPow = pow(specFactor,specular*255.0);
vec3 specCol = Lcolour * specPow;
return (diffCol+specCol)*Lintensity;;
}
float computeOcclusion(vec4 shadowCoords)
{
float vis = 1.0;
vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.05));
if ( depth < coord.z);
{
vis = 0.5;
}
return vis;
}
void main()
{
vec4 pcolour = texture(positionMap, indata.VSTexCoord).rgba;
vec4 ncolour = texture(normalMap, indata.VSTexCoord).rgba;
vec4 dcolour = texture(colourMap, indata.VSTexCoord).rgba;
vec4 scolour = texture(specularMap, indata.VSTexCoord).rgba;
vec4 shadowCoord = ShadowTransform * pcolour;
float visibility = computeOcclusion( shadowCoord );
//float depth = texture(shadowMap, shadowCoord.xy).z;
vec3 vToEye = WSCamPos - pcolour.xyz;
vToEye = normalize(vToEye);
vec3 outColour = vec3(0.0,0.0,0.0);
outColour = computeLight(dirLight.direction.xyz,vToEye,dirLight.colour.rgb,ncolour.rgb,dirLight.intensity,scolour.r);
colour = vec4(visibility*(dcolour.rgb*outColour),1.0);
}
谁能找出问题所在?
此类问题很难发现,因此您需要注意以下几点:
您使用的 samplerShadow
有其独特之处,您需要设置 COMPARE_R_TO_TEXTURE
而您不需要 if
陈述。或者你可以使用 sampler2D
,但你需要在着色器中做一个 if
语句,类似于你所做的,但坐标必须是 vec2
而不是 vec3
考虑使用 textureProj
和 vec4
纹理坐标。因为使用矩阵乘法在光线 space 中转换世界位置要容易得多。它与您最初用于渲染阴影贴图的矩阵相同。在你的例子中是这个值 vec4 shadowCoord = ShadowTransform * pcolour;
;将 shadowCoord
直接用于 textureProj
.
事实证明我的采样 return 是正确的值。
真正的问题是由于在渲染深度贴图时剔除几何体的背面,以及错误地处理深度纹理采样中的 return 值而导致的非常细粒度的阴影痤疮。
我把采样函数改成了:
float computeOcclusion(vec4 shadowCoords)
{
vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.001));
return depth;
}
并更改了我的深度渲染 gl 客户端代码以包括:
glCullFace(GL_FRONT);
在将几何图形渲染到 shadowMap 之前。
完成后,我得到以下结果:
还有一些彼得平移问题,但这是我可以单独处理的问题。
我正在尝试使用 opengl 和定向光实现阴影贴图。
我已确认深度纹理已正确渲染,如下所示:
为了进行视觉检查,我还输出了世界 space 坐标,转换为光透视:
又一次,似乎没问题。
然而,当我对深度纹理进行采样时,使用:
vec3 coord = vec3(shadowCoords.xy,shadowCoords.z/shadowCoords.w);
float depth = texture( shadowMap, coord);
我发现比较总是失败。如果我将 uniform sampler2DShadow shadowMap;
更改为 uniform sampler2D shadowMap;
,并直接使用 texture( shadowMap, coord.xy).r
对纹理进行采样,我发现采样值始终为零,将此结果输出到屏幕。
我是这样创建深度纹理的:
glGenTextures(1, &m_DepthTexture);
glBindTexture(GL_TEXTURE_2D, m_DepthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_DepthTexture, 0);
我的着色器代码如下(顶点):
#version 430
// Some drivers require the following
precision highp float;
layout (location = 0)in vec3 MSVertex;
layout (location = 4)in vec2 MSTexCoord;
out xferBlock
{
vec3 VSVertex;
vec2 VSTexCoord;
} outdata;
void main()
{
outdata.VSVertex = MSVertex;
outdata.VSTexCoord = MSTexCoord;
gl_Position = vec4(MSVertex,1.0);
}
和片段着色器:
#version 430 core
// Some drivers require the following
precision highp float;
layout (location = 0) uniform sampler2D positionMap;
layout (location = 1) uniform sampler2D normalMap;
layout (location = 2) uniform sampler2D colourMap;
layout (location = 3) uniform sampler2D specularMap;
layout (location = 4) uniform sampler2DShadow shadowMap;
struct DirLightData
{
vec4 colour;
float intensity;
vec4 direction;
};
uniform mat4 ShadowTransform;
uniform DirLightData dirLight;
out vec4 colour;
uniform vec3 WSCamPos;
in xferBlock
{
vec3 VSVertex;
vec2 VSTexCoord;
} indata;
vec3 computeLight(vec3 Ldirection, vec3 Vdirection, vec3 Lcolour, vec3 normal, float Lintensity, float specular)
{
vec3 diffCol = Lcolour * max(0.0,dot(normalize(normal),-Ldirection));
vec3 reflectVec = normalize(reflect(Ldirection,normal));
float specFactor = max(dot(reflectVec,Vdirection),0);
float specPow = pow(specFactor,specular*255.0);
vec3 specCol = Lcolour * specPow;
return (diffCol+specCol)*Lintensity;;
}
float computeOcclusion(vec4 shadowCoords)
{
float vis = 1.0;
vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.05));
if ( depth < coord.z);
{
vis = 0.5;
}
return vis;
}
void main()
{
vec4 pcolour = texture(positionMap, indata.VSTexCoord).rgba;
vec4 ncolour = texture(normalMap, indata.VSTexCoord).rgba;
vec4 dcolour = texture(colourMap, indata.VSTexCoord).rgba;
vec4 scolour = texture(specularMap, indata.VSTexCoord).rgba;
vec4 shadowCoord = ShadowTransform * pcolour;
float visibility = computeOcclusion( shadowCoord );
//float depth = texture(shadowMap, shadowCoord.xy).z;
vec3 vToEye = WSCamPos - pcolour.xyz;
vToEye = normalize(vToEye);
vec3 outColour = vec3(0.0,0.0,0.0);
outColour = computeLight(dirLight.direction.xyz,vToEye,dirLight.colour.rgb,ncolour.rgb,dirLight.intensity,scolour.r);
colour = vec4(visibility*(dcolour.rgb*outColour),1.0);
}
谁能找出问题所在?
此类问题很难发现,因此您需要注意以下几点:
您使用的
samplerShadow
有其独特之处,您需要设置COMPARE_R_TO_TEXTURE
而您不需要if
陈述。或者你可以使用sampler2D
,但你需要在着色器中做一个if
语句,类似于你所做的,但坐标必须是vec2
而不是vec3
考虑使用
textureProj
和vec4
纹理坐标。因为使用矩阵乘法在光线 space 中转换世界位置要容易得多。它与您最初用于渲染阴影贴图的矩阵相同。在你的例子中是这个值vec4 shadowCoord = ShadowTransform * pcolour;
;将shadowCoord
直接用于textureProj
.
事实证明我的采样 return 是正确的值。
真正的问题是由于在渲染深度贴图时剔除几何体的背面,以及错误地处理深度纹理采样中的 return 值而导致的非常细粒度的阴影痤疮。
我把采样函数改成了:
float computeOcclusion(vec4 shadowCoords)
{
vec3 coord = vec3(shadowCoords.xyz/shadowCoords.w);
float depth = texture( shadowMap, vec3(coord.xy,coord.z+0.001));
return depth;
}
并更改了我的深度渲染 gl 客户端代码以包括:
glCullFace(GL_FRONT);
在将几何图形渲染到 shadowMap 之前。
完成后,我得到以下结果:
还有一些彼得平移问题,但这是我可以单独处理的问题。