当前位置: 首页 > article >正文

[OpenGL]使用OpenGL+OIT实现透明效果

一、简介

本文介绍了使用OpenGL,利用 Order-Independent Transparency, OIT技术中的加权混合(weighted blended)算法实现透明效果。
该算法在实现中使用四次渲染流程实现OIT透明效果,分别为:

  1. 使用 opaqueShader 渲染非透明模型。保存渲染得到的 color buffer 和 depth buffer,分别保存在 opaqueTextureopaqueDepthTexture 中;
  2. 使用 transparentShader 渲染透明模型。根据各个透明模型的颜色值C、透明度a和在view space中的深度z,计算各个模型对目标片段的颜色权重,将权重保存在 accumTexture 中,各片段对应的透明度加权和存在 revealTexture 中。该渲染流程与模型的顺序无关,即不需要事先对模型进行排序;
  3. 使用 compositeShader1.2.中得到的 opaqueTextureaccumTexturerevealTexture 混合起来,得到最终的渲染结果,保存到 opaqueTexture 中;
  4. 使用 screenShaderopaqueTexture 渲染到屏幕;

根据本文代码,如果顺利,最终你可以到的如下结果(渲染时不需要对透明模型进行排序处理,即,该算法是 Order-Independent Transparency (OIT)的):
渲染结果

三、基于加权混合的OIT

0. 基本思想

基于加权混合的 OIT(Weighted Blended Order-Independent Transparency)的基本思想是通过给每个透明片段分配一个权重,按照这些权重对颜色和透明度进行累积混合,从而避免对透明物体进行排序,同时实现近似的透明效果。每个透明片段的权重 w w w 根据片段的 透明度a 和片段在view space中的 深度z 计算得到,最后使用:
C = C 1 ∗ w ( a 1 , z 1 ) + C 2 ∗ w ( a 2 , z 2 ) + . . . + C n ∗ w ( a n , z n ) C = C_1*w(a_1,z_1) + C_2*w(a_2,z_2) + ... + C_n*w(a_n,z_n) C=C1w(a1,z1)+C2w(a2,z2)+...+Cnw(an,zn)
近似表示:
C = C 1 ∗ a 1 + ( 1 − a 1 ) ∗ ( C 2 ∗ a 2 + ( 1 − a 2 ) ∗ ( . . . ) ) C = C_1*a_1 + (1-a_1)*(C_2*a_2 + (1-a_2)*(...)) C=C1a1+(1a1)(C2a2+(1a2)(...))
这其中的关键是,如何确定各个片段的权重w(a,z)。通常权重w(a,z)都使用heuristic technique启发式方法确定,即人为地根据实际的效果调整权重方程。
这部分过于复杂本文不做过多介绍,读者可以参考LearnOpenGL-OIT-Weighted Blended 和 论文Weighted Blended Order-Independent Transparency。

1. 渲染流程

渲染流程
基于加权混合的算法使用四次渲染流程实现OIT透明效果,分别为:

  1. 使用 opaqueShader 渲染非透明模型。保存渲染得到的 color buffer 和 depth buffer,分别保存在 opaqueTextureopaqueDepthTexture 中。opaqueTexture用做显示最终结果,opaqueDepthTexture用在接下来的2.中,用于丢弃掉被 非透明模型 遮挡的 透明模型。
  2. 使用 transparentShader 渲染透明模型。根据各个透明模型的颜色值C、透明度a和在view space中的深度z,计算各个模型对目标片段的颜色权重,将权重保存在 accumTexture 中,各片段对应的透明度加权和存在 revealTexture 中。该渲染流程与模型的顺序无关,即不需要事先对模型进行排序;
  3. 使用 compositeShader1.2.中得到的 opaqueTextureaccumTexturerevealTexture 混合起来,得到最终的渲染结果,保存到 opaqueTexture 中;
  4. 使用 screenShaderopaqueTexture 渲染到屏幕;

2. main.cpp 介绍

