着色
着色是一个将材质应用到物体的过程。
一、光学基础知识
- 着色是局部的
- 观察者方向 v
- 平面法线 n
- 每一个光线方向 l
- 平面参数(颜色、反光度)
- 每单位的光照等于 l*n
- 光照强度会随着离光源的距离衰减
二、Blinn-Phong光照模型
Blinn-Phong光照模型 = 漫反射+高光+环境光
1、漫反射
- 漫放射独立于视线。
- 光线在各个方向均匀地发散。
- 某点的着色在各个方向是相同的。
L d = k d ( I / r 2 ) m a x ( 0 , n ⋅ l ) L_d=k_d(I/r^{2})max(0,n \cdot l) Ld=kd(I/r2)max(0,n⋅l)
L d L_d Ld:漫反射的光线。
k d k_d kd:漫反射系数。
I I I:光照强度。
r r r:离光源的距离。
I / r 2 I/r^{2} I/r2:光线能量。
m a x ( 0 , n ⋅ l ) max(0,n \cdot l) max(0,n⋅l):光线夹角,超过九十度,结果为负,没有意义。
2、高光
- 光线强度取决于视线方向
- 视线方向越接近镜面反射方向,光线越亮
- v接近镜面反射
⟺
\Longleftrightarrow
⟺ 半程向量接近法向量
h ( 半 程 向 量 ) = v + l ∣ ∣ v + l ∣ ∣ h(半程向量)=\frac{v+l}{||v+l||} h(半程向量)=∣∣v+l∣∣v+l
L s = k s ( I / r 2 ) m a x ( 0 , c o s α ) p = k s ( I / r 2 ) m a x ( 0 , n ⋅ h ) p L_s =k_s(I/r^2)max(0,cos\alpha)^p=k_s(I/r^2)max(0,n\cdot h)^p Ls=ks(I/r2)max(0,cosα)p=ks(I/r2)max(0,n⋅h)p
L s L_s Ls:镜面反射光线
k s k_s ks:系数
冯氏模型与Blinn-Phong模型有一些细微的差别:半程向量与表面法线的夹角通常会小于观察与反射向量的夹角。
Blinn-Phong测量的是法线与半程向量之间的夹角,而冯氏模型测量的是观察方向与反射向量间的夹角。
当物体的反光度非常小时,它产生的镜面高光半径足以让相反方向的光线对亮度产生足够大的影响。在这种情况下就不能忽略它们对镜面光分量的贡献了。[9]
3、环境光
- 目前假设光照强度为常数,如果要很精确计算需要用到全局关照的指数。
L a = k a I a L_a = k_a I_a La=kaIa
L = L a + L d + L s = k a I a + k d ( I / r 2 ) m a x ( 0 , n ⋅ l ) + k s ( I / r 2 ) m a x ( 0 , n ⋅ h ) p L=L_a+L_d+L_s=k_aI_a+k_d(I/r^{2})max(0,n \cdot l)+k_s(I/r^2)max(0,n\cdot h)^p L=La+Ld+Ls=kaIa+kd(I/r2)max(0,n⋅l)+ks(I/r2)max(0,n⋅h)p
三、着色频率
着色的频率不同造成着色的不同。
Flat Shading ( 平面着色 )
- 对三角形进行着色,根据面法向量对光线反射进行计算。
- 三角形较少时,会有块状效果,不适合平滑表面。
Gouraud shading
- 对每个顶点进行着色,发生在顶点着色器阶段。
- 先求出每个顶点的光照颜色,再用重心坐标进行内部插值。
Phong shading
- 对像素进行着色,发生在片段着色器阶段。
- 对多边形每个顶点的法向量进行插值,再去计算光照颜色。
因为模型变换可能会导致模型位置形状发生改变,如果属于该模型的各个三角形面的法线向量不跟着改变的话,那么此时所记录的法线向量就是错误的。因此法线向量一定也要跟着模型本身发生改变。
变换后的: N = ( m o d e l − 1 ) T n N=(model^{-1})^Tn N=(model−1)Tn。[10]
四、图形(实时渲染)管线
-
图形渲染管线是流水线形式
-
模型变换、 视图变换、投影变换:顶点处理阶段
-
将三维图元作为输入,通过采样将其绘制在二维屏幕:光栅化阶段
-
深度测试:片段处理阶段
-
着色:顶点处理阶段(Gouraud shading), 片段处理阶段( Phong shading )
-
纹理映射:顶点处理阶段, 片段处理阶段
五、纹理映射
纹理映射是将纹理空间中的纹理映射到屏幕空间中的过程
- 纹理有纹理坐标(u,v)。
1、重心坐标
重心坐标可以用来进行纹理、颜色等属性插值。
假设存在三角形ABC,三角形内部顶点的坐标可以表示为:
(
x
,
y
)
=
α
A
+
β
B
+
γ
C
,
(
α
+
β
+
γ
=
1
)
(x,y)=\alpha A+\beta B +\gamma C,(\alpha+\beta +\gamma=1)
(x,y)=αA+βB+γC,(α+β+γ=1)
2、纹理过小
当纹理分辨率过小,而需要用来覆盖的物体过大时,多个像素坐标都会采样到同一个纹素,产生一些锯齿的效果,这时我们就有一些解决方法,如:最近邻插值,双线性插值,双三次插值。
1、双线插值
1、对
u
01
u_{01}
u01和
u
11
u_{11}
u11插值得到
u
1
u_{1}
u1,对
u
00
u_{00}
u00和
u
10
u_{10}
u10插值得到
u
0
u_{0}
u0
2、然后再对
u
1
u_{1}
u1和
u
0
u_{0}
u0进行插值得到红点的插值
(水平插值或竖立方向插值都可以。)
2、最近邻插值
取最近的像素进行插值。
3、双三次插值
取最近的十六个点的加权平均得到,类似双线性插值。
2、纹理过大
纹理过大,会导致近处有锯齿,远处有摩尔纹现象。因为近大远小,所以近处需要很高的采样频率,远处不需要很高的采样频率
- 点查询
给定像素点,根据最近邻,双线性,双三次插值得到结果。 - 范围查询
给定一个区域,得到相应的值(平均值等)。
1、MipMap
快速,近似,仅限于正方形范围的范围查询。
通过一张纹理,生成更多高层的纹理。(分辨率每次缩小到一半)。
level 0代表的是原始texture,也是精度最高的纹理,随着level的提升,每提升一级将4个相邻像素点求均值合为一个像素点。
比原来多了
1
3
\frac{1}{3}
31的存储开销。
- 假设Mipmap的层级为D,那么如何确定某个像素P对应的Mipmap层级?
先找到该点和相邻像素点在纹理上的映射点,计算边长L,层级可以由 D = l o g 2 ( L ) D =log _2(L) D=log2(L) 算出。(在第几层会变成一个像素,这就是它的平均值。)
因为D是整数,离散的。会导致出现纹理“割裂”现象。
可以通过三线性插值方法解决:先在D层做双线性插值,再在D+1层做双线性插值,然后根据以上两个值做一次线性插值,得到结果。 - MipMap会出现过曝现象。(即过度模糊)
2、各向异性滤波
- 各向异性滤波能解决过曝现象,它的范围是矩形范围。
- 各向异性是指在不同的方向上表现不同。
开销是原来的3倍。 - 打游戏时会遇到各向异性滤波多少X,其实是压缩到第几层。它跟显存相关,一般开到最大。
- 各向异性滤波只能解决规则的矩形的映射问题,不能解决不规则的图形。
3、EWA滤波
- 用椭圆去近似不规则图形。
- 效果好、但开销大。
六、纹理应用
在现代GPU上 纹理=一块内存+范围查询(滤波)
应用:环境光、存储微观几何、过程纹理 (通过算法生成)、实体建模 、体绘制
1、环境贴图
将环境光存储在一个贴图之上
2、立方体贴图
天空盒
3、凹凸贴图
通过改变相对高度差来改变法线(实际上没有变,在边缘处效果不好)。
先求出切线,根据切线求出法线。
4、位移贴图
真正改变了位置,三角形要足够细。
5、阴影贴图
有些物体会被另一些物体挡住,使得光线照射不到,产生阴影。
可以通过对深度检测,来确定哪些物体有阴影。
七、参考和引用
[1] bilibili:GAMES101-现代计算机图形学入门-闫令琪
[2] 着色(光照与基本着色模型).pdf
[3] 着色(着色频率、图形管线、纹理映射).pdf
[4] CSDN:GAMES101-现代计算机图形学学习笔记(07)
[5] 知乎:GAMES-101 Lecture 05 笔记
[6] 知乎:【GAMES101-现代计算机图形学课程笔记】Lecture 05 光栅化(三角形)
[7] CSDN:GAMES101-现代计算机图形学学习笔记(08)
[8] CSDN:GAMES101-现代计算机图形学学习笔记(09)
[9] learnopengl:高级光照
[10] 计算机图形学五:局部光照模型(Blinn-Phong 反射模型)与着色方法(Phong Shading)
[11] cnblogs:【GAMES101-现代计算机图形学课程笔记】Lecture 09 Shading 3 (纹理映射)
[12] 着色(插值、高级纹理映射).pdf
[13] 几何(基本表示方法).pdf
[14] 计算机图形学八:纹理映射的应用(法线贴图,凹凸贴图与阴影贴图等相关应用的原理详解)
[15] 几何(网格处理)、阴影图.pdf