Opengl:渲染到立方体贴图?

Posted

技术标签:

【中文标题】Opengl:渲染到立方体贴图?【英文标题】:Opengl : Render To Cubemap? 【发布时间】:2020-07-21 16:41:52 【问题描述】:

我正在尝试将 3d 场景渲染到立方体贴图,但立方体贴图只渲染天空盒,这是我的 RenderToCubemap 函数:

GLuint RenderToCubemap(glm::vec3 position, float resolution, float nearPlane, float farPlane)

    unsigned int CM_FBO;
    unsigned int textureID;
    glGenFramebuffers(1, &CM_FBO);
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);

    for (unsigned int i = 0; i < 6; i++)
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, resolution, resolution, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);

    // attach depth texture as FBO's depth buffer
    glBindFramebuffer(GL_FRAMEBUFFER, CM_FBO);
    glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, textureID, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)resolution / (float)resolution, nearPlane, farPlane);
    std::vector<glm::mat4> shadowTransforms;
    shadowTransforms.push_back(shadowProj * glm::lookAt(position, position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
    shadowTransforms.push_back(shadowProj * glm::lookAt(position, position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
    shadowTransforms.push_back(shadowProj * glm::lookAt(position, position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
    shadowTransforms.push_back(shadowProj * glm::lookAt(position, position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
    shadowTransforms.push_back(shadowProj * glm::lookAt(position, position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
    shadowTransforms.push_back(shadowProj * glm::lookAt(position, position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));

    // Render scene to cubemap
    // --------------------------------
    glViewport(0, 0, (int)resolution, (int)resolution);
    glBindFramebuffer(GL_FRAMEBUFFER, CM_FBO);

    Camera capture_cam;
    capture_cam.temp_cam = true;
    capture_cam.projectionMatrix = shadowProj;
    capture_cam.transform.Position = position;
    for (size_t i = 0; i < 6; i++)
    
        capture_cam.viewMatrix = shadowTransforms[i];

        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, textureID, 0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        RenderScene(capture_cam);
    

    return textureID;

渲染场景功能:

void RenderScene(Camera& cam)

    glm::mat4 proj = cam.GetProjectionMatrix();
    glm::mat4 view = cam.GetViewMatrix();
    glm::vec3 viewPos = cam.transform.Position;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        Shader* shader = &materials.main_shader;

        shader ->use();
        shader ->SetMat4("projection", proj);
        shader ->SetMat4("view", view);
        shader ->SetVec3("CamPos", viewPos);

        // Render all meshs
        // ----------------------------------------------------
        for (size_t i = 0; i < Meshs.size(); i++)
        
            if (Meshs[i].Material == nullptr)
                continue;

            Meshs[i].Material->setShaderProperties(shader);

            shader->SetMat4("model", Meshs[i].Transform);
            Meshs[i]->Draw();
           
    
    // render skybox 
    // ----------------------------------------------------
    glDepthFunc(GL_LEQUAL);  // change depth function so depth test passes when values are equal to depth buffer's content
    Shader* bg = &materials.background;
    bg->use();
    bg->SetMat4("view", view);
    bg->SetMat4("projection", proj);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap); 
    renderCube();
    glDepthFunc(GL_LESS); // set depth function back to default

我使用 RenderScene 进行主渲染,它可以工作,但是当我在 renderToCubemap 中使用它时,它只显示天空盒。

有什么帮助或更正吗?

【问题讨论】:

如果您稍后要通过附加每个面来覆盖该附件,那么将立方体贴图纹理作为分层图像附加到帧缓冲区有什么意义?此外,您的评论谈到了“深度纹理”,但您的 FBO 根本没有任何深度缓冲区。那么这到底是如何工作的呢? ... 如上所述,深度测试不起作用,因为帧缓冲区没有深度缓冲区。因此renderCube() 会覆盖之前在“Mesh”循环中绘制的所有内容。 嗨,谢谢您的回复,我发现问题出在“shadowTransforms”中,我通过删除每个 glm::lookAt 上的乘法 shadowProj 来纠正它,我还添加了一个深度缓冲区,现在它工作正常,再次感谢。 【参考方案1】:

我已将“shadowTransforms”替换为:

    std::vector<glm::mat4> shadowTransforms;
    shadowTransforms.push_back(glm::lookAt(position, position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
    shadowTransforms.push_back(glm::lookAt(position, position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
    shadowTransforms.push_back(glm::lookAt(position, position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)));
    shadowTransforms.push_back(glm::lookAt(position, position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)));
    shadowTransforms.push_back(glm::lookAt(position, position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));
    shadowTransforms.push_back(glm::lookAt(position, position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));

我还添加了一个深度缓冲区:

unsigned int m_CubemapDepthRBO;
glGenRenderbuffers(1, &m_CubemapDepthRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_CubemapDepthRBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, (int)resolution, (int)resolution);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_CubemapDepthRBO);

现在可以正常工作了,感谢 Nicole Polas 和 Rabbid76 的快速响应。

【讨论】:

以上是关于Opengl:渲染到立方体贴图?的主要内容,如果未能解决你的问题,请参考以下文章

渲染动态立方体贴图 (OpenGL)

如何在 OpenGL 中使用立方体贴图数组来渲染带有阴影贴图的多个点光源?

带有立方体贴图的 OpenGL 点光阴影映射

使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?

OpenGL中的单色渲染到帧缓冲区对象?

OpenGL+OpenCV实现立方体贴图