2.1) 代码流程

  1. 初始化glfw,glad,窗口
  2. 编译 shader 程序
    2.1 opaque shader
    2.2 transparent shader
    2.3 composite shader
    2.4 screen shader
  3. 设置 FBO
    3.1 设置 opaqueFBO
    3.2 设置 transparentFBO
  4. 加载obj模型、纹理图片、透明物体模型
  5. 设置光源和相机位置,Blinn-Phong 模型参数
  6. 开始渲染
    6.1 渲染 opaque model -> opaqueShader -> opaqueTexture + depthTexture
    6.2 渲染 transparent models -> transparentShader -> accumTexture + revealTexture
    6.3 混合 screen model + accumTexture + revealTexture + opaqueTexture -> compositeShader-> opaqueTexture
    6.4 渲染 screen model + opaqueTexture -> screenShader -> default FBO (screen)
  7. 释放资源

2.2) main.cpp 代码

#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "Skybox.hpp"
#include "Shader.hpp"
#include "Mesh.hpp"
#include "Model.hpp"

#include "glm/ext.hpp"
#include "glm/mat4x4.hpp"
#include <cstdint>
#include <iostream>

#include <random>
#include <iostream>
// 用于处理窗口大小改变的回调函数
void framebuffer_size_callback(GLFWwindow *window, int width, int height);
// 用于处理用户输入的函数
void processInput(GLFWwindow *window);

// 指定窗口默认width和height像素大小
unsigned int SCR_WIDTH = 800;
unsigned int SCR_HEIGHT = 600;

/************************************/

