光栅化渲染管线过程介绍

概要

渲染管线主要分为两种:光栅化渲染管线、光线追踪渲染管线。后者在RTX显卡上支持。
阅读本文需要对渲染管线有一定的了解,本文旨在了解光栅化渲染管线的过程,细节层面没有详细介绍。

主要过程

光栅化渲染管线的主要过程包括:顶点输入、顶点聚集、顶点着色器曲面细分着色器几何着色器、面剔除、裁剪、透视除法、视口变换、光栅化、提前深度测试、片元着色器、模板测试、深度测试、透明度测试、颜色混合、帧缓存输出。

黄色标注的过程为可编程部分,其余的过程为固定部分。

顶点输入

输入多个顶点,每个顶点包含一些属性,例如:位置坐标、颜色、法线、纹理坐标等。

顶点聚集

需要在CPU端指定图元信息,常见的图元包括:点、线、三角形等。
在这里插入图片描述
图元详情介绍

顶点着色器

主要功能是进行坐标变换。
在渲染三维物体时,通常经历:局部坐标 → \rightarrow 世界坐标 → \rightarrow 观察坐标 → \rightarrow 裁剪坐标

曲面细分着色器(可选)

从左到右,三角形细分越来越多
曲面细分人头示例图

几何着色器(可选)

输入是图元,主要功能是新增或删除图元。详情可参考几何着色器
输出图元类型跟输入图元类型无关,输出图元的数量跟输入图元数量无关

几何着色器使用案例:

  • 法线可视化
    在这里插入图片描述
    输入:一个三角形,输出:三个线段
  • 公告牌技术
    公告牌技术就是以2维图片来代替实际模型渲染的技术,使2维图片总是面向摄像机
    在这里插入图片描述
    输入:一个点,输出:一个四边形

面剔除

分为正面剔除和被面剔除
对于一个三角形,顶点顺序为逆时针表示为正面,顺时针表示为背面。可以使用右手螺旋法则来判断三角形的法线。
在这里插入图片描述在这里插入图片描述

裁剪

对于部分位于视椎体的图元,需要对他们进行裁剪操作
裁剪示例图
对位于左下角的线段和右上角的三角形进行裁剪,得到新的顶点

透视除法

裁剪坐标 → \rightarrow NDC坐标

归一化设备坐标(Normalized Device Coordinates,NDC)

NDC坐标范围[-1,1],可以通过NDC坐标的z分量计算出实际的线性深度值
Z v i e w = f a r − n e a r 2 Z n d c + f a r + n e a r 2 Z_{view} = \frac{far-near}{2} Z_{ndc} + \frac{far+near}{2} Zview=2farnearZndc+2far+near

视口变换

NDC坐标 → \rightarrow 窗口坐标
在这里插入图片描述
窗口坐标的z分量表示非线性的深度值,范围在[0,1]。
Z w i n d o w = 1 Z v i e w − 1 n e a r 1 f a r − 1 n e a r Z_{window} = \frac{ \frac{1}{Z_{view}} - \frac{1}{near} } {\frac{1}{far} - \frac{1}{near}} Zwindow=far1near1Zview1near1
在这里插入图片描述

光栅化

光栅化是个离散化的过程,将连续的物体转化为离散屏幕像素点的过程。
在这里插入图片描述
会对顶点着色器的输出数据进行插值,得到各个片段对应的数据值,为后面的片段着色提供片段数据。

两种插值方法如下:

  • 重心坐标插值
    T P = α T A + β T B + γ T C T_P = \alpha T_A + \beta T_B + \gamma T_C TP=αTA+βTB+γTC
  • 透视校正插值
    1 T P = α 1 T A + β 1 T B + γ 1 T C \frac 1 T_P = \alpha \frac 1 {T_A} + \beta \frac 1 {T_B} + \gamma \frac 1 {T_C} T1P=αTA1+βTB1+γTC1
    因为 1 Z A \frac 1 {Z_A} ZA1, 1 Z B \frac 1 {Z_B} ZB1, 1 Z C \frac 1 {Z_C} ZC1是已知的,使用如下公式计算更方便:
    T P = α T A Z A + β T B Z B + γ T C Z C α 1 Z A + β 1 Z B + γ 1 Z C T_P = \frac {\alpha \frac {T_A} {Z_A} + \beta \frac {T_B} {Z_B} + \gamma \frac {T_C} {Z_C}} {\alpha \frac {1} {Z_A} + \beta \frac {1} {Z_B } + \gamma \frac {1} {Z_C}} TP=αZA1+βZB1+γZC1αZATA+βZBTB+γZCTC

