目录
主要内容:着色、着色频率、图形(渲染)管线、纹理贴图
>>> MVP->视口->光栅化
着色:像素的颜色都应该是什么......
着色
明暗 颜色
定义为:对不同的物体应用不同材质叫做着色。
说明:着色不考虑其他物体的存在,只考虑它自己。
Blinn-Phone 反射模型
>>>>(一个着色模型)
漫反射 高光 环境光(通过其他物体反射得到的光照)
漫反射
漫反射与观测方向完全无关。
定义:当一个光线打到一个物体上去,光线会被均匀的反射出去。
光在不同半径上的强度(能量的守恒)
到达了多少能量 >>> 接收了多少能量 ---》即反射出了多少能量
Kd:表示漫反射项的系数,若系数为1,表示完全不吸收能量,为最亮的。
若系数为0,则表示全部吸收了,没有能量反射出去,式最暗的。(表示明暗)
Kd:也可表示一种颜色。
Kd:表示颜色或明暗......
高光
- 用v和R是否相近判断高光--Phone反射模型
- 用n和h是否相近判断高光--Blinn-Phone反射模型
当观测方向和镜面反射方向足够接近时,可以看到高光。
V和R接近时---说明n和h方向接近。
h(半程向量)--在v和l方向的角平分线上。
怎么判断两个向量是否接近呢? 算点乘 接近1--相近
指数p是什么意思?p一般在100-200.(指数p控制高光大小)
在衡量n h是否相近的时候,让其变化的更加明显,只能在一段很近的距离里看到高光。
- Ks越大,表示越亮。
- p越大,表示高光范围越小。
环境光照
>>> 假设为一个常数 与法线方向、入射方向、观测方向没有任何关系。
假设:任何一个点点接收的来自环境的光照是相同的 为Ia
Ka表示了一个颜色
Blinn-Phone总结
- 环境光:不管在哪里,都是同一个颜色。
- 漫反射:和观测方向无关,和光照和法线方向有关。
- 高光:只有在很小的地方可以看见高光。
着色频率
定义:着色应用在什么上面。
>>>> 之前的Blinn-phone模型考虑了任何一个点的漫反射、高光、环境光,接下来考虑所有点的做一遍着色操作。
>>> 把着色应用在一个平面上(一个平面有一个法线,一个平面做一次着色)
>>> 对每一个平面的顶点求法线,对每个顶点做一次着色,平面内部的点通过插值求颜色(着色应用在每个顶点上)(插值颜色)
>>> 对一个平面的顶点求法线,对法线方向在平面内部进行插值,所以每个像素会有一个自己的法线方向,再对每一个像素进行一次着色(着色应用在每一个像素上)(插值法线方向)
1.flat shading
三角形两边做一个叉积,求出三角形的法线,一个三角形做一次着色。
》》》每个三角形
2.Gouraud shading
求三角形每个顶点的法线,对每个顶点做一次着色,三角形内部的颜色通过颜色插值实现。
》》》每个顶点
3.Phong shading
三角形的三个顶点求出来一个各自的法线,三角形内部的每个像素进行法线方向的插值,对每个像素进行着色。
》》》每个像素
- Blinn-Phong指的是一种着色模型
- Phong shading指的是着色频率模型
总结
结论:相同几何模型的情况下 Phone-shading着色效果会更好,但当几何足够复杂时,就可以使用相对简单的着色频率模型。
问题
问题1 每个顶点的法线是什么?
任何一个顶点和多个三角形关联。
>>> 顶点的法线是相邻几个面的法线的平均。
问题2 已知三角形顶点的法线是什么,如何得到内部各个像素的法线。
>>> 需要用到重心坐标,在下面纹理映射中提到。
渲染管线
(实时渲染管线 图形管线)
>>> 从三维场景到最后渲染成的一幅图......
过程:(从三维场景到最后渲染成的一幅图)
- 三维空间中的点投影到屏幕上(MVP 视口变换) >>> 这些点会形成三角形
- 三角形离散成像素(光栅化) -采样 -深度测试
- 着色(知道每一个像素的颜色 明暗)
每一个顶点做一个变换。
对每一个像素采样,看是否在三角形内,光栅化。
光栅化后产生的像素是否可见的问题 深度缓存
着色发生在顶点和像素上 >>> 考虑不同的着色频率
着色器
着色器是可编程的:顶点着色器 像素着色器
只需写一个顶点和像素如何着色就可以,程序中不需要写循环。
纹理映射
定义
纹理和着色的关系: 纹理映射用来定义着色的时候,不同点的不同属性。
在物体表面的不同位置定义不同的属性。
>>> 三角形三个顶点,每一个顶点都对应一个(u,v) --- 纹理映射
假设已经知道 物体上任意一个三角形的顶点都能对应在纹理的哪一个坐标上。
在纹理上定义一个坐标系(u,v){0=<u,v<=1}
提出问题:
已知三角形三个顶点对应的纹理坐标(u,v),怎么知道三角形内部对应的纹理坐标(u,v)?
插值问题,由重心坐标来解决。
重心坐标(插值)
如何在三角形内部进行任何属性的插值 >>> 引入重心坐标
应用
- 已知三角形三个顶点对应的纹理坐标,求三角形内部各点对应什么。
- 着色频率中,已知三角形三个顶点的颜色,求三角形内部的颜色。
- 着色频率中,已知三角形三个顶点对应的法线方向,求三角形内部的法线方向。
重心坐标定义
重心坐标是定义在一个三角形上的。一个三角形对应一套重心坐标。
三角形所在平面上的任何一个点(三角形外、内)都可以通过ABC的线性组合来表示。如下:
>>> 三个变量加和==1 是为了显示(x,y)在三角形所在平面上。
(x,y)在重心坐标下的表示为
如果(x,y)点在三角形内部,必须满足这三个系数都>=0
A点的重心坐标即为(1,0,0) B点(0,1,0) C点(0,0,1)
>>>> 重心坐标的另外一个定义:
重心坐标可通过面积比求出来:
>>>> 三角形的重心会将 三角形分成三个等面积的三角形,因此三角形的重心坐标对应的重心坐标为(1/3,1/3,1/3)
>>>> 重心坐标的另一种求法
重心坐标的应用
VA VB VC即在三角形三个顶点上的属性(可以是位置,纹理坐标,颜色,法线方向......)
V即可通过重心坐标和三个顶点的属性计算出来
存在问题:
重心坐标在投影变换时会发生改变。
>>>> 所以如果我们要插值三维空间中的属性,要找三维空间中点的坐标,以此求重心坐标,再进行插值,而不能在投影之后的图形上面做。
进行深度插值时的深度值,是在三维空间中插值好的深度值,然后放回到对应的二维屏幕中。
纹理渲染的实际应用
>>>> 根据已知的三角形三个顶点的对应的纹理图片的坐标值,根据重心坐标插值出三角形中任意一个点对应的纹理图片的坐标值,将此坐标对应在纹理图片上的颜色替换为漫反射中的Kd。
双线性插值
纹理渲染存在的问题:纹理图片太小(插值)
>>>> 一个像素可能会映射到一个非整数坐标的纹理元素上,对坐标四舍五入后,会造成一个纹理元素会映射到多个像素上,造成类似于图一的结果。
- Neareat是取最近的那一个纹理元素的值
- Bilinear 是取周围临近4个纹理元素进行线性插值。
- Bicubic 是取周围临近的16个纹理元素进行非线性插值。
解决方法: 双线性插值(结果为中间的这幅图)
即如何解决 一个非整数坐标的纹理元素问题。
找到此非整数坐标点距离最近的纹理图片的四个纹理元素,然后进行线性插值。
插值公式为:
- 当x==0时,为V0
- 当x==1时,为V1
- 当x==0.5时,为V0和V1的中间值。
计算过程如下:
先进行两次水平方向的插值,再进行一次竖直方向的插值。 (s t 必定都是>=0&&<=1的值)
Mipmap
>>>在一个区域内做一个范围查询--立刻知道这个范围的平均值是多少。
是一种范围查询的方法:速度快,结果不准确,只可以做正方形的范围查询
纹理渲染存在的问题:纹理图片太大(范围查询)
屏幕上的这些像素覆盖的纹理图片上的大小是各不相同的,远处的像素覆盖的纹理图片区域较大
如何解决问题:已知产生的是走样问题:信号变化过快,采样频率跟不上。
>>> 所以选择不采样,找一种方法,给定一定的纹理区域,便可给我们这块区域的平均值。
Mipmap >>>一种范围查询方法
可由一张图生成多张图...... 每张图都在上一张图的基础上分辨率缩小一半。
第0层 第1层 第2层......
Mipmap:在一个区域内做范围查询,立刻知道这个区域的平均值。
1. 那这个区域怎么找?
>>>> 如上图,找到一个像素的临近两个像素,分别计算对应到纹理图片上的点的距离,取最大的一个距离,作为此像素映射到纹理图片上的一个区域,是一个正方形。
2. 接下来,有了一个区域,如何计算此区域的平均值?
>>>> 对于L*L的区域,在这一层上,是一个像素,所以去第D层查询这一个平均值就可以。
结论:在离我们近的地方,去低层找这个平均值,在离我们远的地方,要去高层找这个平均值。
出现了问题:在选择的层与层中间,会出现一个间隙(图一)。
图二是三线性插值后的结果
类似于这个(因为层数是离散 1 2 3 不是连续的 没有1.8层)
因此如何查询1.8层呢:用插值:(三线性插值)
在第一层做一次插值,在第二层做一次插值,然后再第一层和第二层之间做一次插值。
这样层数就是连续的了,在任意一层都可以查询......
- 在纹理内部,不管是整数坐标还是非整数坐标,都可以双线性插值出来一个平滑过渡的值。
- 在层与层之间也可以插值出来一个连续的值。
>>> 因此,对任何查询的区域,都可以通过三线性插值,做一次查询,就可以得到这个区域覆盖的平均。(三线性插值 ---->>> 在层与层之间 和 层内部都是连续的)
Mipmap的结果:在远处出现了模糊
why? Mipmap只能进行正方形区域的范围查询。
各向异性过滤来解决三线性插值的问题。
各向异性过滤允许我们对矩形做快速的范围查询(不是限制在一个正方形区域内)。
引进:
EWA过滤:速度慢,可查询不规则图形。
纹理映射的其他应用
-
环境贴图
纹理:不限制在一块图形上。
纹理可以用来表述环境光。
如下:环境光照,环境贴图
环境光记录在球上,然后展开:
图像的上方和下方会扭曲
如何解决:
环境光记录在球的包围立方体的面中。
结果:
-
凹凸贴图(法线贴图)
过程: 凹凸贴图 >>> 改变相对高度 >>> 改变法线
>>>> 定义一个复杂的纹理,但并不去改变任何的几何信息,所以三角形个数不变。
纹理定义的是任何一个点相对的高度移动,可以通过这个高度的变化来改变法线。
是为了改变任何一个点的法线。
过程图示:
本来是一个光滑的平面(黑色图线),通过凹凸贴图得到相对高度,法线方向从p变到n。
二维:
>>>> 我们先假设原法线向量是垂直向上的,法线和u,v可以构成一个坐标系,取点(0,0,1),利用差分方法求出u和v方向上的切线,然后对切线逆时针旋转90度再标准化,就可以求出对应的法线。
三维:
-
位移贴图
>>>> 通过纹理,定义任何一个点应该有的相对高度的差别,所以凹凸贴图和唯一贴图用的一样的纹理。
>>>> 移动了三角形顶点的位置,改变了几何,效果较好。
>>> 位移贴图也有缺陷,它需要三角形足够细,因为它改变的是三角形顶点的位置,如果三角形不是足够细的的话,那么三角形内部需要发生变化就跟不上了,也就是三角形的变化频率跟得上纹理的变化频率。
>>> 为了可以达到最逼真的效果,我们可以尝试先用大三角形粗糙的进行位移贴图,在贴图的过程检测三角形是否需要变得更小更细,如果需要再把三角形拆成更多更小的三角形,这就是动态曲面细分,这个功能在Direct X中的得到了使用。
-
三维纹理
定义了空间中任何一个点的值。
通过定义三维空间中的噪声函数,我们可以算出每个点的值,将这个噪声函数进行一系列处理就可以得到我们想要的纹理,著名的噪声函数有Perlin noise。
-
记录之前已经算好的信息
>>>> 通过环境光遮蔽计算阴影信息(如眉毛下面的一部分阴影),然后,将此阴影信息存放在纹理中,用的时候直接贴图。
-
体渲染
>>> 原本的光照模型只是考虑一个表面,而事实上在医学核磁共振中,经常返回的是三维空间上任何一个点的信息例如密度,这些信息可以拿过来进行渲染得到一个结果,这些信息及存储在空间中,又可以当做一个纹理进行存储。