int main()
{
    /****** 1.初始化glfw, glad, 窗口 *******/
    // glfw 初始化 + 配置 glfw 参数
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // 在创建窗口之前
    glfwWindowHint(GLFW_SAMPLES, 4); // 设置多重采样级别为4
    // glfw 生成窗口
    GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
    if (window == NULL)
    {
        // 检查是否成功生成窗口,如果没有成功打印出错信息并且退出
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    // 设置窗口window的上下文
    glfwMakeContextCurrent(window);
    // 配置window变化时的回调函数
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    // 使用 glad 加载 OpenGL 中的各种函数
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // 使用线框模式,绘制时只绘制 三角形 的轮廓
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); // 使用填充模式,绘制时对 三角形 内部进行填充
    // 启用 多重采样抗锯齿
    glEnable(GL_MULTISAMPLE);
    /************************************/

    /****** 2.编译 shader 程序 ******/

    // 2.1 opaque shader. 使用Blinn-Phong模型渲染非透明(opaque)物体 shader, opaque results -> opaqueFBO
    Shader opaqueShader("../resources/Blinn-Phong.vert", "../resources/Blinn-Phong.frag");
    // 2.2 transparent shader. 渲染 透明物体的 shader,  transparent results -> transparentFBO
    Shader transparentShader("../resources/transparent.vert", "../resources/transparent.frag");
    // 2.3 composite shader. 将 transparentFBO 归一化的 shader, opaque results + transparent results -> opaqueFBO
    Shader compositeShader("../resources/composite.vert", "../resources/composite.frag");
    // 2.4 screen shader. 将 compositeFBO 当做纹理,显示在屏幕上的 shader, -> default FBO (screen)
    Shader screenShader("../resources/screen.vert", "../resources/screen.frag");
    /************************************/

    /****** 3. 设置FBO ******/
    unsigned int opaqueFBO, transparentFBO;
    glGenFramebuffers(1, &opaqueFBO);
    glGenFramebuffers(1, &transparentFBO);

    // 3.1 设置 opaqueFBO 对应的 texture
    // 设置 opaqueFBO 的渲染结果纹理, opaqueFBO 用于渲染 opaque 物体的 颜色->opaqueTexture, 深度值->opaqueDepthTexture
    unsigned int opaqueTexture;
    glGenTextures(1, &opaqueTexture);            // 生成 texture (opaqueTexture)
    glBindTexture(GL_TEXTURE_2D, opaqueTexture); // 绑定 texture (opaqueTexture 绑定到 CL_TEXTURE_2D 上)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_HALF_FLOAT,
                 NULL); // 设置 opaqueTexture 属性
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0); // 解绑 opaqueTexture

    unsigned int opaqueDepthTexture;                  // 生成 deepth texture (opaqueDepthTexture)
    glGenTextures(1, &opaqueDepthTexture);            // 绑定 texture (opaqueDepthTexture)
    glBindTexture(GL_TEXTURE_2D, opaqueDepthTexture); // 设置 opaqueDepthTexture 属性
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SCR_WIDTH, SCR_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glBindTexture(GL_TEXTURE_2D, 0);

    // 将 opaqueTexture, opaqueDepthTexture 绑定到 opaqueGBO 上
    // opaqueTexture 用于接收 GL_COLOR_ATTACHMENT0
    // opaqueDepthTexture 用于接收 GL_DEPTH_ATTACHMENT
    glBindFramebuffer(GL_FRAMEBUFFER, opaqueFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, opaqueTexture, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, opaqueDepthTexture, 0);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR::FRAMEBUFFER:: Opaque framebuffer is not complete!" << std::endl;

    glBindFramebuffer(GL_FRAMEBUFFER, 0); // 解绑  opaqueFBO

    // 3.2 设置 transparentFBO 对应的 texture
    // 设置 transparentFBO 的渲染纹理
    // transparentShader 中的 accum -> accumTexture, reveal -> revealTexture
    unsigned int accumTexture;
    glGenTextures(1, &accumTexture);
    glBindTexture(GL_TEXTURE_2D, accumTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGBA, GL_HALF_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    unsigned int revealTexture;
    glGenTextures(1, &revealTexture);
    glBindTexture(GL_TEXTURE_2D, revealTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, SCR_WIDTH, SCR_HEIGHT, 0, GL_RED, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);

    glBindFramebuffer(GL_FRAMEBUFFER, transparentFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, accumTexture, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, revealTexture, 0);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, opaqueDepthTexture,
                           0); // opaque framebuffer's depth texture

    const GLenum transparentDrawBuffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
    glDrawBuffers(2, transparentDrawBuffers);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        std::cout << "ERROR::FRAMEBUFFER:: Transparent framebuffer is not complete!" << std::endl;

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    /****** 4.加载obj模型、纹理图片、透明物体模型 ******/
    // 4.1 opaque model
    Model ourModel("../resources/models/spot/spot.obj");
    // Model ourModel("../resources/models/nanosuit/nanosuit.obj");

    // 4.2 transparent model 0
    vector<Vertex> transWinVertex0 = {
        {{-0.80, 0.20, -1.0}, {0.0, 0.0, 1.0}, {0.0, 1.0}},  // position, normal, texture_coordinate
        {{-0.80, -0.80, -1.0}, {0.0, 0.0, 1.0}, {0.0, 0.0}}, //
        {{0.20, -0.80, -1.0}, {0.0, 0.0, 1.0}, {1.0, 0.0}},  //
        {{0.20, 0.20, -1.0}, {0.0, 0.0, 1.0}, {1.0, 1.0}}};
    vector<unsigned int> transWinIndex0 = {0, 1, 2, 2, 3, 0};
    vector<Texture> transWinTexture0 = {
        {TextureFromFile("window-r.png", "../resources/textures", true, GL_CLAMP_TO_EDGE), "texture_diffuse",
         "../resources/textures/window-r.png"}}; // textire_id, type, file_path
    Mesh transWinMesh0(transWinVertex0, transWinIndex0, transWinTexture0);
    Model transWinModel0(transWinMesh0);

    // 4.3 transparent model 1
    vector<Vertex> transWinVertex1 = {
        {{-0.10, 0.90, -1.2}, {0.0, 0.0, 1.0}, {0.0, 1.0}},  //  position, normal, texture_coordinate
        {{-0.10, -0.10, -1.2}, {0.0, 0.0, 1.0}, {0.0, 0.0}}, //
        {{0.90, -0.10, -1.2}, {0.0, 0.0, 1.0}, {1.0, 0.0}},  //
        {{0.90, 0.90, -1.2}, {0.0, 0.0, 1.0}, {1.0, 1.0}}};
    vector<unsigned int> transWinIndex1 = {0, 1, 2, 2, 3, 0};
    vector<Texture> transWinTexture1 = {
        {TextureFromFile("window-g.png", "../resources/textures", true, GL_CLAMP_TO_EDGE), "texture_diffuse",
         "../resources/textures/window-g.png"}}; // textire_id, type, file_path
    Mesh transWinMesh1(transWinVertex1, transWinIndex1, transWinTexture1);
    Model transWinModel1(transWinMesh1);

    // 4.4 transparent model 2
    vector<Vertex> transWinVertex2 = {
        {{-0.10, 0.2, 1.2}, {0.0, 0.0, 1.0}, {0.0, 1.0}},  //  position, normal, texture_coordinate
        {{-0.10, -0.8, 1.2}, {0.0, 0.0, 1.0}, {0.0, 0.0}}, //
        {{0.90, -0.8, 1.2}, {0.0, 0.0, 1.0}, {1.0, 0.0}},  //
        {{0.90, 0.2, 1.2}, {0.0, 0.0, 1.0}, {1.0, 1.0}}};
    vector<unsigned int> transWinIndex2 = {0, 1, 2, 2, 3, 0};
    vector<Texture> transWinTexture2 = {
        {TextureFromFile("window-b.png", "../resources/textures", true, GL_CLAMP_TO_EDGE), "texture_diffuse",
         "../resources/textures/window-b.png"}}; // textire_id, type, file_path
    Mesh transWinMesh2(transWinVertex2, transWinIndex2, transWinTexture2);
    Model transWinModel2(transWinMesh2);

    // 4.5 screen model
    vector<Vertex> screenVertices = {{{-1, 1, 0}, {0, 1, 0}, {0, 1.0}},
                                     {{-1, -1, 0}, {0, 1, 0}, {0, 0}},
                                     {{1, -1, 0}, {0, 1, 0}, {1.0, 0}},
                                     {{1, 1, 0}, {0, 1, 0}, {1.0, 1.0}}};

    vector<unsigned int> screenIndices = {0, 1, 2, 0, 2, 3};
    vector<Texture> screenTexture; // 空纹理, 在渲染时会将 opaqueTexture 设为 screenModel 的纹理
    Mesh screenMesh(screenVertices, screenIndices, screenTexture);
    Model screenModel(screenMesh);

    /************************************/

    /****** 5.设置光源和相机位置,Blinn-Phong 模型参数 ******/
    // 模型参数 ka, kd, ks
    float k[] = {0.1f, 0.7f, 0.2f}; // ka, kd, ks
    // 光源位置
    glm::vec3 light_pos = glm::vec3(-2.0f, 2.0f, 0.0f);
    // 相机位置
    glm::vec3 camera_pos = glm::vec3(0.0f, 0.0f, 1.5f);
    /************************************/

    /****** 6.开始渲染 ******/
    // 6.1 渲染 opaque model -> opaqueShader -> opaqueTexture + depthTexture
    float rotate = 180.0f;
    // 初始值 0.0, 1.0
    glm::vec4 zeroFillerVec(0.0f);
    glm::vec4 oneFillerVec(1.0f);
    while (!glfwWindowShouldClose(window))
    {
        rotate += 0.05f;
        // input
        // -----
        processInput(window);

        // render
        // ------

        // 6.1 渲染 opaque model -> opaqueShader -> opaqueTexture + depthTexture
        // 6.1.1). set {FBO (must be set first), depth test, blend, color/depth buffer (optional, must after set FBO)}
        glBindFramebuffer(GL_FRAMEBUFFER, opaqueFBO); // 渲染到 opaqueFBO (opaqueTexture, opaqueDepthTexture)
        glEnable(GL_DEPTH_TEST);                      // 启用 depth test
        glDepthFunc(GL_LESS);                         // depth test 通过 条件为 less
        glDepthMask(GL_TRUE);                         // 可以写入 depth buffer
        glDisable(GL_BLEND);                          // 禁止 blend

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT |
                GL_DEPTH_BUFFER_BIT); // 使用 (0.2,0.3,0.3,1.0)清空 color texture, 清空 depth buffer

        // 6.1.2). use shader
        opaqueShader.use(); // 启用 opaqueShader

        // 6.1.3). set MVP matrixes
        // 设置 camera_MVP 矩阵, 假设以 camera 为视角,渲染 camera 视角下的场景深度图
        // camera model 矩阵
        glm::mat4 camera_model = glm::mat4(1.0f);
        camera_model = glm::translate(camera_model, glm::vec3(0.0f, 0.0f, 0.0f));
        camera_model = glm::rotate(camera_model, glm::radians(0.0f), glm::vec3(1.0f, 0.0f, 0.0f));
        camera_model = glm::rotate(camera_model, glm::radians(rotate), glm::vec3(0.0f, 1.0f, 0.0f));
        camera_model = glm::rotate(camera_model, glm::radians(0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
        camera_model = glm::scale(camera_model, glm::vec3(0.5f, 0.5f, 0.5f));
        // camera view 矩阵
        glm::mat4 camera_view = glm::mat4(1.0f);
        camera_view = glm::lookAt(camera_pos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));

        // camera projection 矩阵
        glm::mat4 camera_projection = glm::mat4(1.0f);
        camera_projection = glm::perspective(glm::radians(60.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
        opaqueShader.setMat4("model", camera_model);
        opaqueShader.setMat4("view", camera_view);
        opaqueShader.setMat4("projection", camera_projection);
        opaqueShader.setVec3("k", k[0], k[1], k[2]);
        opaqueShader.setVec3("cameraPos", camera_pos);
        opaqueShader.setVec3("lightPos", light_pos);

        // 6.1.4). Draw()
        ourModel.Draw(opaqueShader);

        // 6.1.5). set default FBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // 6.2 渲染 transparent models -> transparentShader -> accumTexture + revealTexture

        // 6.2.1). set {FBO (must be set first), depth test, blend, color/depth buffer (must after set FBO)}
        glBindFramebuffer(GL_FRAMEBUFFER, transparentFBO); // 渲染到 transparentFBO (accumTexture, revealTexture)
        glDepthMask(GL_FALSE);                             // 禁止写入 depth buffer
        glEnable(GL_BLEND);                                // 启用 blend
        glBlendFunci(0, GL_ONE, GL_ONE);                   // 设置 color_attachment0 的混合权重为 1,1
        // C_d_accum = C_s + C_d_accum
        glBlendFunci(1, GL_ZERO, GL_ONE_MINUS_SRC_COLOR); // 设置 color_attachment1 的混合权重为 0, 1-C_s
        // C_d_reveal = C_d_reveal * (1-C_s_color)
        glBlendEquation(GL_FUNC_ADD); // 设置 blend 运算为 ADD 运算, 实际上不设置也可以,因为默认就是 ADD 运算
        glClearBufferfv(GL_COLOR, 0, &zeroFillerVec[0]); // 初始化 color_attachment0 (accumTexture) 值为 0.0
        glClearBufferfv(GL_COLOR, 1, &oneFillerVec[0]);  // 初始化 color_attachment1 (revealTexture) 值为1.0

        // 6.2.2). use shader
        transparentShader.use();

        // 6.2.3). set MVP matrixes
        transparentShader.setMat4("model", camera_model);
        transparentShader.setMat4("view", camera_view);
        transparentShader.setMat4("projection", camera_projection);

        // 6.2.4). Draw()
        transWinModel0.Draw(transparentShader);
        transWinModel1.Draw(transparentShader);
        transWinModel2.Draw(transparentShader);

        // 6.2.5). unbind transparentFBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // 6.3 混合 screen model + accumTexture + revealTexture + opaqueTexture -> compositeShader-> opaqueTexture
        // 6.3.1). set {FBO (must be set first), depth test, blend, color/depth buffer (optional, must after set FBO)}
        glBindFramebuffer(GL_FRAMEBUFFER, opaqueFBO);      // 绑定 opaqueFBO
        glDepthFunc(GL_ALWAYS);                            // 总是通过 depth test
        glEnable(GL_BLEND);                                // 启用 blend
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 混合权重设为 alpha_src, 1-alpha_src

        // 6.3.2) use shader
        compositeShader.use();

        // 6.3.4) set texture
        screenModel.setTexture(
            {{accumTexture, "texture_diffuse", "accumTexture"}, {revealTexture, "texture_diffuse", "revealTexture"}});
        // 6.3.5) Draw()
        screenMesh.DrawWithTextures(
            compositeShader,
            {{accumTexture, "texture_diffuse", "accumTexture"}, {revealTexture, "texture_diffuse", "revealTexture"}},
            {"accum", "reveal"});
        // 6.3.6) 解绑 opaqueFBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0);

        // 6.4 渲染 screen model + opaqueTexture -> screenShader -> default FBO (screen)
        // 6.4.1). set {FBO (must be set first), depth test, blend, color/depth buffer (must after set FBO)}
        glBindFramebuffer(GL_FRAMEBUFFER, 0); // 渲染到屏幕
        glDisable(GL_DEPTH_TEST);             // 关闭深度测试
        glDepthMask(GL_TRUE);                 // 开启写入 depth buffer, 使用 glClear() 清空 depth buffer
        glDisable(GL_BLEND);                  // 关闭 blend
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); // 清空 clor, depth, stencil 缓冲
        // 6.4.2) use shader
        screenShader.use();
        // 6.4.3) set texture
        screenModel.setTexture({{opaqueTexture, "texture_diffuse", "opaqueTexture"}});
        // 6.4.4) Draw
        screenModel.Draw(screenShader);

        glfwSwapBuffers(window); // 在gfw中启用双缓冲,确保绘制的平滑和无缝切换
        glfwPollEvents(); // 用于处理所有挂起的事件,例如键盘输入、鼠标移动、窗口大小变化等事件
    }

    /************************************/
    /****** 7.释放资源 ******/
    // glfw 释放 glfw使用的所有资源
    glfwTerminate();
    /************************************/
    return 0;
}

