Games101-04 Shading着色
处理遮挡-Z-buffering
画画时,先画远的再画近的,前景遮挡背景;遇到两两覆盖的问题之前采用画家算法
Z-buffer:
- 存储当前像素的最小z值(假设z是正的,近的值小,远的值大)
- 需要一个额外的缓冲区来存放深度值
- 帧缓冲区存放颜色值
- 深度缓冲区存放深度
1 | for (each triangle T) |
Q:n个三角形如何排序,排序效率
Shading
不同物体用不同材质(Material - 和光线不同作用)表现的过程
照明和阴影(Blinn-Phong 模型)
漫反射
漫反射无论观察方向在哪里,看到该点的光是一样的,
Shading是局部的(只看该点,不考虑其他物体和阴影),计算在特定着色点反射到相机的光线(shading point),默认不会产生阴影
Lambertian (Diffuse) Shading 朗博着色:着色过程推导如下
设观察方向为 v,光线方向为 I,法线为 n,研究的着色点 shading point,I和n的夹角为
假设反射为漫反射,反射后得到的光为多少呢?
根据朗博余弦定律,单位面积的光与成正比,而且将光源定义为球体,
设总光源强度为I,则球壳上距离光源半径为r的点的强度为
因此,最后计算漫反射光为;
:漫反射光
:漫反射系数,颜色(灰度大小)
:到达着色点的光强,从光源出发点到达着色点衰减后的光强
:接受到的能量反射出去,0用于计算得到负值的情况取0
镜面反射
由于镜面反射着色点不吸收光照,接受多少反射多少,,观察方向与反射方向越近越接近高光,
- 求R和V的夹角也就可以转换为计算n与(I和v夹角/2)之间的夹角→半程向量,通过单位向量的点积测量远近。半程向量和法线足够近就可以看到高光,p为指数,p越大高光越集中,即h和v近
其中,为反射镜面光,为镜面系数
环境光
着色不依赖于任何东西
- 添加恒定的颜色来考虑忽略的照明和黑色阴影
- 近似的
其中,为反射环境光,为环境光系数,为反射的环境光
Blinn-Phong反射模型(布林冯)
那么,什么导致了着色差异?
例如,一个平面做一次shading和一个法线,一个顶点在做一次shading和一个法线,一个像素做一次shading和一个法线,像素效果最好
兰伯特模型
没有高光(镜面反射)
着色频率
- 三角形平面着色(平面着色):一个平面做一次shading和一个法线,不适用于表面平滑的物体
- 顶点着色(高洛德着色):一个顶点在做一次shading和一个法向量,需要内部插值
- 每个像素着色(冯氏着色,双线性插值着色):每个三角形的法向量插值,计算所有像素,不属于布模型
面频率非常高的情况下,着色差异不大
定义逐顶点法向量
- 优先从几何结构直接计算出法线(例如圆切面)
- 否则就从三角形面推断法线,例如平均周围的面法线(顶点所在面加权平均)
- 已知顶点求内部法线:顶点法线的重心插值,规范化方向
图形(实时渲染)管线
- Shader 程序
- 程序顶点和片段处理阶段
- 描述对单个顶点(或片段)的操作
- 步骤
- Shader函数每个片段执行一次
- 输出当前片段屏幕采样位置表面的颜色
- 这个着色器执行一个纹理查找来获得表面的材质颜色,然后执行一个漫反射照明计算(先获得颜色再处理光照)
1 | uniform sampler2D myTexture; |
Texture Mapping 纹理映射
纹理(Texture):即三角形的内部填充图,纹理图表面是2D。
每个3D表面点在2D图像(纹理)中也有一个位置。例如地图展开图
将2D纹理展开放在(U,V)坐标系中,则3D对应的点在该坐标会有(u,v)位置
三角形插值算法
插值:利用它可通过函数在有限个点处的取值状况,估算出函数在其他点的近似值,用来填充图像变换时像素之间的空隙
为什么需要插值算法?
指定顶点值
需要获得三角形上平滑过度的不同值
需要对什么做插值?
- 纹理坐标,颜色,法向量
如何做插值?
- Barycentric Coordinates 重心坐标
重心坐标
设一个三角形坐标系 ,三个坐标点非负;三个顶点为A,B,C,内部点为
若在A点,则 为0
若按面积表示
- 重心将三角形分成三个等面积三角形,计算任意点面积,公式为
- 顶点上的线性插值算法
重心坐标在投影后是不变的,重心坐标和任何点插值投影后不一定是一个点,V可以表示位置,纹理等
简单的纹理映射:漫反射颜色贴图
步骤:
- 对每一个光栅化后屏幕的采样点(x, y),一般是像素点中心纹理映射
- (u,v)表示纹理坐标,查找屏幕上这个点(x, y)对应的纹理坐标
texcolor = texture.sample(u, v)
- 设置采样点颜色为纹理颜色,通常是漫反射系数
纹理太小
对于纹理太小的情况
双线性插值:屏幕上的像素点映射到纹理坐标上不是整数(不是中心)
- 取周围4个样本的纹理值,设周围4个点到该点的水平,垂直距离为(s, t)
线性插值:
已知,从强度加上到的差之间与x相乘
水平上下方向的线性插值:
双线性插值(水平+垂直):可以实现平滑过度
纹理太大
纹理太大出现采样不够,出现摩尔纹锯齿等走样情况
- 超采样:更高质量,更高消耗,信号频率在一个像素内过大,需要更高的采样频率
尝试不采样,计算一个范围内的平均值
例如在一个场景中有前景和背景,前景物体大,一个像素所占的纹理少;背景信息多,所占纹理更多
- Mipmap
一张图生成一系列图,分辨率依次降低,类似 U-Net 先下降分辨率提取不同分辨率的特征,实际上不同的特征就是不同的纹理
通过自己的中心(蓝点)和邻居的中心(红点)映射到纹理空间上位置的与屏幕空间位置之间的差异做插值
计算第 D 层的 Mipmap
三线性插值
在双线性插值的基础上层与层之间做插值,处理层与层之间的渐变,不同深度下场景渐变
个性异向过滤具有更好的效果
纹理应用
环境映射(贴图)
环境光
球环境映射
立方体映射:球体信息记录在立方体上
纹理会影响着色:纹理并不只表示颜色
- 存储高度和法线
- 法线变化,着色变化;相对高度引起法线差异
- 虚假的几何信息
- 凹凸贴图(法线贴图—任一像素的法线扰动)
- 每像素的法线扰动(只影响shading)
- 对纹理定义的每个纹理“高度偏移”
- 高度变化后的法线如何计算?p点坐标为(u,v)
- 2D平面的情况
- 先固定切线,通过切线定义法线,设原始切线
- p处的导数是
- 扰动法线为
- 2D平面的情况
- 3D平面的情况
- 原始表面法线
- p处的导数
- 扰动法线为
- 且这是在本地坐标的情况
- 位移映射(位移贴图)
- 在凹凸贴图上使用相同的纹理
- 实际上是移动顶点
- 3D噪声生成+实体建模
- 提供预先计算好的Shading
- 3D纹理和体积渲染