着色频率
从边界可以看出三个球,拥有完全相同的几何形状。但是着色之后结果各不相同
着色频率:着色要应用在哪些点上。
第一个球,把着色应用在一个面上。一个平面只做一次shading。
第二个球,每一个平面有4个顶点,每个顶点都算出对应的法线,进行shading。每3个顶点,可以围成一个三角形,三角形内部的颜色通过插值的方法计算
第三个球,着色应用在每一个像素上。求出每一个三角形的法线,将法线进行插值计算出每一个像素自己的法线,在做一遍着色
Shade each triangle/flat shading
每一个三角形作为一个平面,将三角形的两条边做一个叉积,求出法线。根据light方向算出shading结果
Shade each vertex/Gouraud shading
求出每一个顶点的法线,每个顶点进行一次着色,三角形内部的颜色通过插值计算
Shade each pixel/Phong shading
三角形三个顶点各求出法线,三角形内部每一个像素根据插值求出自己的法线方向,进行着色
当几何足够复杂的情况下,可以用相对简单的着色频率。
当面的频率已经很更高的情况下,不需要用很高的着色频率
但当三角形面的数量超过了像素数,做flat shading的计算量反而更高
要取决于具体的物体
定义每个顶点的法线![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/2c441a4bcf34b638346f3b76cd68a6c5.png#pic_center)
任何一个顶点会和很多个三角形有所关联,则顶点的法线认为是相邻的所有面的法线求平均,根据各个三角形的面积进行加权平均
定义每个像素的法线
使用重心坐标求插值,注意法线是方向,最终结果要归一化
渲染管线/Graphics (Real-time Rendering) Pipeline
管线:如何从场景到最后一张图
- 输入一系列空间中的点
- 三维空间中的点变换投影到屏幕上
- 这些点形成三角形
- 通过光栅化离散成不同的fragments(类比于像素)
- 对像素进行着色,例如如果用了MSAA,就是好多个不同的fragment合成一个像素的着色
- 输出到屏幕
第一个大步骤是顶点的处理,各种变换。第二个大步骤是光栅化,涉及到如何采样,如何做深度测试,找到最终能显示在屏幕上的像素。第三个大步骤就是着色
顶点变换
采样光栅化
zBuffer深度缓存
shading发生在vertex和fragment都有可能,如果phong shading则是在Vertex,如果是flat shading则是在Fragment。
所以要注意顶点如何着色,或者像素如何着色。
现代GPU里允许管线的一些部分是可编程的,可以自己定义顶点或像素如何着色(即Shader)
纹理映射
Shader
shader本质上是一些能在硬件上执行的语言
shader是每一个顶点或者每一个像素会执行一次
shader是每一个像素通用的,不用特殊指定哪个像素,所有像素都会执行,因此shader里不需要for循环,只需要处理一个顶点或者一个像素如何运行
如果写的是对顶点的操作,则是顶点着色器/vertex shader
如果写的是对像素的操作,则是像素(片段)着色器/pixel(fragment) shader
上图的例子,像素着色器,要做的是写清楚对一个像素来说怎样算出它的颜色,并且输出出去
在网页上直接执行shader的一个程序
纹理映射/Texture Mapping
一个物体每个点公用同一个着色模型,但是希望定义物体上每个点各自的属性,如每个点有自己的光照系数。因此映入纹理映射
任何一个3维物体的表面都是2维的
因此一个物体的表面可以和一张图有一一对应的关系,即纹理映射
物体表面上任一三角形的顶点,都能在纹理图片上找到对应的三角形的顶点
纹理上定义的坐标系:(u,v),u,v的范围默认在[0,1]之间
一个纹理可以多次应用,不同的位置可以映射到相同的纹理位置上
tiled纹理:纹理的四周是无缝衔接的