延迟渲染 Deferred Rendering

news/2024/11/26 1:22:17/

前向渲染
先计算光照再裁剪。

前向渲染是现在最基础,也是最多引擎使用的标准。前向渲染的流程是给定一个几何体,引擎对其进行从顶点到像素着色器的一系列计算,然后输出到最终的图像缓冲区。场景中有多个几何体时,引擎就是对其挨个进行渲染,完成一个再继续下一个。

前向渲染的问题
前向渲染有一个问题就是无效渲染太多,比如场景中有四个物体,互相之间存在叠压关系,按照前向渲染的流程,先前渲染了一个物体之后,它的一部分被后一个渲染的物体挡住了,那么被挡住的这部分就是无效的计算,毕竟我们在屏幕上是看不到这部分的。

另一个问题在于难以支持过多的光源,对于每个需要逐像素计算的光源,渲染一个几何体的时候需要逐个做一次光照计算。如果有一个场景,其中有10个几何体需要进行渲染,有四个光源对整个场景产生影响,那么渲染整个场景需要进行40次光照计算。而且其中还有很多的计算被挡住了。

前向渲染的优点
如果需要在场景中使用多个着色模型,甚至是每个几何体都使用不同的着色模型和渲染技术,前向渲染是可以很好的支持的。

另外,因为前向渲染这种逐个渲染的特点,它非常适合渲染半透明物体。
在这里插入图片描述
上面图中就是简单的前向着色的示意图。一个几何模型,进入渲染流程中,首先就是要经过顶点着色器的计算,顶点着色器一般会对顶点做空间变换,有的还有顶点位移和UV偏移等计算。经过顶点着色器之后就到了曲面细分着色器,这个阶段是可选的,用来给模型的表面增加顶点数,并且产生更细微的凹凸,当然游戏中的大部分模型是不会做这个阶段的计算的,一般用在高质量游戏的渲染。几何着色器也是可选的,一般会用来做基于模型表面的顶点渲染出一片草丛等功能。像素着色器当然是大部分模型都要经历的,用来做采样贴图和计算光照等计算。

前向渲染优化策略——前向实时剔除
前向渲染的缺点这么明显,难道没有人想办法解决一下吗?当然有一些解决办法的,比如Early-z 、Z-Prepass 、 Hi-Z 等剔除方法。

Early-z : 传统的渲染管线中深度测试是在计算完光照之后才进行的,但是计算完光照再进行深度剔除,被挡到的部分就白计算了。在光栅化阶段,每个模型的深度就已经写入深度缓存了,为什么不先进行深度剔除再计算光照呢?这就是Early-z功能,这也是现在所有硬件和渲染管线都有的功能。
Z-Prepass :上面说的Early-Z优化虽然是在每个模型计算光照之前就进行了深度剔除,但是还是不能完全避免无效光照计算的问题。比如第一个模型渲染的时候,深度通道是没有信息的,这时哪怕这个模型会被后来渲染的模型完全遮挡,它也会计算光照。Z-Prepass就可以解决这个问题,首先把整个场景中的模型都渲染一遍,全部都写入Z-Buffer ,这次渲染除了Z-Buffer其他的信息都不计算。然后再渲染一遍场景,这次渲染关闭深度写入,每个像素和Z-Buffer中已经存在的深度信息进行对比,只有通过测试的像素才会计算光照。这种方法虽然避免了无效的光照计算,但是却执行了两次顶点着色器,所以最好是在场景中物体的光照计算非常复杂但是顶点数量却不是很多的情况下使用。
Hi-Z :上面两种方法都是在GPU段进行的,而Hi-Z这种方法是在CPU端进行的,在几何体被提交到GPU之前会进行遮挡测试,如果几何体被别的物体遮挡了就不会提交到GPU 。这种方法直接减少了GPU需要渲染的几何体数量,适用于细碎且数量多的模型。
延迟渲染
先裁剪再计算光照。

延迟渲染可以支持大量的实时光照,所以现在的大型电脑游戏基本都已经是延迟渲染了。

延迟渲染就是把光照计算延迟到深度测试之后的渲染方式,延迟着色适合在场景中实时光照很多的情况下使用,而且延迟着色可以对每个光源都按逐像素的方式计算。那Z-prepass也是先渲染出深度缓存进行深度测试后再计算光照的,和延迟渲染有什么不同?最大的不同点就在于G-buffer ,Z-prepass在深度测试后也还是按照一个几何体渲染完再进行下一个这种方式来渲染的 ,延迟渲染是几何体的信息传递到G -buffer之后就和几何体没多大关系了,接下来的操作都是对G-buffer进行的。