提前深度测试

提前深度测试与透明度测试有冲突
开启前提:不能在片元着色器去修改深度缓冲

片元着色器

片元着色器为每个片元计算颜色,用来决定屏幕上像素的最终颜色

常用的贴图技术:

  • 光照贴图:纹理贴图(漫反射贴图)+ 镜面光贴图
  • 法线贴图
  • 凹凸贴图

常用的光照技术:

  • Gouraud着色

  • Phong着色
    在这里插入图片描述

  • Blinn-Phong着色
    Blinn-Phong着色示例图

  • PBR
    L o ( p , ω ⃗ 0 ) = ∫ Ω f r ( p , ω ⃗ i , ω ⃗ o ) × L i ( p , ω ⃗ i ) × ( n ⃗ ⋅ ω ⃗ i ) d ω ⃗ i L_o(p,\vec \omega_0) = \int_{\Omega} f_r (p,\vec \omega_i,\vec \omega_o) \times L_i(p,\vec \omega_i) \times ( \vec n \cdot \vec \omega_i ) d \vec \omega_i Lo(p,ω 0)=Ωfr(p,ω i,ω o)×Li(p,ω i)×(n ω i)dω i

p p p是一个观察的点, ω ⃗ 0 \vec \omega_0 ω 0是出射方向, Ω \Omega Ω表示半球面, ω ⃗ i \vec \omega_i ω i是入射方向, n ⃗ \vec n n 是法线方向
L o ( p , ω ⃗ 0 ) L_o(p,\vec \omega_0) Lo(p,ω 0)表示出射光, f r ( p , ω ⃗ i , ω ⃗ o ) f_r (p,\vec \omega_i,\vec \omega_o) fr(p,ω i,ω o)表示反射率, L i ( p , ω ⃗ i ) L_i(p,\vec \omega_i) Li(p,ω i)表示入射光, n ⃗ ⋅ ω ⃗ i \vec n \cdot \vec \omega_i n ω i表示法向与入射方向夹角的余弦值
∫ Ω d ω ⃗ i \int_{\Omega} d \vec \omega_i Ωdω i表示对入射方向 ω ⃗ i \vec \omega_i ω i,沿着整个半球面 Ω \Omega Ω的积分
在这里插入图片描述
注意: ω \omega ω在这里代表方向的说法并不严谨,实际上是立体角

模板测试

何时更新模板缓冲?
可以在三种时机更新模板缓冲:

  • 模板测试失败时;
  • 模板测试通过,但深度测试失败时;
  • 模板测试和深度测试都通过时。

如何更新模板缓冲?
常用的更新方式有:

  • 不更新
  • 更新为参考值
  • 更新为0

模板函数
模板函数可以设置模板测试函数,参考值,掩码。
常见的模板测试函数有:

  • 一定不通过
  • 一定通过
  • 等于参考值
  • 不等于参考值

参考值会先与掩码进行与运算,然后再与模板缓冲的值进行比较

模板掩码
与将要写入模板缓冲的模板值进行与运算,再将运算后的值写入模板缓冲
通常情况下,值为0xFF表示不改变模板值,值为0x00表示将模板值置为0

物体轮廓绘制示例:

  1. 开启模板测试
  2. 开启模板写入(模板掩码为0xFF)。模板测试函数:测试一定通过,参考值为1。
  3. 正常绘制物体
    在这里插入图片描述
    得到的模板缓冲如下图所示:
    在这里插入图片描述
  4. 关闭模板写入(模板掩码为0x00),模板测试函数:不等于1时测试通过
  5. 然后稍微放大物体,以轮廓色绘制物体
    在这里插入图片描述
    通过的片段如下图所示
    在这里插入图片描述

