GAMES101 学习8——着色(着色频率、图形管线、纹理映射)
一、Shading Frequencies着色频率(指着色应用在哪些点上)
引起着色的不同主要就是因为着色频率不同所导致的,如下图:
从左到右依次应用为 面 → 顶点 →像素
这里主要分成对三角形进行着色,对顶点进行着色,对像素进行着色三种着色方案进行讨论
1.1 Flat shading(应用在表面,对三角形进行着色)
对每个三角形着色也称为Flat shading
,它是指每项属性例如纹理,法向,颜色,都是属于一个三角形的,所以三角形内部不会有插值变化。所以,三角形内部只会根据面法向量对光线反射进行计算,所有的三角形反射都看做一个平面,给人以一种块状的效果(三角形较少时),如下图:
简言之:两边做叉积→三角形的法线
1.2 Gouraud shading(逐顶点)
对顶点进行着色也称为gouraud shading
,它发生在顶点着色器阶段
。对于每个多边形的顶点都存在一个法向量,但是他的着色是先通过这些法向量对顶点计算出光照颜色,然后用光照颜色来进行三角形内部插值,如下图:
简言之:算出顶点法线,然后插值
定义逐顶点法线求法
认为顶点的法线为相邻面的法线的平均(更优办法是根据面积加权平均)
1.3 Phong shading(逐像素)
对每个像素着色也称phong shading
,它发生在片段着色器阶段
。它是通过对多边形每个顶点的法向量进行插值,然后我们通过插值得到的法向量(每个像素都有自己的法向量),再去计算光照颜色,如下图:
注意:Phong shading
是一种着色频率,和布林冯着色模型
不是一个概念。
使用不同的着色方案会得到不同的结果,但是也不能说某种方案就一定差于另一种方案,当顶点数足够多时,对三角形进行着色不一定会比对像素进行着色效果差,对应的内存开销也不一定比对像素进行着色小。
通过求重心坐标获取逐像素发现(后边讲)
说明:
由于片段着色器阶段计算的坐标都是处于世界坐标系中,所以在计算光照时,所用的法向量也要转换到世界坐标系下。还记得之前我们把坐标转换到世界坐标是乘以model矩阵,但是法向量是不可以直接乘以model矩阵的,因为它仅仅是一个向量,而且也不是齐次坐标表示,所以这里需要一个法线矩阵(它是model矩阵逆的转置)来进行转换,使法向量也处于世界坐标下,详细推导可以看这里:链接: http://www.lighthouse3d.com/tutorials/glsl-12-tutorial/the-normal-matrix
二、渲染管线 Graphics (Real-time Rendering)Pipeline
2.1 渲染管线流程
通过图形渲染管线都是流水线形式,上一阶段的输出作为下一阶段的输入,该课程的一个图形渲染管线(也是前向渲染管线)流程如下:
总体来说:顶点 →光栅化 →着色
用mvp举例:
MVP(Model, View, Projection transforms)→采样 →z-buffer test →shading →Texture mapping
具体来说:
-
首先我们有一系列三维点坐标,可能是从某些文件读入。然后我们把它们输入给Vertex Processing阶段(顶点着色器),该阶段主要进行的操作是
model
,view
,projection
变换,将三维坐标变换到二维裁剪空间(通过投影丢掉了不可见的区域),也可以进行gouraud shading
等操作。
-
随后把顶点着色器的输出,作为输入给
Triangle Processing
阶段,这里主要是进行一些图元的绘制,包括把点连接成三角形,或者制作一些顶点的副本等 -
下一个阶段是
Rasterization
阶段(光栅化),该阶段将三维图元作为输入,通过采样将其绘制在二维屏幕上,并以片段
的形式作为输出。
片段、像素 关系说明:
片段(Fragment)
:三维顶点光栅化后的数据集合,还没有经过深度测试像素
:片段经过深度测试、模板测试、alpha混合之后的结果- 片段的个数远远多于像素,因为有的片段会在测试和混合阶段被丢弃,无法被渲染成像素
Fragment Processing
把片段作为输入。该阶段主要进行深度测试
,计算光照
以及纹理映射
等,所以该阶段输出的结果基本上已经确定了像素最终的颜色。
2.2 管线渲染编程
通常可以在Vertex Processing
阶段(顶点着色器) 和 Fragment Processing
阶段(片段着色器) 进行编程,这些编程的小程序被称为Shader Programs,里面常用的语言有glsl等。
shader编写学习资料: https://www.shadertoy.com/.
2.2.1 Shader programs概念说明
- 能在硬件上执行的语言
- 每个顶点/像素执行一次(通用的,不用for循环)
- 顶点的操作→顶点着色器vertex shader
- 像素的操作→像素/片元着色器fragment shader
一个GLSL中的例子:下面的示例程序简单描述了一个着色器的工作,uniform
表示从cpu传来的变量,varying
表示从上一个阶段传来的变量,void diffuseShader()
为着色函数, texture2d
是内置函数,它表示将纹理myTexture 对应到uv向量,gl_FragColor
可以看做是内置参数,它是屏幕上用来显示的最终颜色。
uniform sampler2D myTexture; // program parameter
uniform vec3 lightDir; // program parameter
varying vec2 uv; // per fragment value (interp. by rasterizer)
varying vec3 norm; // per fragment value (interp. by rasterizer)
void diffuseShader()
{
vec3 kd;
kd = texture2d(myTexture, uv); // material color from texture
kd *= clamp(dot(–lightDir, norm), 0.0, 1.0); // Lambertian shading model
gl_FragColor = vec4(kd, 1.0); // output fragment color
}
2.2.2 Snail Shader Program 在线Shader编写网站
https://www.shadertoy.com/view/ld3Gz2
3.GPU
①gpu:-独显;-核显
②gpu可以理解成高度并行化的处理器
(核心数量理解为并行线程的数量)
gpu并行度惊人,远超过cpu
三、Texture Mapping纹理映射
纹理映射
就是将纹理空间中的纹理像素映射到屏幕空间中的像素的过程。通俗来说可以认为是一张二维纹理把一个三维物体“包裹”了起来,因此三维物体获得了一些表面纹理:
纹理坐标系
纹理也是有坐标的,它的坐标空间是由uv构成(通常[0,1]),里面对应的元素是纹素
,是计算机图形纹理空间中的基本单元,如下图:
纹素
和像素
不一样,因为它们是处于不同坐标下的,纹素处于纹理空间,而像素处于屏幕空间。在对三维表面铺设纹理的时候,通过纹理映射技术将纹素映射到恰当的输出图像像素上,这种映射不是简单的一一对应,因为会受到视角的影响,如果以一种斜的姿势观察物体,一个像素对应的纹理区域很可能是比较扭曲的,可以看下图:
纹理和着色的区别与联系
纹理用来定义着色的时候需要的不同点的属性(不希望每一个点相同着色,用纹理来改变)
- 点赞
- 收藏
- 关注作者
评论(0)