// 用于处理用户输入的函数
void processInput(GLFWwindow *window)
{
    // 当按下 Esc 按键时调用 glfwSetWindowShouldClose() 函数,关闭窗口
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    {
        glfwSetWindowShouldClose(window, true);
    }
}

// 在使用 OpenGL 和 GLFW 库时,处理窗口大小改变的回调函数
// 当窗口大小发生变化时,确保 OpenGL 渲染的内容能够适应新的窗口大小,避免图像被拉伸、压缩或出现其他比例失真的问题
void framebuffer_size_callback(GLFWwindow *window, int width, int height)
{
    SCR_WIDTH = width;
    SCR_HEIGHT = height;
    glViewport(0, 0, width, height);
}

由于篇幅问题,本文不再介绍其他文件中的代码细节,全部代码和相关模型可以在三、全部代码中下载。

3. 编译运行及结果

编译运行:

cd ./build
cmake ..
make
./OpenGL_OIT

渲染结果:
渲染结果

三、全部代码

全部代码以及模型文件可以在OpenGL使用OpenGL+OIT实现透明效果中下载。

四、参考

[1.] LearnOpenGL-OIT-Weighted Blended
[2.] Weighted Blended Order-Independent Transparency


http://www.kler.cn/a/409548.html

相关文章:

  • Vue进阶面试题目(一)
  • ros2学习日记_241124_ros相关链接
  • ssm实战项目──哈米音乐(二)
  • opencv-python 分离边缘粘连的物体(距离变换)
  • stable-diffusion-webui在conda pycharm中运行
  • 搜索插入位置
  • CPU性能优化--性能分析方法
  • 网络层协议IP
  • 【计算机网络】多路转接之select
  • Next.js-样式处理
  • 数据结构 (9)顺序表与链表的综合比较
  • 深入理解二叉搜索树(BST)
  • 【组件】前端ElementUi 下拉Tree树形组件 带模糊搜索自动展开高亮功能
  • Move 合约部署踩坑笔记:如何解决 Sui 客户端发布错误Committing lock file
  • linux系统运维面试题(二)(Linux System Operations Interview Questions II)
  • 国产FPGA+DSP 双FMC 6U VPX处理板
  • 嵌入式硬件实战提升篇(二)PCB高速板设计 FPGA核心板带DDR3 PCB设计DDR全面解析
  • LeetCode Hot100 - 矩阵篇
  • Vue.js 前端路由详解:从基础概念到 Vue Router 实战
  • 植物明星大乱斗——功能拆解
  • ffmpeg.wasm 在浏览器运行ffmpeg操作视频
  • day27|leetCode 455. 分发饼干,376.摆动序列,53. 最大子数组和
  • 快速排序算法-C语言
  • GitLab 使用过程中常见问题及解决方案
  • 【人工智能】Transformers之Pipeline(二十五):图片特征抽取(image-feature-extraction)
  • Vue.js 学习总结(14)—— Vue3 为什么推荐使用 ref 而不是 reactive