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

计算机图形学:(七)渲染目标

渲染目标

        在设置渲染结果的输出目标时,一般可选择:① 帧缓存(FrameBuffer)、② 渲染纹理(RenderTexture)。

        注:帧缓存和帧缓冲区是同一个东西,只是翻译的不同;

# 帧缓存(FrameBuffer)

        OpenGL 会提供一个默认的窗口系统提供的帧缓存,由窗口系统(如GLFW、SDL等)管理,直接关联到显示设备。在 OpenGL 以及大部分的渲染管线中,帧缓存是在实际渲染之前的最后一个步骤。帧缓存本质上是一块内存或者硬件中的空间,负责保存需要渲染图像的像素相关信息。

        帧缓存存储的信息主要包括以下几个方面:

  • 颜色缓冲区(Color Buffer)

        存储像素的颜色信息,每个像素通常包含红色、绿色、蓝色和透明度(Alpha)数据。

  • 深度缓冲区(Depth Buffer)

        存储场景中每个像素的深度信息,帮助确定哪个物体应该遮挡其他物体。

  • 模板缓冲区(Stencil Buffer)

        用于复杂的遮罩操作,控制哪些区域可以被渲染。

  • 其他缓冲区

        例如多重采样缓冲区(MSAA Buffer)、反射缓冲区等。

# 帧缓冲区对象(FrameBufferObject)

        FBO,即Frame Buffer Object,是计算机图形学中的一项关键技术。它允许我们将渲染目标从默认的帧缓冲区扩展到纹理,为离屏渲染提供了强大的支持。它允许开发者创建自定义的帧缓冲,不依赖窗口系统,从而支持离屏渲染(如后期处理、阴影映射、纹理绘制等)。

图源: (四)结合代码初步理解帧缓存(Frame Buffer)概念_图像帧缓存-CSDN博客

        FBO 虽然叫缓冲区对象,但是它并不是一个真正的缓冲区,因为 OpenGL 并没有为它分配存储空间去存储渲染所需的几何、像素数据。我们可以把它认为是一个指针的集合,这些指针指向了颜色缓冲区、深度缓冲区、模板缓冲区、累积缓冲区等这些真正的缓冲区对象。

        我们把这里的『指向关系』叫做附着,而 FBO 中的附着点类型有:颜色附着、深度附着和模板附着。这些附着点指向的缓冲区通常包含在某些对象里,我们把这些对象叫做附件,附件的类型有:纹理(Texture)或渲染缓冲区对象(Render Buffer Object,RBO)。

纹理作为FBO颜色缓冲区的依附

        FBO 本身不直接用于渲染,而是要为其绑定好附件后才能作为渲染目标。所以,建构一个完整的 FBO 需要满足下列条件:

  • 必须往 FBO 里面加入至少一个附件(颜色、深度、模板缓冲);
  • 其中至少有一个是颜色附件;
  • 所有的附件都应该是已经完全做好的(已经存储在内存之中);
  • 每个缓冲都应该有同样数目的样本。

gl.framebufferTexture2D 用来绑定texture附件;

gl.framebufferRenderbuffer 用来绑定renderBuffer附件;

# 渲染纹理(RenderTexture)

        渲染纹理是一张在 GPU 上的纹理。通常我们会把它设置到相机的 目标纹理 上,使相机照射的内容通过离屏的 frame Buffer 绘制到该纹理上。一般可用于制作汽车后视镜,动态阴影等功能。

        在OpenGL/DirectX等图形API中,渲染纹理通常通过 FBO(Framebuffer Object)或类似机制绑定为帧缓冲对象的附件。

// 创建和绑定 FBO:
GLuint fbo;
glGenFramebuffers(1, &fbo); // 创建 FBO
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // 绑定 FBO,注意:如果这里用 glBindFramebuffer(GL_FRAMEBUFFER, 0) 则是激活默认的帧缓冲区// 创建纹理:
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // 创建纹理和分配存储空间。传入 NULL 作为纹理的 data 参数,不填充数据,填充纹理数据会在渲染到 FBO 时去做。
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);// 将纹理添加为 FBO 的附件,连接在颜色附着点:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);// 检测 FBO 是否完整:
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)printf("Frame buffer incomplete!\n");
elseprintf("Frame buffer complete!\n");// ...省略其他代码...
2)使用 RBO 附件下面是一个简单的使用 RBO 附件的例子:// 创建和绑定 FBO:
GLuint fbo;
glGenFramebuffers(1, &fbo); // 创建 FBO
glBindFramebuffer(GL_FRAMEBUFFER, fbo); // 绑定 FBO,注意:如果这里用 glBindFramebuffer(GL_FRAMEBUFFER, 0) 则是激活默认的帧缓冲区// 创建 RBO:
GLuint rbo;
glGenRenderbuffers(1, &rbo); // 创建 RBO
glBindRenderbuffer(GL_RENDERBUFFER, rbo); // 绑定 RBO,所有后续渲染缓冲操作都会影响到当前的渲染缓冲对象
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, m_width, m_height); // 为 RBO 的颜色缓冲区分配存储空间// 将 RBO 添加为 FBO 的附件,连接在颜色附着点:
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);// 检测 FBO:
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)printf("Frame buffer incomplete!\n");
elseprintf("Frame buffer complete!\n");

