我已经实现了基本的阴影映射算法,但它只能正确处理一个光源。
我想渲染带有以下两个点光源的场景:
- Light_1 - 位置:vec3(-8.0f,5.0f,8.0f),方向:vec3(1.3f,-1.0f,-1.0f) - Light_2 - 位置:vec3(8.0f,5.0f,8.0f),方向:vec3(1.3f,-1.0f,-1.0f)
如果我分别渲染这两个灯光,我会得到以下结果:
使用Light_1进行渲染:
[图片]
使用Light_2进行渲染:
[图片]
但同时渲染两个灯光时情况如下:
[图片]
可以看出第一个阴影似乎被正确渲染,但它在light_2的阴影之下,这是不正确的。总之,我的盒子纹理绑定到纹理单元0。阴影深度纹理从纹理单元1绑定,如果有多个深度纹理(例如此示例中至少两个光源),则将其绑定到纹理单元1 + 1(GL_TEXTURE1 + 1)。下面是代表我说的代码:
顶点着色器如下(适用于仅两个光源):
似乎是一个纹理单元的问题,因为两个阴影分别渲染得很完美,而且我认为我正确使用了glActiveTexture。此外,我注意到如果改变灯光的加载顺序,不良阴影是由“另一个灯光”引起的(相反也一样)。所以似乎来自纹理单元2,但我不明白为什么。请问有人可以帮忙吗?非常感谢您的帮助。
我想渲染带有以下两个点光源的场景:
- Light_1 - 位置:vec3(-8.0f,5.0f,8.0f),方向:vec3(1.3f,-1.0f,-1.0f) - Light_2 - 位置:vec3(8.0f,5.0f,8.0f),方向:vec3(1.3f,-1.0f,-1.0f)
如果我分别渲染这两个灯光,我会得到以下结果:
使用Light_1进行渲染:
[图片]
使用Light_2进行渲染:
[图片]
但同时渲染两个灯光时情况如下:
[图片]
可以看出第一个阴影似乎被正确渲染,但它在light_2的阴影之下,这是不正确的。总之,我的盒子纹理绑定到纹理单元0。阴影深度纹理从纹理单元1绑定,如果有多个深度纹理(例如此示例中至少两个光源),则将其绑定到纹理单元1 + 1(GL_TEXTURE1 + 1)。下面是代表我说的代码:
for (int idy = 0; idy < this->m_pScene->getLightList().size(); idy++)
[...]
Light *light = this->m_pScene->getLightList()[idy];
FrameBuffer *frameBuffer = light->getFrameBuffer();
glActiveTexture(GL_TEXTURE1 + idy);
glBindTexture(GL_TEXTURE_2D, frameBuffer->getTexture()->getTextureId()); //To unbind
shaderProgram->setUniform(std::string("ShadowMatrix[").append(Convertor::toString<int> (idy)).append("]").c_str(), this->m_pScene->getLightList()[idy]->getBiasViewPerspectiveMatrix() * modelMatrix);
shaderProgram->setUniform(std::string("ShadowMap[").append(Convertor::toString<int>(idy)).append("]").c_str(), (int)idy + 1);
在我们的情况下,它对应于:
shaderProgram->setUniform("ShadowMatrix[0]", <shadow_matrix_light_1>);
shaderProgram->setUniform("ShadowMap[0]", 1); (GL_TEXTURE1)
shaderProgram->setUniform("ShadowMatrix[1]", <shadow_matrix_light_2>);
shaderProgram->setUniform("ShadowMap[1]", 2); (GL_TEXTURE2)
顶点着色器如下(适用于仅两个光源):
#version 400
#define MAX_SHADOW_MATRIX 10
#define MAX_SHADOW_COORDS 10
layout (location = 0) in vec4 VertexPosition;
layout (location = 1) in vec3 VertexNormal;
layout (location = 2) in vec2 VertexTexture;
uniform mat3 NormalMatrix;
uniform mat4 ModelViewMatrix;
uniform mat4 ShadowMatrix[MAX_SHADOW_MATRIX];
uniform mat4 MVP;
uniform int lightCount;
out vec3 Position;
out vec3 Normal;
out vec2 TexCoords;
out vec4 ShadowCoords[MAX_SHADOW_COORDS];
void main(void)
{
TexCoords = VertexTexture;
Normal = normalize(NormalMatrix * VertexNormal);
Position = vec3(ModelViewMatrix * VertexPosition);
for (int idx = 0; idx < lightCount; idx++)
ShadowCoords[idx] = ShadowMatrix[idx] * VertexPosition;
gl_Position = MVP * VertexPosition;
}
以下是片段着色器的一部分代码:
[...]
vec3 evalBasicFragmentShadow(vec3 LightIntensity, int idx)
{
vec3 Ambient = LightInfos[idx].La * MaterialInfos.Ka;
if (ShadowCoords[idx].w > 0.0f)
{
vec4 tmp_shadow_coords = ShadowCoords[idx];
tmp_shadow_coords.z -= SHADOW_OFFSET;
float shadow = textureProj(ShadowMap[idx], tmp_shadow_coords);
LightIntensity = LightIntensity * shadow + Ambient;
}
else
{
LightIntensity = LightIntensity + MaterialInfos.Ka;
}
return (LightIntensity);
}
vec3 getLightIntensity(vec3 TexColor)
{
vec3 LightIntensity = vec3(0.0f);
for (int idx = 0; idx < lightCount; idx++)
{
vec3 tnorm = (gl_FrontFacing ? -normalize(Normal) : normalize(Normal));
vec3 lightDir = vec3(LightInfos[idx].Position) - Position;
vec3 lightDirNorm = normalize(lightDir);
float lightAtt = getLightAttenuation(lightDir, LightInfos[idx]);
LightIntensity += Point_ADS_Shading(lightAtt, -tnorm, lightDirNorm, TexColor, idx);
LightIntensity = evalBasicFragmentShadow(LightIntensity, idx);
}
return (LightIntensity);
}
[...]
似乎是一个纹理单元的问题,因为两个阴影分别渲染得很完美,而且我认为我正确使用了glActiveTexture。此外,我注意到如果改变灯光的加载顺序,不良阴影是由“另一个灯光”引起的(相反也一样)。所以似乎来自纹理单元2,但我不明白为什么。请问有人可以帮忙吗?非常感谢您的帮助。
vec4(VertexPosition, 1.0f)
,一开始声明VertexPosition
为vec4
就可以了。如果你的glVertexAttribPointer(...)
函数调用只提供了足够的 XYZ 数据,那么 GLSL 会自动填充W
的值为 1.0。此外,你正在进行的整个复杂操作,将idy
转换为字符并构建一个字符串(例如 "ShadowCoords[" idy "]") 是不必要的 - 你可以获取ShadowCoords
的统一变量位置,然后将idy
添加到该值中,因为统一变量数组中的每个元素都保证被分配一个连续的位置。 - Andon M. Coleman