Shading(着色)
Shading(着色)
Visibility/Occulusion(可见性/遮蔽)
Painter’s Algorithm 从后往前画
但是由于自遮挡的关系,有些无法具体描述远近的(如上图左右面的绘制),绘制顺序显得尤为重要。
左,下,右,上,这个顺序结果正确
但是右,上,左,下,由于左下两面的错误遮挡,导致结果错误。
假如一个模型是两个蛇状管道相互缠绕组合而成的,那渲染先后的问题就更加困难,正方体能够区分不同面无非是一个面遮挡另一个,后者不规则的分区有着非单一的复杂遮挡关系,如此看来这种算法局限性也很大
结论: 一定程度上画家算法是有效的,但是sorting layer的问题是难以解决的。
ZBuffer 深度缓存
为了解决画家算法的问题,引入深度缓存
简而言之,对每个像素的深度进行保存,保留最近的那个深度值
- framebuffer存颜色值
- depth buffer(z-buffer)存深度值
效果如下图,记z值为positive
具体代码实现算法,记初始zbuffer的值都是无限大,每绘制一个图元都来一次二重循环遍历所有像素,不断装填覆盖更小的z
时间复杂度O(n),设三角形个数为n,三角形之间覆盖的个数为常数个。
zbuffer的算法显然是一个很好的解决方法。
【提高】
MSAA常用于反走样,一个像素中有多个采样点,然后根据采样点的分布率来评判该像素颜色深浅
如果绘制有重叠部分的两个三角形,对于抗锯齿的部分,如果只是对像素进行z-buffer,然后边缘锯齿用MSAA,
结果也还行。
想要更好的结果,我们也许可以对采样点进行zbuffer,毕竟像素是呆板的块状,如果能够进一步细化,或许分布率不会变,却也能让先后关系更精确,进而结果更精确。
Illumination&Shading
BlinnPhong Model
布林冯光照模型
三个相加等于着色结果
着色是局部的
着色不等于阴影(shading != shadow)
n是法线向量,h是半程向量(入射光向量l与眼睛视线向量v的和的单位向量)
以下为布林冯的高光
最终结果
Shading Frequency 着色频率问题
Graphics Pipeline(Real-time rendering)
图形渲染管线,实时渲染管线
Application 应用阶段,输入顶点数据
Geometry 几何阶段
Rasterization 光栅化阶段
Shading 着色(shaded fragment)
framebuffer (严格来说属于光栅化)
输出屏幕
除了常规的fragment shader,vertex shader
现在还有compute shader(通用),geometry shader(几何shader)等可编程部分
Texture Mapping
每个三角形顶点都有一个uv坐标(0,1),可以反复平铺
Barycentric coordinates(重心坐标)
【注意】 我们首先要区别点的重心坐标和三角形的重心坐标
interporate across triangle在三角形内进行插值,希望三角形内部得到平滑过渡
α,β,γ均大于等于0,重心在三角形内
A点在重心坐标系的重心坐标(α,β,γ)为(1,0,0),B为(0,1,0)
三角形的重心坐标计算公式就是相加除以3,重心坐标为(A.x+B.x+C.x/3,A.y+B.y+C.y/3,A.z+B.z+C.z/3)
三角形内任意一点的重心坐标计算结论如下
结论
【补充】
- α+β+γ = 1,是重心坐标的性质,同时是重心坐标在ABC平面上的要求
- 三维中的属性在三维中做插值,否则投影到屏幕再做可能会因为重心不一致而错误;
Texture queries
a pixel on a texture is a texel(纹素)
texture mapping简单应用:通过查uv来将纹理的值作为Diffuse Color
纹理太小,采样后会被拉大texture magnification
最后结果不精确,得到的会是明显的像素块的非连续结果
解决方法:纹素,屏幕分辨率差别大,texture queries的时候,用屏幕像素坐标查询texture的uv,
使用双线性插值(Bilinear Interpolation) 来解决非连续的问题。
水平、竖直都进行下述插值操作,对texel的4个像素进行插值
另有Bicubic的方法,取周围16个像素
1. Point Sample problem
采样纹理的时候为什么会出现这样的走样(artifact)?
当纹理特别大,哪怕一个纹素也包括了很多高频信息,人眼跟不上变化频率,于是产生了走样。
或者,texture queries 的时候,采样一个像素的时候只使用一个采样点,采样频率不够,导致最后结果表现不够精确连续。
增加采样点虽然理论可行,但是计算量太大。
2. Range Query Problem
范围查询不像点查询一样进行采样,而是直接查询一个范围的结果,这样就避免了上述的计算量。
范围查询根据功能可以分为平均,最大,最小….很多种不同类的方式。
引入Mipmap的概念,(fast,approximate,square),分为多级,分辨率逐级减半,D = log(L)
使用mipmap比原来多用了1/3的空间存储
如何使用mipmap?
离人眼近的地方,使用低级别的,分辨率更高的,离人眼远的地方,对精度要求低,可以用分辨率更低的mipmap。
【注】实际操作中,由于mipmap本身是方块,查询方式离散,层与层之间还需再进行插值。本身xy两轴上分别做了插值让纹理适配原像素,然后又在层与层直接插值,称之为三线性插值(trilinear interpolation)
3. mipmap limitation & Anisotropic Filter
mipmap远处会出现过度模糊的问题,
问题在哪?其实还是出在三线性插值上,之前提到mipmap的approximate的特性,本身插值方法就是人为近似的,而且又只能处理方形区域的查询。
引入效果更好的方法。
Anisotropic Filter各向异性过滤(ripmap)
游戏中2x指的是左上角两层的范围,存储量收敛到原来的3倍,游戏中一般都可以开到最高,对性能不会有任何影响。
这种方法由于x,y方向都有拉伸,查询不局限于方形,扩展到矩形
但是如下图,screen上的一块像素表达的内容在texture上也许是斜着的,使用各向异性查询,就要求将整块斜块用矩形包围,最后结果overblur。irregular footprint(覆盖区) in texture的问题
竖着的长条可以解决,但是斜着的就不好解决。
EWA filtering
将查询范围用多个圆包围,多次查询
可以处理不规则图形,但是计算量很大
Application of textures
现代GPU中,texture = memory + range query(filtering)
Environment Map 环境贴图,物体反射周围的光;描述不同方向的光照信息。
Shperical Map,发生扭曲;Cube Map
Bump/Normal Map
凹凸贴图如何绘制法线制造凹凸感?
- 设原来法线为(0,0,1)
- 求偏导(derivatives),假设u,v变化单位1
切线逆时针旋转90度得到法线
得到法线(-dp/du,-dp/dv,1)
这样,通过凹凸贴图的纹理映射,制造假的法线,实现结果的凹凸。
Displacement Map,位移贴图,真正的移动了原模型,不同于凹凸贴图。
要求三角形很细,三角形的频率要比纹理高;采样率高,模型足够细致
DX上有一个方法叫动态细分,即便是模型不是很精细,但是可以根据需要进行选择性移动
其它
Provide Precompute shading
3d textures and volume rendering