最终生成的物体轮廓如下图所示:
在这里插入图片描述

深度测试

深度测试简单来说是一个比较当前片元深度值和深度缓冲区中对应深度值大小的过程,比较完后需要决定是否保留片元,是否更新深度缓冲区。
每个片元的z分量中存储着非线性的深度值,值的范围为0~1

Created with Raphaël 2.3.0 开始 是否开启模板测试 模板测试是否通过 是否开启深度测试 深度测试是否通过 模板写入(方式3) 保留片元 是否开启深度写入 ? 深度写入 结束 模板写入(方式2) 丢弃片元 模板写入(方式1) yes no yes no yes no yes no yes no

透明度测试

丢弃不符合透明度条件的片段

颜色混合

混合方程如下:
C r e s u l t = C s o u r c e × F s o u r c e + C d e s t i n a t i o n × F d e s t i n a t i o n C_{result} = C_{source} \times F_{source} + C_{destination} \times F_{destination} Cresult=Csource×Fsource+Cdestination×Fdestination
C r e s u l t C_{result} Cresult表示源颜色, F s o u r c e F_{source} Fsource表示源因子, C d e s t i n a t i o n C_{destination} Cdestination表示目标颜色, F d e s t i n a t i o n F_{destination} Fdestination表示目标因子
目标颜色是在颜色缓冲上的颜色,源颜色是片元着色器输出的颜色

常用的因子有:

  • (0, 0, 0, 0)
  • (1, 1, 1, 1)
  • C s o u r c e C_{source} Csource
  • 1 − C s o u r c e 1-C_{source} 1Csource
  • C d e s t i n a t i o n C_{destination} Cdestination
  • 1 − C d e s t i n a t i o n 1-C_{destination} 1Cdestination
  • A s o u r c e = ( a s , a s , a s , a s ) , 其中 a s = C s o u r c e . a l p h a A_{source} = (a_s, a_s, a_s, a_s), 其中a_s = C_{source}.alpha Asource=(as,as,as,as),其中as=Csource.alpha
  • 1 − A s o u r c e = ( 1 − a s , 1 − a s , 1 − a s , 1 − a s ) 1-A_{source} = (1-a_s, 1-a_s, 1-a_s, 1-a_s) 1Asource=(1as,1as,1as,1as)
  • A d e s t i n a t i o n = ( a d , a d , a d , a d ) , 其中 a d = C d e s t i n a t i o n . a l p h a A_{destination} = (a_d, a_d, a_d, a_d), 其中a_d = C_{destination}.alpha Adestination=(ad,ad,ad,ad),其中ad=Cdestination.alpha
  • 1 − A d e s t i n a t i o n = ( 1 − a d , 1 − a d , 1 − a d , 1 − a d ) 1-A_{destination} = (1-a_d, 1-a_d, 1-a_d, 1-a_d) 1Adestination=(1ad,1ad,1ad,1ad)

通常情况的半透明混合, F s o u r c e = A s o u r c e F_{source} = A_{source} Fsource=Asource F d e s t i n a t i o n = 1 − A s o u r c e F_{destination} = 1-A_{source} Fdestination=1Asource

帧缓冲输出

帧缓冲 = 颜色缓冲( ≥ 1 \geq 1 1个) + 深度缓冲( ≥ 0 \geq 0 0个) + 模板缓冲( ≥ 0 \geq 0 0个)

每种缓冲都可以附加附件,有两种附件:

  1. 纹理附件
  2. 渲染缓冲对象
附件形式优点缺点适用情况
纹理附件可读可写,着色器使用方便读写速度较慢需要从缓冲中采样数据(如颜色)
渲染缓冲对象写入或复制速度快不可读,只可写常被用于绑定深度缓冲或者模板缓冲

参考资料

  1. 【Vulkan入门】六 渲染管线简介
  2. 图形学|shader|用一篇文章理解半透明渲染、透明度测试和混合、提前深度测试并彻底理清渲染顺序。
  3. 细说图形学渲染管线
  4. [数学] 重心坐标插值与透视校正插值
  5. 深入理解 PBR/基于图像照明 (IBL)
  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序鸡

如果帮到您,点个赞鼓励一下吧。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值