当前位置: 首页 > 知识库问答 >
问题:

使用GLSL时,多灯光阴影贴图无法正常工作

乐钱青
2023-03-14

我已经实现了基本的阴影映射算法,但它只适用于一种灯光。

我想用以下两个点光源渲染场景:

  • 灯1-位置:vec3(-8.0f,5.0f,8.0f),方向:vec3(1.3f,-1.0f,-1.0f)
  • 灯2-位置:vec3(8.0华氏度,5.0华氏度,8.0华氏度),方向:vec3(1.3华氏度,-1.0华氏度,-1.0华氏度)

如果我分别渲染两个灯,我有以下结果:

Light_1渲染:

使用灯光_2渲染:

但这两盏灯合在一起看起来是这样的:

正如您所看到的,第一个阴影似乎被正确渲染,但它在light_2阴影的下方,这是不正确的。总结一下,我有绑定到纹理单元0的盒子的纹理。阴影深度纹理是从纹理单元1绑定的,如果有多个深度纹理(所以至少有两个连接,如本例所示),则绑定到纹理单元1 1(GL_TEXTURE11)。这是代表我所说的代码:

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)

顶点着色器如下(仅适用于2个灯光):

#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(我认为是这样)。另外,我注意到,如果我改变灯光的加载顺序,坏阴影是由“另一个灯光”造成的(相反)。所以它似乎来自纹理第二单元,但我不明白为什么。有人能帮我吗?非常感谢你的帮助。

共有1个答案

姬国安
2023-03-14

我解决了我的问题。实际上,我只是填充了第一个深度纹理(对于第一个加载的光)。所以对于第二个光,阴影贴图没有填充,这就是上面第三张图片上黑色区域的原因。

以下是最终结果:

我希望这篇文章对某人有用。谢谢你的关注。

 类似资料:
  • 我有一个由2个网格(平面、立方体)、一个灯和一个相机组成的场景。我想使用GLSL着色器和OpenGL的阴影映射技术在我的场景中显示阴影。 以下是我得到的结果(为了简单起见,我的立方体和平面都是蓝色和蓝色): 这是FBO和深度纹理初始化: 以下是我的顶点着色器的内容: 还有我的片段着色器: 正如你所见,模型上有一些工件,我不知道如何取出它们。但是阴影看起来是正确的,所以我的着色器中输入的变量也应该是

  • 在三维场景中有时候需要设置模型的阴影,也就是阴影贴图或者说光照贴图·lightMap,一般Threejs加载外部模型的光照贴图·lightMap,三维模型加载器可以自动设置,不需要程序员通过代码去设置,不过为了让大家更好理解光照贴图·lightMap,这里就通过Three.js代码设置场景模型的阴影贴图·lightMap。 //创建一个平面几何体作为投影面 var planeGeometry =

  • 我遇到了一个非常奇怪的问题,它似乎起源于片段着色器中的一个简单乘法 我正在尝试使用帧缓冲区计算阴影,该帧缓冲区仅从“灯光透视图”渲染深度,这是初学者的常见技术,易于实现 片段着色器: main()中的最后一个乘法运算表现得很奇怪,将漫反射光的结果乘以纹理颜色可以很好地渲染(因此我们没有阴影,只有漫反射闪电) 将漫反射光乘以阴影结果也可以很好地渲染(现在我们没有纹理) 将所有这些结合起来,只渲染一个

  • 阴影 Unity 的灯光可以将 阴影 从一个游戏对象投射到自身的其他部分或是附近的其他游戏对象上。阴影以『扁平』的方式体现游戏对象的尺寸和位置,因此可以为场景添加一定程度的深度和真实感。 场景视图中的游戏对象正在投射阴影 阴影如何工作? 考虑一种最简单的情况,在场景中只有单个光源。光线从光源出发并沿着直线传播,最终可能会碰撞到场景中的游戏对象。一旦光线碰撞到某个游戏对象,光线将无法继续传播和照亮前

  • 第十五课中已经学习了如何创建光照贴图。光照贴图可用于静态对象的光照,其阴影效果也很不错,但无法处理运动的对象。 阴影贴图是目前(截止2012年)最好的生成动态阴影的方法。此法最大的优点是易于实现,缺点是想完全正确地实现不大容易。 本课首先介绍基本算法,探究其缺陷,然后实现一些优化。由于撰写本文时(2012),阴影贴图技术还在被广泛地研究;我们将提供一些指导,以便你根据自身需要,进一步改善你的阴影贴

  • Note 本节暂未进行完全的重写,错误可能会很多。如果可能的话,请对照原文进行阅读。如果有报告本节的错误,将会延迟至重写之后进行处理。 上个教程我们学到了如何使用阴影映射技术创建动态阴影。效果不错,但它只适合定向光,因为阴影只是在单一定向光源下生成的。所以它也叫定向阴影映射,深度(阴影)贴图生成自定向光的视角。 Important 本节我们的焦点是在各种方向生成动态阴影。这个技术可以适用于点光源,