[OpenGL]使用OpenGL+OIT实现透明效果
一、简介
本文介绍了使用OpenGL,利用 Order-Independent Transparency, OIT技术中的加权混合(weighted blended)
算法实现透明效果。
该算法在实现中使用四次渲染流程实现OIT透明效果,分别为:
- 使用
opaqueShader
渲染非透明模型。保存渲染得到的 color buffer 和 depth buffer,分别保存在opaqueTexture
和opaqueDepthTexture
中; - 使用
transparentShader
渲染透明模型。根据各个透明模型的颜色值C、透明度a和在view space中的深度z,计算各个模型对目标片段的颜色权重,将权重保存在accumTexture
中,各片段对应的透明度加权和存在revealTexture
中。该渲染流程与模型的顺序无关,即不需要事先对模型进行排序; - 使用
compositeShader
将1.
和2.
中得到的opaqueTexture
、accumTexture
和revealTexture
混合起来,得到最终的渲染结果,保存到opaqueTexture
中; - 使用
screenShader
将opaqueTexture
渲染到屏幕;
根据本文代码,如果顺利,最终你可以到的如下结果(渲染时不需要对透明模型进行排序处理,即,该算法是 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=C1∗w(a1,z1)+C2∗w(a2,z2)+...+Cn∗w(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=C1∗a1+(1−a1)∗(C2∗a2+(1−a2)∗(...))
这其中的关键是,如何确定各个片段的权重w(a,z)
。通常权重w(a,z)
都使用heuristic technique启发式方法
确定,即人为地根据实际的效果调整权重方程。
这部分过于复杂本文不做过多介绍,读者可以参考LearnOpenGL-OIT-Weighted Blended 和 论文Weighted Blended Order-Independent Transparency。
1. 渲染流程
基于加权混合的算法使用四次渲染流程实现OIT透明效果,分别为:
- 使用
opaqueShader
渲染非透明模型。保存渲染得到的 color buffer 和 depth buffer,分别保存在opaqueTexture
和opaqueDepthTexture
中。opaqueTexture
用做显示最终结果,opaqueDepthTexture
用在接下来的2.
中,用于丢弃掉被 非透明模型 遮挡的 透明模型。 - 使用
transparentShader
渲染透明模型。根据各个透明模型的颜色值C、透明度a和在view space中的深度z,计算各个模型对目标片段的颜色权重,将权重保存在accumTexture
中,各片段对应的透明度加权和存在revealTexture
中。该渲染流程与模型的顺序无关,即不需要事先对模型进行排序; - 使用
compositeShader
将1.
和2.
中得到的opaqueTexture
、accumTexture
和revealTexture
混合起来,得到最终的渲染结果,保存到opaqueTexture
中; - 使用
screenShader
将opaqueTexture
渲染到屏幕;
三、代码实现
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) 代码流程
- 初始化glfw,glad,窗口
- 编译 shader 程序
2.1 opaque shader
2.2 transparent shader
2.3 composite shader
2.4 screen shader - 设置 FBO
3.1 设置 opaqueFBO
3.2 设置 transparentFBO - 加载obj模型、纹理图片、透明物体模型
- 设置光源和相机位置,Blinn-Phong 模型参数
- 开始渲染
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) - 释放资源
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