示例

        用three.js做一个简单的示例,我们先渲染一个平面Plane:

var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 60);
camera.up.set(0, 1, 0);
camera.lookAt(new THREE.Vector3(0, 0, 0));var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x0000FF, 1);     // 渲染器的背景色(蓝色)
document.body.appendChild(renderer.domElement);// 场景
var bufferScene = new THREE.Scene();
// 创建物体
var fboGeometry = new THREE.PlaneGeometry(60, 30);
var fboMaterial = new THREE.MeshBasicMaterial({color: 0xFF0000 // 红色
});
var fboPlane = new THREE.Mesh(fboGeometry, fboMaterial);
// 添加平面到场景
bufferScene.add(fboPlane);renderer.render(bufferScene, camera);

        接下来我们把这个渲染结果作为一个渲染纹理,渲染在另一个相同大小的平面上:

// 前面的代码省略...var bufferTexture = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
// 渲染到目标缓冲区
renderer.setRenderTarget(bufferTexture);
// 渲染
renderer.render(bufferScene, camera);
// 恢复渲染到屏幕
renderer.setRenderTarget(null);var scene = new THREE.Scene();
scene.background = new THREE.Color(0xAAAAAA); // 场景的背景色(灰色)var planeGeometry = new THREE.PlaneGeometry(60, 30);
var planeMaterial = new THREE.MeshBasicMaterial({     map: bufferTexture.texture // 获取渲染目标缓冲区中的纹理
});var plane = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(plane);function render() {requestAnimationFrame(render);renderer.render(scene, camera);
}
render();

        其他示例:Cesium实战篇2 离屏渲染 - 哔哩哔哩

参考

  • 链接:Three.js 渲染目标(Render Targets)技术详解-CSDN博客
  • 链接:three.js中帧缓存的使用_threejs 帧缓存-CSDN博客
  • 链接:FPS、Vsync和Triple Buffer_vsync 和 fps什么关系-CSDN博客
http://www.xdnf.cn/news/12715.html

相关文章:

  • MybatisPlus中LambdaQueryWrapper 校验非空,非空判断
  • 解决cesium加载模型太黑暗,程序崩溃,不显示,位置不对模型太大,Cesium加载gltf/glb模型后变暗,变慢问题
  • x32dbg/x64dbg SwissArmyKnife 插件导入map文件不生效
  • 数论——同余问题全家桶2 不定方程和同余方程
  • 高考:如何合理选择学科、专业以及职业
  • 大模型时代的“思考“与“行动“:人工智能的认知革命
  • 智能仓储解决方案:如何为您的企业选择最佳系统 (提升效率 降低成本)
  • 多模态动态图卷积神经网络及Transformer多头注意力机制设计
  • window查看SVN账号密码
  • Blaster - Multiplayer P145-P152: 多种武器
  • 2025年SDK游戏盾实战深度解析:防御T级攻击与AI反作弊的终极方案
  • 大学课程:计算机科学与技术专业主要课程,是否落伍了?
  • ORM框架(SQLAlchemy 与 Tortoise )
  • idea中 maven 本地仓库有jar包,但还是找不到,解决打包失败和无法引用的问题
  • 【iSAQB软件架构】魔法成功软件项目的矩形
  • D1675/HBT191单通道高清视频放大电路解析
  • DAY 23 pipeline管道
  • 10分钟私有部署Deepseek-R1-0518,打造团队专属AI助手
  • 小牛电动NXT,市场销量第一
  • 嵌入式学习笔记- freeRTOS 带FromISR后缀的函数
  • 打卡day46
  • 【leetcode】3. 无重复字符的最长子串
  • 变频串联谐振试验技术解析
  • 【python基础知识】变量名和方法名的单下划线(_)和双下划线(__)总结
  • Unity基础-数学向量
  • 无刷电机的驱动MOSFET
  • Windows安装 cityflow
  • 超声波清洗设备的清洗效果如何?
  • Python 3.11.9 安装教程
  • 视频监控平台建设方案