【渲染学习随笔】帧缓存(Frame buffer)和帧缓存的模拟实现

  • 帧缓存的概念

在 OpenGL 以及大部分的渲染管线中,帧缓存(Frame buffer)是在实际渲染之前的最后一个步骤。帧缓存本质上是一块内存或者硬件中的空间,负责保存需要渲染图像的像素相关信息。[1]

OpenGL 的渲染管线

帧缓存是一个集合概念,因为帧缓存的内部包括(但不局限于):

  • 颜色缓存 Color buffer:记录像素颜色信息,很多帖子也将颜色缓冲当作帧缓冲的主体。 [2]
  • 深度缓存 Z buffer:记录像素深度值。
  • 模块缓存 Stencil buffer:限制渲染区域,可以和深度缓存一起创造不同的渲染效果 。[3]
  • (还有其他的缓冲,在此不做赘述)
  • 为什么需要帧缓存

帧缓存的存在是为了在渲染到屏幕或者说传到窗口缓冲区之前能对图像进行后期处理 (Post-processing)等其他操作。帧缓存也实现了离屏渲染。

  • 离屏渲染(Off-screen rendering)

这里摘自 [4] :

GPU屏幕渲染有以下两种方式:

On-Screen Rendering意为当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行。

Off-Screen Rendering意为离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。

大致意思可以理解为,立刻在屏幕上显现的渲染是当前屏幕渲染,渲染而不立刻显现在屏幕上的既是离屏渲染。

离屏渲染可以实现对图像的后期处理,也可以避免 GPU 因为性能问题导致无法顺利绘制一帧的全部内容,从而可以避免因为硬件问题导致的跳帧,也可以用来做抗锯齿等功能(关于离屏渲染的具体作用还是不是很懂,欢迎指正)

离屏渲染的代价也是比较高的,主要是为空间上(需要单独开辟一块内存)和时间上(需要在屏幕渲染缓存和离屏缓存间来回切换)的性能损耗。

  • 帧缓存的模拟实现

最近一直在拜读 BlauHimmel 大神的光栅器代码 [5],里面有模拟帧缓存的实现部分,大致结构如下:

// 作者:Yuming Zhou BlauHimmelSimple-3D-Renderer
// 改动:DamienTian

/*
// 帧缓存结构 frameBuffer -> |----8----|----8----|----8----|----8----| R G B zBuffer -> 1 / z |---- h * sizeof(void*)----|----height * sizeof(void*)----|----1024 * sizeof(void*)----|----w * h * 4----|----w * h * 4----|----64----| _frameBuffer _zBuffer _texture frameBuffer zBuffer ptr ->frameBuffer ->zBuffer ->ptr */ void Framebuffer::Init(_INT32 width, _INT32 height, _PVOID buffer) { //需求空间(根据上面空间分配所得) int need = size(void*) * (height * 2 + TEXTURE_MAX_SIZE) + sizeof(char) * width * height * 8; char* ptr = new char[need + 64 * sizeof(char)]; // Framebuffer 指针索引 char* frameBuffer; char* zBuffer; assert(buffer != NULL); // 分配索引空间 _buffer = ptr; _frameBuffer = (unsigned int**)ptr; ptr += sizeof(void*) * height; _zBuffer = (float**)ptr; ptr += sizeof(void*) * height; // 分配实际空间 frameBuffer = ptr; ptr += sizeof(char) * width * height * 4; zBuffer = ptr; ptr += sizeof(char) * width * height * 4; if (buffer != NULL) { frameBuffer = (char*)buffer; } // 链接索引与内容 for (auto i = 0; i < height; i++) { _frameBuffer[i] = (unsigned int*)(frameBuffer + sizeof(char) * width * 4 * i);
    _zBuffer[i]
= (float*)(zBuffer + sizeof(char) * width * 4 * i);
  }
// ... 后续内容省略,有兴趣看的我强推大佬的代码!
// 大神代码的讲解:https://www.jianshu.com/p/feef32f96552
}

 注:其实代码中的 _frameBuffer 更像是一个颜色缓存,他存储的是每一个像素的颜色信息。

  而 _buffer 则更像是概念上的帧缓存,在代码中它包括了颜色缓存和深度缓存两个部分。

 

参考资料:

[1] 基本概念:https://blog.csdn.net/weixin_34210740/article/details/93428008?utm_source=app

[2] 颜色缓冲: https://www.oreilly.com/library/view/opengl-programming-guide/9780132748445/ch04lev2sec1.html

[3] 模块缓冲:https://en.wikipedia.org/wiki/Stencil_buffer

[4] 什么是离屏渲染:https://www.jianshu.com/p/f62e81b72bba

[5] 帧缓存的模拟实现:https://github.com/BlauHimmel/Simple-3D-Renderer

图片:

OpenGL渲染管线:https://glumpy.github.io/modern-gl.html

posted @ 2020-09-13 11:49  DamienTian  阅读(1770)  评论(0编辑  收藏  举报