A_A_S05 2024-09-17 14:52 采纳率: 66.7%
浏览 3

多光源阴影贴图显示问题

我想要实现一个多光源阴影贴图,在调试之后,glGetError已经不报错了,光照情况是正确的,但是阴影就是没有实现,不明白是什么原因。
下面是我的代码:

……//初始化
Shader shader("D:/cppalbum/shader/lighting/pointDepth/multiDepthVert.glsl",
    "D:/cppalbum/shader/lighting/pointDepth/multiDepthFrag.glsl");
Shader simpleDepthShader("D:/cppalbum/shader/lighting/pointDepth/cubeVert.glsl",
    "D:/cppalbum/shader/lighting/pointDepth/cubeFrag.glsl",
    "D:/cppalbum/shader/lighting/pointDepth/cubeGeo.glsl");
shader.use();
shader.setInt("diffuseMap", 0);

Model mc("D:/cppalbum/texture/T2/test2.obj");

unsigned int wood = loadTexture("D:/cppalbum/texture/Wooden_floor.jpg");

const unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024;
// create depth cubemap texture
unsigned int fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
unsigned int depthCubeMapArray;
glGenTextures(1, &depthCubeMapArray);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubeMapArray);
// 为每个立方体贴图分配内存
glTexImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, GL_DEPTH_COMPONENT,
    SHADOW_WIDTH, SHADOW_HEIGHT, 4 * 6, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
// 设置纹理参数
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubeMapArray, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;

const int NUM_LIGHTS = 4;
// 绑定每个立方体贴图到数组中


shader.setInt("depthMap", 1);


glm::vec3 lightPos[4] = {
    glm::vec3(0.0f, 0.0f, 0.0f),
    glm::vec3(1.0f, 0.0f, 1.0f),
    glm::vec3(0.0f, 2.0f, 0.0f),
    glm::vec3(1.0f, 1.0f, 1.0f) };


