实时渲染 -- 光栅化(Rasterization)

图元(Primitive)


在进行渲染之前,我们需要输入装配图元数据,因此需要先定义图元结构,一般有:三角形、四边形、多边形、线段、点

最常用的图元就是三角形了,选择它的理由有很多:

  • 三角形是最基础的几何面,可以组成任意边形
  • 在三维空间中,3个顶点组成的面一定是三角形,但4个顶点组成的面不一定是四边形(例如一张纸沿对角线折叠)
  • 三角形一定是凸多边形(凹多边形很容易导致算法错误或者更复杂的算法实现)
  • 三角形可使用易于实现的三角插值

三角形遍历(Triangle Traversal)

有了图元数据后,经过MVP变换和视口变换(Viewport Transform)后会得到屏幕空间上的顶点数据(三角形顶点无论如何变换最后顶点组成的形状仍然为三角形),而接下来就需要使用光栅化去将这种顶点数据生成用于显示的像素数组。

 

基于屏幕像素的采样

一个最简单的想法就是将屏幕像素进行遍历,测试其每个像素是否在三角形内部。可以预见的是,这种光栅化方式必然带来极高的时间复杂度

for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)image[x][y] = inside(Vector2(x+0.5,y+0.5),tri);//判断点在三角形内部,若在内部则返还1,若在外部则返还0
int inside(Vector2 p,Vector2 vertexs[3]){for(int i = 0; i < 3; ++i){//假设三角形的边edge都是逆时针方向Vector2 edge = vertex[(i+1)%3]-vertex[i];Vector2 vec = vertex[i] - p;int result = cross(edge,vec);//若点在三角形内,得到的叉积值应均为正数if(sign(result) == 0) return 0;//注:无背面剔除时,得到叉积值均为正数或者均为负数时都应返还true}return 1;
}

 

基于包围盒的采样

一个更好的方法是,用包围盒对三角形进行包围(可使用AABB盒),然后无需对整个屏幕的像素进行循环遍历,而只需对包围盒范围内的像素进行循环遍历:

基于自增的采样

还有一个做法:

  1. 从最下边的一行(顶点的最小y值)开始,找到最左边的格子(顶点的最小x值)作为起点
  2. 从左往右遍历,一旦遇到0就停止遍历。
  3. 回到起点,然后往上一行,开始从左往右寻找新起点,一旦遇到1(意味着找到新起点了)就停止遍历
  4. 找到新起点后重复步骤2和3,直到找不到新起点(这意味着步骤3最终遍历到了顶点最大x值)

虽然循环次数少了(可能适用于狭长的三角面),但由于实现复杂,且不容易实现并行化计算(每一行每一列都有依赖关系),因此实际效率并不会快多少。

抗锯齿(Anti-Aliasing)

信号与采样

光栅化的采样会遇到一些走样(Aliasing)问题:锯齿现象、摩尔纹。

锯齿:光栅化不可避免的问题就是会产生锯齿,其原因在于屏幕像素的采样是离散的,不可能精确表示三角形。

摩尔纹:摩尔纹是采样时可能会出现的另一种不理想的怪异现象。

 

解释走样问题之前,首先我们来认识一下信号:信号本质上就是一个函数,输入参数,输出结果。对于任何函数f(x),都有两种表现形式:时域、频域。其中我们最常见的便是时域的形式,也是现实世界的直观形式,可以理解成即f(x)本身,把x当成时间,那么时域便是分析函数值关于时间x的关系。

而傅里叶告诉我们,任意一个函数 f(x)可以由若干个频率不同、振幅不同的余弦函数相加而成。

 

当我们每隔一定间隔采样 f(x),实际上就是每隔一定间隔,分别采样这些组成信号的余弦波并相加起来。下图可以看到,低频余弦波的采样结果与实际余弦函数差别并不大,但是随着频率越来越高,余弦波的采样失真越来越严重了。

尤其最下面的高频余弦波,本该是剧烈起伏的,采样的结果却是平缓起伏,与实际结果已经严重不一致

 因此,我们可以得出结论:当采样频率过低(采样间隔过大)时,信号中的高频信息会失真,这也是走样问题的来源。反走样要做的就是尽可能让高频信息量减少(高频余弦波的振幅减少)。

那么,对于目标采样频率(目标分辨率)的反走样基本原理为:

  1. 先把原始图片当成一种信号,即信号 f(x)输入一个二维位置x,输出一个像素颜色值(那么自然而然,这张图片也可以由若干个不同频率的余弦波组成)

  2. 接下来,我们对时域函数(图片信号)进行卷积操作(即模糊图片),卷积操作实际上就是每个点取周围(包括点本身)的平均值。

容易想象得出到,经过卷积后的时域函数 f(x) 会变得更加平缓(图片变得更加模糊)。这样分离出来的高频余弦波振幅更加小,换句话说,相当于我们把高频信息剁掉了。

        3. 最后,我们对这张卷积后的图片进行目标频率的采样,就能得到走样现象不明显的目标分辨率图片。

SSAA(超采样抗锯齿) 

SSAA(Super Sampling Anti-Aliasing 超采样抗锯齿):先进行高频率的采样并着色到高分辨率的buffer上,然后目标分辨率下的每个目标像素颜色会综合混合高分辨率buffer中对应的多个像素颜色去生成目标画面。(相当于,先进行高频率采样,接着进行卷积操作,最后再进行目标频率采样得到目标分辨率图片)

例如,在4xSSAA算法中,假设最终屏幕输出的分辨率是800x600, 4x SSAA就会先光栅化到一个分辨率1600x1200的buffer上并逐个像素着色,然后再直接把这个放大4倍的buffer下采样至800x600的画面

SSAA 是一种最原始的抗锯齿方法,虽然得到的图片锯齿感少了很多,代价是:例如4x SSAA,光栅化和着色的计算负荷都比原来多了4倍,buffer存储空间的大小也比目标分辨率多了4倍。

MSAA(多重采样抗锯齿)

MSAA(MultiSampling Anti-Aliasing 多重采样抗锯齿) 也是一种超采样的抗锯齿方法,但是做法更加聪明:光栅化只在采样时采样更多点,最后根据每个像素格子采样结果的覆盖率来填入像素格子。(相当于,先进行卷积操作,最后再进行目标频率采样得到目标分辨率图片)

实际应用的话,采样点位置不一定是标准细分正方形的中心位置,也可以是不规则分布的位置。

可以看到,4x MSAA在光栅化计算负荷比原来多了4倍,但是到了像素着色(pixel shading)阶段的时候,每个目标像素只着色1次(4x SSAA对应一个目标像素则需要计算4个高分辨率像素,即4次着色),而且也不需要更大的buffer存储(4x SSAA需要4倍的buffer存储)

MSAA的一个问题就是和延迟渲染(Deferred Shading)框架并不是那么兼容。因为用延迟渲染的时候场景都先被光栅化到GBuffer上去了,不直接做着色。

FXAA(快速近似抗锯齿)

FXAA(Fast Approximate Anti-Aliasing 快速近似抗锯齿) 是一种图像后处理技术。它先直接采样得到目标图像,然后通过像素颜色检测边缘。这种方法使得颜色变化剧烈的像素会被认为是边缘,精度可能不好,但是处理速度非常快。

它不属于先前的信号反走样思路,而是属于一种让画面看上去更舒服的trick。

后处理技术的抗锯齿方法一般没倍数概念,这是因为图像不存在放大。

TAA(帧间抗锯齿)

TAA(Temporal Anti-Aliasing 帧间抗锯齿) 是最常用的图像后处理技术。

TAA 的核心思想是将采样点从单帧分布到多个帧上(从时间的维度上去采样),即对上一帧图像对应的位置进行采样,得到的像素以一定比例混入当前帧的图像像素中,这样当连续的多个帧的数据混合起来以后,就相当于对每个像素进行了多次采样。

采样时还需要进行抖动操作(即每帧采样的位置有一定随机偏移),这是避免画面静止时导致重复对相同的位置采样从而导致整个图像相当于采样次数没有增加,造成抗锯齿失效。

其中,TAA 使用了运动矢量(motion vector)来确定前一帧在何处进行采样,然后将与当前帧的像素进行混合。

所谓运动矢量,其实就是一个空间中的物体(更准确说是物体像素点)在上一帧的位置与下一帧的位置之差,这往往要借助G Buffer信息来找到,具体算法稍微复杂。

TAA 的缺点是,由于每一帧图像的像素颜色实际上是根据以前的帧来进行混合的,因此容易产生画面延迟感;而且当物体运动过快时,会出现物体的残影现象。

TXAA

TXAA 是后来NVIDIA提供的抗锯齿技术,实际上就是TAA+MSAA的组合。

通过引入额外的深度信息来支持在延迟渲染(Deferred Shading)上使用MSAA,TXAA综合了MSAA的强大能力与类似于CG电影中所采用的复杂的高画质过滤器。还可以抖动帧与帧之间的采样位置来获得更高画质。

DLSS(深度学习超采样)

DLSS(Deep Learning Super Sampling 深度学习超采样技术) 则是NVIDIA在Turing架构的时候推出的基于深度学习方法的图像后处理技术。

DLSS 1.0 的基本工作原理是:利用NVIDIA神经图形框架NGX,在超级计算机中以极低的帧率和每像素64个样本对数万张高分辨率的精美图像进行离线渲染,训练出一个深度神经网络。基于无数个小时的训练所获得的数据,网络就可以将分辨率较低的图像作为输入,输出一个高分辨率的精美图,并在一定程度上避免了出现 TAA 等传统方法的模糊、不清晰和透明问题。

DLSS 也不属于先前介绍的信号反走样思路,而是通过低分辨率画面去”猜测“出高分辨率画面,这种猜出来的信息已经不算是来源于正确的原始信号了。

DLSS 2.0 则额外依赖了G Buffer的信息(这点与TAA有一定相似),从而“猜测”更加有依据、精确,能够输出锯齿现象更加轻微、画面更加清晰的高分辨率画面。

可见性/遮挡(Visibility/Occlusion)


前面我们知道如何将一个三角形光栅化到屏幕上,而接下来的问题是当场景中有大量三角形时,我们还需要将它们光栅化的结果综合起来。

画家算法(Painter's Algorithm)

画家算法是最原始的算法,就是简单地将三角形进行排序,根据z值(离摄像机的前后距离)的顺序,将三角形逐个进行光栅化,并且当光栅化遇到冲突时(以前有三角形光栅化占据了这个像素)强制覆盖之。

画家算法的缺点:

  • 以三角形的z距离进行排序,需要一定开销,时间复杂度为O(nlogn)�(�����),n为三角形个数
  • 以三角形为单位可能会发生不准确的z值排序,如画家算法无法渲染出下图

深度测试(Z-Test)

Z-Test则是一种主流且被硬件支持的遮挡剔除技术,其原理是提供一个额外存储最小z值的buffer(经过变换后的坐标z值越小,实际上就是越接近摄像机),这样实际有两个buffer:

  • frame buffer:负责存储像素颜色,也就是存储图像用的
  • z-buffer(depth buffer):负责存储深度值(z值)

Z-Test技术实际上就是:每次光栅化且像素着色(Pixel/Fragment Shader)后的每个像素z值先和z-buffer的对应像素深度进行比较,若更小(意味着离摄像机更近),则像素颜色写入frame buffer对应位置且z值覆盖写入z-buffer对应位置;若更大,则抛弃(discard)像素。

for (each triangle T)
for (each sample (x,y,z) in T){if (z < zbuffer[x,y]){      // closest sample so farframebuffer[x,y] = rgb; // update colorzbuffer[x,y] = z;       // update depth}else{;} // do nothing, this sample is occluded
}

总结Z-Test有如下特点:

  • Z-buffer的时间复杂度是O(n),n为三角形个数
  • 绝大部分GPU硬件都实现了Z-Test算法,可以较快执行

Early-Z

Z-Test的一个缺点是,当花费了较多的像素着色计算(Pixel/Fragment Shader 负责光照和纹理采样等大量计算)后得到的像素点有可能被抛弃,这就造成了计算性能的浪费。而 Early-Z 的原理就是把Z-Test的操作提前到光栅化之后和像素着色之前,这样就避免了本就该被抛弃的像素进行额外的像素着色计算。

有一些情况是不适用于Early-Z技术的:像素着色计算可能会修改z深度值、Alpha Test等。这时候用Early-Z技术是不准确的,必须老老实实用Z-test,即等到光栅化和着色后才决定是否抛弃像素。

然而Early-Z性能是不稳定的,最坏情况就是从远到近渲染每个三角形,这样对每个三角形的所有像素都要进行像素着色计算(代价和Z-test一样),而最好情况就是从近到远渲染,这样就不会出现overdraw。

Z-prepass 改进:使用额外一个pass(理解成跑多一次管线流程),每个三角形光栅化后仅写入深度而不做任何像素着色计算(不输出任何颜色),这样所有三角形通过第一个pass后,我们可以得到记录最小z值的屏幕深度图(实际就是z-buffer);而第二个pass则作为正常渲染流程,只是每个三角形光栅化后需要关闭深度写入并通过比较深度(比较是否相等)来决定是否进行该像素的着色计算,这样就能保证屏幕每个像素只可能对应有最多一次像素着色计算。

总结Early-Z有如下特点:

  • Early-Z相比Z-Test更节省掉可能的像素着色计算,也是被大部分GPU硬件所实现的硬件技术,可以较快执行
  • Z-prepass 则是配合Early-Z的软件技术,解决了Early-Z性能不稳定的问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/422850.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安装向量数据库milvus可视化工具attu

使用docker安装的命令和简单就一个命令&#xff1a; docker run -p 8000:3000 -e MILVUS_URL{milvus server IP}:19530 zilliz/attu:v2.3.5sunyuhuasunyuhua-HKF-WXX:~/dockercom/milvus$ docker run -p 8000:3000 -e MILVUS_URL127.0.0.1:19530 zilliz/attu:latest yarn run…

k8s使用ingress实现应用的灰度发布升级

v1是1.14.0版本nginx ,实操时候升级到v2是1.20.0版本nginx&#xff0c;来测试灰度发布实现过程 一、方案&#xff1a;使用ingress实现应用的灰度发布 1、服务端&#xff1a;正常版本v1&#xff0c;灰度升级版本v2 2、客户端&#xff1a;带有请求头versionv2标识的请求访问版…

STP生成树

0x00 前言 关于STP生成树的一些问题和笔记 0x01 正文 二层环路带来的问题有&#xff1f; 广播风暴MAC地址漂移 什么是广播风暴&#xff1f; 相当于在环形中&#xff0c;大家不停的反复进行泛洪广播&#xff0c;从而导致出现广播风暴耗尽所有资源的情况。 什么是MAC地址漂…

《WebKit 技术内幕》学习之八(3):硬件加速机制

3 其他硬件加速模块 3.1 2D图形的硬件加速机制 其实网页中有很多绘图操作是针对2D图形的&#xff0c;这些操作包括通常的网页绘制&#xff0c;例如绘制边框、文字、图片、填充等&#xff0c;它们都是典型的2D绘图操作。在HTML5中&#xff0c;规范又引入了2D绘图的画布功能&a…

html 3D 倒计时爆炸特效

下面是代码&#xff1a; <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>HTML5 Canvas 3D 倒计时爆炸特效DEMO演示</title><link rel"stylesheet" href"css/style.css" media"screen&q…

旅游项目day08

1. 旅游日记&#xff08;游记&#xff09; 后端&#xff1a;实体类&#xff0c;列表&#xff0c;查看&#xff0c;审核 前端&#xff1a;目的地明细中-游记->带范围条件查询&#xff0c;游记首页&#xff0c;【扩展】游记添加/编辑&#xff0c;【扩展】添加游记时间没登录时…

第十二站(20天):C++泛型编程

模板 C提供了模板(template)编程的概念。所谓模板&#xff0c;实际上是建立一个通用函数或类&#xff0c; 其 类内部的类型和函数的形参类型不具体指定 &#xff0c;用一个虚拟的类型来代表。这种通用的方式称 为模板。 模板是泛型编程的基础, 泛型编程即以一种独立于任何特定…

代码随想录刷题题Day40

刷题的第四十天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C Day40 任务 ● 392.判断子序列 ● 115.不同的子序列 1 判断子序列 392.判断子序列 思路&#xff1a; 动态规划 &#xff08;1&am…

《高教学刊》是什么级别的期刊?是正规期刊吗?是核心期刊吗?

​标题解答 1、《高教学刊》是什么级别的期刊&#xff1f; 省级 2、《高教学刊》是核心期刊吗&#xff1f; 不是&#xff0c;只是封面有核心字样 《高教学刊》刊发高等教育教学与高教理论研究成果&#xff0c;交流高校教学与建设的改革措施和实践经验&#xff0c;探索高等教…

【Linux】解决普通用户无法进行sudo提权

当某个普通用户进行sudo指令提权的时候&#xff0c;可能存在无法操作的问题&#xff0c;如下图&#xff1a; 这个图中有一个细节&#xff0c;我们使用sudo进行提权的时候&#xff0c;用的可是zhangsan的密码&#xff0c;因此有人可能会有疑问&#xff0c;这不是有问题吗&#x…

1 认识微服务

1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.0.学习目标 了解微服务架构的优缺点 1.1.单体架构 单体架构&#xff1a;将业务的所有…

windows下载安装ffmpeg最新版

windows环境搭建专栏&#x1f517;点击跳转 win系统环境搭建&#xff08;十六&#xff09;——windows下载安装ffmpeg最新版 文章目录 win系统环境搭建&#xff08;十六&#xff09;——windows下载安装ffmpeg最新版1.下载2.安装3.验证 1.下载 下载页面地址是https://ffmpeg.…