如果说前向渲染中几何体数量N和光照数量M产生的计算量是N*M的话延迟渲染产生的计算量就是N+M 。这是因为延迟渲染的思路就是先把几何体的信息都渲染到二维空间中(G-Buffer),然后把G-Buffer整体进行光照计算,G-Buffer中存在的信息都是会最终呈现在屏幕上的,不会有无效计算。

那么G-Buffer中到底会储存哪些信息?不同的引擎对于G-Buffer的处理也是不一样的,对于一个针对PBR渲染的引擎来说,至少会有深度、模板、颜色、法线、世界位置、金属、粗糙、高光这些信息。

在这里插入图片描述

延迟渲染的优点
当场景中所有几何体都写入G-Buffer之后,光照计算就和场景中有多少物体,多少三角形没有关系了。

只渲染可见的像素,不会有无效的计算。

延迟渲染的缺点
延迟渲染要求场景中要使用更少的Shader种类,毕竟如果每个模型的每个材质都使用不同的Shader ,那到底应该在G-Buffer中储存哪些信息呢?这对于程序和项目管理上来说可以说是个巨大的优点,可以节省性能,优化流程什么的。但是对美术来说却是个大缺点,因为限制了美术的表现效果。

前向渲染只需要深度缓冲和最终的颜色缓冲就够了,延迟渲染需要缓存的信息实在太多了,这造成了带宽的开销大幅增加。这也是为什么现在的手机游戏基本都是前向渲染的原因,毕竟手机带宽太小,延迟渲染虽然看起来很美好,但是用不了。

对于半透明无能为力,所有半透明的物体都需要等待不透明物体以延迟渲染完成之后,在用前向渲染的方式渲染半透明物体。

分块延迟渲染
虽然延迟渲染已经把光照数量和三角形数量不再关联了,但是当场景中的光源数量不断上升之后,就算是延迟渲染也有点撑不住。

这时就需要分块延迟渲染,它的思路是把G-Buffer分成很多个小块,分析每个小块受到哪些光源的影响,然后逐个分块进行着色,那些受光源影响的数量少的小块就不需要那么多的光照计算了。这种渲染方式在光源数量少的情况下效果不明显,但是光源数量越多它优化的性能也就越多。


http://www.ppmy.cn/news/49098.html

相关文章

learn C++ NO.1——命名空间域、输入输出、函数重载

前言 什么是C C(c plus plus)是一种计算机高级程序设计语言,由C语言扩展升级而产生,最早于1979年由本贾尼斯特劳斯特卢普在AT&T贝尔工作室研发。C语言是结构化和模块化的语言,适合处理较小规模的程序。对于复杂的…

【react】react18的学习(四)--复合组件通信

上一篇:【react】react18的学习(三)–hooks组件 1、父子通信:props、ref 父传子:props 传给子组件状态数据;特殊地,props.children:将元素内容传给子组件;所以不要手动…

如何使用 Python 爬虫抓取动态网页数据

如何使用 Python 爬虫抓取动态网页数据 随着 Web 技术的不断发展,越来越多的网站采用了动态网页技术,这使得传统的静态网页爬虫变得无能为力。本文将介绍如何使用 Python 爬虫抓取动态网页数据,包括分析动态网页、模拟用户行为、使用 Seleni…

PID原理

PID控制器(比例-积分-微分控制器),由比例单元(P)、积分单元(I)和微分单元(D)组成。 可以通过调整这三个单元的增益Kp,Ki和Kd来调定其特性,PID控制…

注释和关键字

注释 注释概念 ●注释是在程序指定位置添加的说明性信息 ●简单理解:对代码的一种解释说明,方便我们程序员更好的去阅读代码 例如: public class HelloWorld {//这是通过class定义了一个类,类名叫HelloWorld public static voi…

学会这些Jmeter插件,才能设计出复杂性能测试场景

为什么要使用jmeter线程组插件呢? jmeter自带的线程组插件模拟的压测场景非常有限,当需要模拟复杂压测场景的时候,推荐大家使用jmeter线程组插件。 如何下载jmeter线程组插件呢? 早期版本的jmeter可以针对我们需要的扩展功能&a…

【C/C++】format 格式化方法使用技巧(代码实例,皆可运行)

printf 当使用__attribute__((format(printf, ...)))语法时&#xff0c;可以使用printf函数作为一个例子来说明它的作用。下面是一个简单的示例代码&#xff1a; #include <stdio.h>void my_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));vo…

源码简读 - AlphaFold2的2.3.2版本源码解析 (1)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/130323566 时间&#xff1a;2023.4.22 官网&#xff1a;https://github.com/deepmind/alphafold AlphaFold2是一种基于深度学习的方法…