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

[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 渲染到屏幕;

三、代码实现

0. 环境需要

  • Linux,或者 windos下使用wsl2。
  • 安装GLFW和GLAD。请参考[OpenGL] wsl2上安装使用cmake+OpenGL教程。
  • 安装glm。glm是个可以只使用头文件的库,因此可以直接下载release的压缩文件,然后解压到include目录下。例如,假设下载的release版本的压缩文件为glm-1.0.1-light.zip。将glm-1.0.1-light.zip复制include目录下,然后执行以下命令即可解压glm源代码:
    unzip glm-1.0.1-light.zip
    
  • 需要使用Assimp库加载obj模型,在 ubuntu 下可以使用以下命令安装 Assimp
    sudo apt-get update
    sudo apt-get install libassimp-dev
    
  • 需要下载 stb_image.h 作为加载.png图像的库。将 stb_image.h 下载后放入include/目录下。

1. main.cpp 介绍

1.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. 释放资源

1.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 -> opaqueFBOShader opaqueShader("../resources/Blinn-Phong.vert", "../resources/Blinn-Phong.frag");// 2.2 transparent shader. 渲染 透明物体的 shader,  transparent results -> transparentFBOShader transparentShader("../resources/transparent.vert", "../resources/transparent.frag");// 2.3 composite shader. 将 transparentFBO 归一化的 shader, opaque results + transparent results -> opaqueFBOShader 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, 深度值->opaqueDepthTextureunsigned 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); // 解绑 opaqueTextureunsigned 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_ATTACHMENTglBindFramebuffer(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 -> revealTextureunsigned 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 textureconst 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 modelModel ourModel("../resources/models/spot/spot.obj");// Model ourModel("../resources/models/nanosuit/nanosuit.obj");// 4.2 transparent model 0vector<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_pathMesh transWinMesh0(transWinVertex0, transWinIndex0, transWinTexture0);Model transWinModel0(transWinMesh0);// 4.3 transparent model 1vector<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_pathMesh transWinMesh1(transWinVertex1, transWinIndex1, transWinTexture1);Model transWinModel1(transWinMesh1);// 4.4 transparent model 2vector<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_pathMesh transWinMesh2(transWinVertex2, transWinIndex2, transWinTexture2);Model transWinModel2(transWinMesh2);// 4.5 screen modelvector<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, ksfloat 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 + depthTexturefloat rotate = 180.0f;// 初始值 0.0, 1.0glm::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 testglDepthFunc(GL_LESS);                         // depth test 通过 条件为 lessglDepthMask(GL_TRUE);                         // 可以写入 depth bufferglDisable(GL_BLEND);                          // 禁止 blendglClearColor(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 shaderopaqueShader.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 FBOglBindFramebuffer(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 bufferglEnable(GL_BLEND);                                // 启用 blendglBlendFunci(0, GL_ONE, GL_ONE);                   // 设置 color_attachment0 的混合权重为 1,1// C_d_accum = C_s + C_d_accumglBlendFunci(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.0glClearBufferfv(GL_COLOR, 1, &oneFillerVec[0]);  // 初始化 color_attachment1 (revealTexture) 值为1.0// 6.2.2). use shadertransparentShader.use();// 6.2.3). set MVP matrixestransparentShader.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 transparentFBOglBindFramebuffer(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);      // 绑定 opaqueFBOglDepthFunc(GL_ALWAYS);                            // 总是通过 depth testglEnable(GL_BLEND);                                // 启用 blendglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // 混合权重设为 alpha_src, 1-alpha_src// 6.3.2) use shadercompositeShader.use();// 6.3.4) set texturescreenModel.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) 解绑 opaqueFBOglBindFramebuffer(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 bufferglDisable(GL_BLEND);                  // 关闭 blendglClearColor(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 shaderscreenShader.use();// 6.4.3) set texturescreenModel.setTexture({{opaqueTexture, "texture_diffuse", "opaqueTexture"}});// 6.4.4) DrawscreenModel.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);
}

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

2. 编译运行及结果

编译运行:

cd ./build
cmake ..
make
./OpenGL_OIT

渲染结果:
渲染结果

四、全部代码

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

五、参考

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


http://www.mrgr.cn/news/78050.html

相关文章:

  • 找到一个或多个多重定义的符号的问题
  • UDP -- 简易聊天室
  • 超完整Docker学习记录,Docker常用命令详解
  • docker一键安装脚本(docker安装)
  • MySQL安装,配置教程
  • Java验证邮箱是否有用的实现与解析
  • 内存不足引发C++程序闪退崩溃问题的分析与总结
  • 2024 年:Kubernetes 包管理的新前沿
  • AI:电商平台销售效率提升的魔法钥匙
  • 深度学习笔记1:自动微分与神经网络实现(附代码)
  • Springboot 整合 Java DL4J 搭建智能问答系统
  • 小米C++ 面试题及参考答案下(120道面试题覆盖各种类型八股文)
  • Django 自定义路由转换器
  • 免费下载 | 2025中国5G产业全景图谱报告
  • Leetcode647. 回文子串(HOT100)
  • 【可解释性机器学习】基于SHAP进行特征选择和贡献度计算
  • AI-Talk开发板之Camera
  • OpenCV基础(3)
  • 优化Docker镜像:提升部署效率与降低资源消耗
  • Spring Boot 与 Java 决策树:构建智能分类系统
  • 数字逻辑(一)——导论
  • 241125学习日志——[CSDIY] [ByteDance] 后端训练营 [18]
  • 车载摄像camera基础知识和评估
  • 2024年底-Arch linux或转为0BSD许可证!
  • 打造智能扩容新纪元:Kubernetes Custom Metrics深度解析
  • Vue 修饰符的作用与应用,应用场景详细介绍