//主循环
// ------------------------------------------------------------------
while (!glfwWindowShouldClose(window))
{
    // per-frame time logic
    // --------------------
    float currentFrame = static_cast<float>(glfwGetTime());
    deltaTime = currentFrame - lastFrame;
    lastFrame = currentFrame;

    // input
    // -----
    processInput(window);

    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    float near_plane = 1.0f;
    float far_plane = 25.0f;
    glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)SHADOW_WIDTH / (float)SHADOW_HEIGHT, near_plane, far_plane);
    

    for (int i = 0; i < 4; ++i)
    {
        std::vector<glm::mat4> shadowTransforms;
        shadowTransforms.push_back(shadowProj * 
            glm::lookAt(lightPos[i], lightPos[i] + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        shadowTransforms.push_back(shadowProj * 
            glm::lookAt(lightPos[i], lightPos[i] + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        shadowTransforms.push_back(shadowProj * 
            glm::lookAt(lightPos[i], lightPos[i] + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
        shadowTransforms.push_back(shadowProj * 
            glm::lookAt(lightPos[i], lightPos[i] + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
        shadowTransforms.push_back(shadowProj * 
            glm::lookAt(lightPos[i], lightPos[i] + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        shadowTransforms.push_back(shadowProj * 
            glm::lookAt(lightPos[i], lightPos[i] + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
        glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubeMapArray, 0, i * 6);
        glClear(GL_DEPTH_BUFFER_BIT);
        simpleDepthShader.use();
        for (unsigned int j = 0; j < 6; ++j)
            simpleDepthShader.setMat4("shadowMatrices[" + std::to_string(j) + "]", shadowTransforms[j]);
        simpleDepthShader.setFloat("far_plane", far_plane);
        simpleDepthShader.setVec3("lightPos", lightPos[i]);
        renderScene(simpleDepthShader, mc, wood);
    }

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // 激活纹理单元
    glActiveTexture(GL_TEXTURE1);
    // 绑定立方体贴图数组纹理
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, depthCubeMapArray);

    // 2. render scene as normal 
    // -------------------------
    glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    shader.use();
    glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    glm::mat4 view = camera.GetViewMatrix();
    shader.setMat4("projection", projection);
    shader.setMat4("view", view);
    // set lighting uniforms
    for (unsigned int i = 0; i < 4; ++i)
        shader.setVec3("lightPos["+std::to_string(i)+"]", lightPos[i]);
    shader.setVec3("viewPos", camera.Position);
    shader.setInt("shadows", shadows); // enable/disable shadows by pressing 'SPACE'
    shader.setFloat("far_plane", far_plane);
    
    renderScene(shader, mc, wood);
……//剩余部分

着色器(只放fs和几何着色器了,顶点没啥用也不会有问题):
multiDepthFrag.glsl


#version 330 core
out vec4 FragColor;

in VS_OUT {
    vec3 FragPos;
    vec3 Normal;
    vec2 TexCoords;
} fs_in;

uniform sampler2D diffuseTexture;
uniform samplerCubeArray depthMap;

uniform vec3 lightPos[4];
uniform vec3 viewPos;

uniform float far_plane;
uniform bool shadows;

vec3 sampleOffsetDirections[20] = vec3[]
(
   vec3( 1,  1,  1), vec3( 1, -1,  1), vec3(-1, -1,  1), vec3(-1,  1,  1), 
   vec3( 1,  1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1,  1, -1),
   vec3( 1,  1,  0), vec3( 1, -1,  0), vec3(-1, -1,  0), vec3(-1,  1,  0),
   vec3( 1,  0,  1), vec3(-1,  0,  1), vec3( 1,  0, -1), vec3(-1,  0, -1),
   vec3( 0,  1,  1), vec3( 0, -1,  1), vec3( 0, -1, -1), vec3( 0,  1, -1)
);

float ShadowCalculation(vec3 fragPos,int i)
{
    // Get vector between fragment position and light position
    vec3 fragToLight = fragPos - lightPos[i];
    float currentDepth = length(fragToLight);
    // Now test for shadows
    float shadow = 0.0;
    float bias = 0.05; 
    int samples = 20;
    float viewDistance = length(viewPos - fragPos);
    float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;
    for (int i=0;i<samples;++i)
    {
        float closestDepth = texture(depthMap, vec4(fragToLight + sampleOffsetDirections[i] * diskRadius,i)).r;
        closestDepth *= far_plane;   // Undo mapping [0;1]
        if(currentDepth - bias > closestDepth)
            shadow += 1.0;
    }
    shadow /= samples;

    return shadow;
}

void main()
{           
    vec3 color = texture(diffuseTexture, fs_in.TexCoords).rgb;
    vec3 normal = normalize(fs_in.Normal);
    vec3 lightColor = vec3(0.3);
    // Ambient
    vec3 ambient = 0.3 * color;
    FragColor = vec4(0.0f);
    int lightNum=4;
    float lightNums = lightNum;
    // Diffuse
    for (int i=0;i<lightNum;++i)
    {
        vec3 lightDir = normalize(lightPos[i] - fs_in.FragPos);
        float diff = max(dot(lightDir, normal), 0.0);
        vec3 diffuse = diff * lightColor;
    // Specular
        vec3 viewDir = normalize(viewPos - fs_in.FragPos);
        vec3 reflectDir = reflect(-lightDir, normal);
        float spec = 0.0;
        vec3 halfwayDir = normalize(lightDir + viewDir);  
        spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
        vec3 specular = spec * lightColor;    
    // Calculate shadow
        float shadow = shadows ? ShadowCalculation(fs_in.FragPos, i) : 0.0;                      
        vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * color;    
        FragColor += vec4(lighting, 1.0f);
    }
    FragColor /= lightNums;
    
}

cubeGeo.glsl


#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;

uniform mat4 shadowMatrices[6];

out vec4 FragPos; // FragPos from GS (output per emitvertex)

void main()
{
    for(int face = 0; face < 6; ++face)
    {
        gl_Layer = face; // built-in variable that specifies to which face we render.
        for(int i = 0; i < 3; ++i) // for each triangle's vertices
        {
            FragPos = gl_in[i].gl_Position;
            gl_Position = shadowMatrices[face] * FragPos;
            EmitVertex();
        }    
        EndPrimitive();
    }
}

cubeFrag.glsl


#version 330 core
in vec4 FragPos;

uniform vec3 lightPos;
uniform float far_plane;

void main()
{
    // get distance between fragment and light source
    float lightDistance = length(FragPos.xyz - lightPos);

    // map to [0;1] range by dividing by far_plane
    lightDistance = lightDistance / far_plane;

    // write this as modified depth
    gl_FragDepth = lightDistance;
}

现在的显示是这样的:

img

调试了一中午了

  • 写回答

1条回答 默认 最新

  • 码踏云端 Java领域新星创作者 2024-09-17 16:32
    关注

    看了你的代码之后,问题可能出在以下几个方面,尤其是在阴影贴图的生成和采样部分。这里是一些可能的原因和调试建议:

    1. 深度缓冲区层的绑定可能有问题

    在主循环中,你在每个光源渲染到深度贴图时,使用了 glFramebufferTextureLayer 函数。然而,glFramebufferTextureLayer 的第四个参数(layer 参数)用于指定哪一层立方体贴图的纹理应该被渲染。你设置的是 i * 6,这是因为你假设每个光源会有 6 层纹理。然而,这样的方式可能会导致问题,具体取决于你在 glTexImage3D 中分配纹理的方式。

    修正建议:

    • glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubeMapArray, 0, i * 6); 修改为 glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubeMapArray, 0, i);
    • 确保深度缓冲区的层数与光源的数量和面向立方体的方向数(6 个方向)相匹配。

    2. 几何着色器中的坐标传递问题

    在你的几何着色器中,gl_in[i].gl_Position 直接赋值给 FragPos。然而,gl_Position 通常是裁剪空间坐标,在传递给片段着色器时需要经过一定的变换。

    修正建议:

    • 使用 gl_in[i].gl_Position 之前,确保将坐标从局部空间正确转换为世界空间或者光空间。

    3. 阴影计算中的光源索引问题

    你在 multiDepthFrag.glslShadowCalculation 函数中传递了光源索引 i,但同时也在循环中使用 i 作为光源的迭代索引。这可能会引起混淆或变量覆盖问题。

    修正建议:

    • ShadowCalculation 中使用不同的变量名,避免与循环索引 i 冲突。

    4. 深度贴图采样问题

    ShadowCalculation 函数中,你从 depthMap 中采样时,使用了 vec4(fragToLight + sampleOffsetDirections[i] * diskRadius, i) 作为参数,这里的 i 是用作光源索引的,但可能需要具体指明你希望从哪个面向采样。因为你使用的是立方体贴图数组,所以你需要确保在采样时正确选择立方体贴图的层。

    修正建议:

    • 确保 depthMap 的采样索引与正确的光源层匹配。
    • 可以检查是否立方体纹理的数组索引被正确传递。

    5. 调试建议

    • 使用 glGetFramebufferAttachmentParameteriv 检查深度缓冲区的绑定状态:你可以在 glFramebufferTextureLayer 后检查深度附件的绑定状态,确保它绑定到正确的层。

    • 检查光源位置和裁剪空间矩阵:可以打印光源的阴影矩阵和深度缓冲区值,确认阴影数据是否被正确写入。

    • 启用调试输出:使用 OpenGL 的 GL_KHR_debug 扩展捕获更多的错误或警告。

    • 分步渲染和可视化阴影贴图:你可以将生成的深度贴图可视化渲染到屏幕上,确保每个光源的阴影贴图生成是正确的。

    通过这些调试和修改,应该可以逐步定位问题的根源。如果你需要进一步深入调试,可以尝试将阴影贴图生成的步骤拆解成更小的部分逐一验证。

    评论

报告相同问题?

问题事件

  • 创建了问题 9月17日

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?