计算机图形学-深度缓存着色shadding着色模型着色频率渲染管线
Posted 点燃火柴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机图形学-深度缓存着色shadding着色模型着色频率渲染管线相关的知识,希望对你有一定的参考价值。
shadding-着色
1 深度缓存
三维空间中物体有远有近,通常近处的物体会遮挡住远处的物体,在计算机渲染中这个问题如何处理,解决方法叫作深度缓存(深度缓冲)或者Z-buffer
1.1 从画家算法到深度缓存
像油画作画一样,先将远处的物体画在画布上,然后再画中间的,最后才画最近的物体,绘画完成后,会呈现出正确的遮挡关系,以计算机绘制立方体为例说明一下,绘制时,先绘制背后的面,接着绘制上下左右四个面,最后绘制前面的面,最终立方体呈现在屏幕中,遮挡关系符合预期,这个绘制的算法就叫作画家算法
画家算法虽然可以正确处理物体的遮挡关系,但是需要绘制之前先得到物体的远近关系,需要耗费一定的性能,这个问题是可以解决的,但是有一种特殊的情况画家算法无法正确处理
如上图,三个三角形互相遮挡,此时画家算法无法准确分辨谁在前面谁在后面,无法使用画家算法在计算机中绘制出正确的遮挡关系,这时人们就发明的新的办法-深度缓存,既然以三角形(物体)为整体无法准确判断物体的遮挡关系,那可以更细一步,以屏幕中的像素为单位来判断物体的遮挡关系。
1.2 深度缓存
深度缓存与画家算法的处理过程不同,深度缓存主要是以像素为单位,时刻维护着这个像素上的最小深度,也就是时刻记录着这个像素上最近的物体,最后绘制时按照最近物体的颜色绘制即可,
以绘制两个遮挡关系的三角形为例说明一下:
初始化时,我们认为每个像素的深度都是无限远(下图中用R表示),计算第一个红色三角形式,每个像素的深度都是5,那么三角形所在的每个像素的深度值记作5(5小于无限远),第二次计算蓝色三角形,蓝色三角形的深度有的大于红色三角形有的小于,用每个像素中已有的深度与蓝色三角形的深度做比较,如果深度小于已记录的深度则替换为新的深度值,否则不变,处理过程如下图所示
1.2.1 深度缓存深度缓存的实现方法
1.创建一个二维数组zBuffer[width][height],用来存放每个像素的深度,每个元素初始为一个比场景中最远物体的还大的z值
2.遍历每个物体覆盖的每个像素,将映射到该像素上每个物体的z值跟zBuffer对应深度作比较,小于zBuffer对应的深度则将该值更新为新的zBuffer深度
请参数如下伪代码
1.2.2 深度缓存注意事项
1.z-buffer冲突
发生深度冲突是通常使用多边形偏移来解决冲突,以webgl为例,添加如下代码
//启用多边形偏移
gl.enable(gl.POLYGON_OFFSET_FILL)
//绘制之前,指定计算偏移量的参数
gl.polygonOffset(1.0, 1.0)
如果使用的是three.js,可以给相机设置合适 near和far值或者设置渲染属性logarithmicDepthBuffer为true
var renderer = new THREE.WebGLRenderer( logarithmicDepthBuffer: true );
其他的可以让建模人员稍微调整模型深度冲突部分的位置
2.MSAA抗锯齿时深度缓存
采用MSAA抗锯齿时,深度缓存是针对每个采样点,不在是针对像素进行深度比对,默认是每个像素保存一个深度如果做MSAA抗锯齿时时2*2的盒子,那么每个像素需要保存4个深度值
2 着色shadding
定义:对不同物体应用不同材质的过程
如上图物体表面受光照影响分为环境光、漫反射和高光反射三部分,如果通过一种方式可以分析并表示一个光源的这三部分影响,那我们就可以通过计算得到如上图杯子的材质
我们把物体表面任意一点当做一个着色点,物体表面不一定是平整的但是可以认为它代表的是一个极小的平面,那么它的表面是平整的,如上图,n表示法线,垂直于物体表面,v表示观测方向,通常指相机,i表示光源方向
2.1 着色模型
2.1.1 漫反射
一条光线打到物体表面某个点,会被均匀地反射到四面八方,这种现象叫作漫反射
同一个物体被同一个光源照射,但物体表面的亮度不尽相同,主要有两个原因:
1.光源与表面法线夹角
如上图,假设一个光源有6根光线照射到物体表面,该表面大小为单位面积。当光线与物体表面垂直时,6根光线被物体表面全部接收,当物体表面与光线呈45度时,物体表面只能接收到一半的光线,由此推出结论,物体接收光源能量的大小与光源与物体表面法线有关,成正比 cosθ = l · n
2.光源与着色点的距离(衰减)
如上图,假设光源位于中心,发射出的能量是I,随着时间的推移在三维空间中向周围均匀的辐射开来,图中的圆圈表示三维中的球壳,你会发现半径越大线越细,线的粗细表示能量的大小,从球心开始,半径越大球的表面面积越大,分到单位面积上的能量就越小
依据能量守恒定律,某一时刻球壳上的能量与上一时刻球壳上的能量是相等的,因此某一点的能量与球的半径的平方成反比
漫反射模型
依据上述理论,人们总结得到了漫反射的计算模型 Ld = kd(I/r2)max(0,n·l),它是经验模型
表示光线与物体表面法线夹角的影响,之所以使用max将点乘结果为负的结果排除,因为点乘结果为负数时,表示光源在物体表面的下方,计算光照没有意义
表示光源衰减
表示漫射射系数或漫反射光颜色
2.1.2 高光项
如上图,假设物体表面非常光滑,那么光线照射的到物体表面会反射出去,上图中R表示反射光线,这时从v方向望去,在R附近一定的范围内(黄色部分),会有大量的光线射入眼睛,这时会观察到物体表面的高光,这个模型被称为Phong模型
后来人们发现判断视线v与反射光线R是否接近,可以用视线v和光源i的半程向量与表面法线n是否接近来替代,这就是大名鼎鼎的Blinn-Phong模型,它也是经验模型
如上图所示,求半程向量h非常简单,只需要将v与i相加,与之前的漫反射计算不同的是计算高光反射时进行p次幂计算呢,现实中物体表面高光通常会比较小,这个p次幂是为了加速高光衰减,使其在较小的角度内就衰减完
上图中的第一幅图,如果仅仅用余弦夹角来判断两个向量是否接近,可以观测出即使是45度角时也会有一个较大的值,也就是说45度时也能观察的一定的高光,就会看到一个非常大的高光,现实世界中的高光一般是一个很小非常亮的一个点,也就是能看到高光的夹角非常小,于是给它进行次幂运算,发现64次幂时,大约20度左右就可以衰减到0。
在Blinn-Phong模型中指数p通常会取100到200之间的数字
计算高光参数与渲染结果的关系如下图所示
Ks表示镜面反射系数,图中从上到下,随着系数的增大,高光不断变量,也就是说镜面反射系数控制高光的亮度
从左到右指数p不断增长,看到高光的范围越来越小,也就是上文提到的通过指数来加速高光的衰减速度,使高光看起来更符合现实物体的高光
2.1.3 环境光
模拟真实的环境光照是一项非常复杂工作,上图中描述环境光的计算方式也是一个经验模型,这个模型基于一个大胆的假设,就是场景中任意一个点接收到的环境光都是相同的,表示环境光照强度,表示环境光的系数或颜色
2.1.4 Blinn-Phong模型使用
如上图,一个物体将它的环境光、漫反射、高光依据模型计算后累加,可以获得非常不错的渲染效果,使用这种方式计算材质的模型叫作Blinn-Phong 反射模型
2.2 着色频率
依据不同着色频率,着色方式分为面着色、顶点着色和片元着色
2.2.1 面着色(Flat Shading)
以物体的表面为单位进行着色计算,由于每个面只有一个法线,所以同一个面有相同的光照效果,一个面的法线比较好获取取任意两个边做个叉乘得到的结果就是法线
2.2.2 顶点着色(Gouraud Shading)
每个顶点都计算一次着色,每个顶点有自己的法线,三角形内部通过插值的方法获得对应位置的法线
如何计算顶点法线
我们已经知道三角面的法线可以通过三角面上任意两边叉乘得到,如下图已知围绕顶点V的四个面的法线,要想获得顶点v的法线的思路是将共用该顶点四个面法向求和取平均值即 Nv = (N1+N2+N3+N4)/4
但是这种实用与周边三角形面积差异不大的情况,如果其中一个三角形面积特别大还有一个面积特别小,简单的求平均值算出来的法线无法准确描述这个顶点的法线,这时就需要通过加权平均来获得更真实的结果,这里加权平均的权就是对应三角形的面积
我们知道两个向量叉乘得到这两个向量组成的平面的法线,同时该法线的长度等于原向量合成的平行四边形的面积。
三角形的面积是平行四边形的一半,即所求三角形的法线的长度的一半为该三角形的面积
以下为通过加权平均求顶点法线的伪代码,仅作参考
//假设上图中从顶点v触发四条边的法线分别为N12、N24、N34、N13
//计算相关三角形法线
vec3 N1 = cross(N12,N13);
vec3 N2 = cross(N12,N24);
vec3 N3 = cross(N13,N34);
vec3 N4 = cross(N24,N34);
//用法线计算三角形面积
float s1 = length(N1)/2.0;
float s1 = length(N1)/2.0;
float s1 = length(N1)/2.0;
float s1 = length(N1)/2.0;
//以面积为权进行加权平均求顶点法线
vec3 Nv = normalize((N1*s1 + N2 * s2 + N3 * s3 + N4 * s4) / 4.0);
2.2.3 片元(像素)着色(Phong Shading)
片元着色就是针对每个像素进行一次着色计算,会发现计算的高光更加圆润真实。但计算量也会更大。
每一个像素的法线同样通过插值计算得到,假设已经知道了两个顶点的法线,那么每个像素的法线插值过程如下图所示,因为法线表示的是一个方向,所以计算后要记得归一化(调用normalize函数)
法线做插值计算的时候需要用到重心坐标
2.2.4 不同着色频率与着色点数量关系
通过上图可以观察到,面着色(Flat Shadding)的渲染结果不一定是最差的,如第一列所示,随着几何体面数的增加,增加到一定数量,也可以渲染出很好的效果,从左到右依次为面着色、顶点着色、片元着色,当着色数量较小时,着色效果依次增强,同时计算量也不断加大,随着着色数量的增加越到最后差异越来越小,所以说,选择什么着色频率(方式),应综合考虑几何体的顶点数、想要达到的效果以及计算性能来决定
2.3 图形管线
把场景中的物体经过一系列的处理,最后一张图像的形式在屏幕上显示出来,这一系列过程就是渲染管线
渲染光线从上到下依次完成以下步骤:
1.获取到场景中三维空间中的一些顶点
2.经过投影变换,将这些点转换到屏幕坐标系下
3.将这些点拼装成不同的三角形
4.通过光栅化,将三角形离散成不同的着色点(片元)
5.着色计算,给不同片元进行光照计算等处理
6.输出到屏幕上
这里特别说下一下,物体在着色时会同时发生在顶点处理阶段和片元处理阶段,这个是因为根据着色频率不同,着色会发生在不同的阶段,比如你使用的是顶点着色(Gouraud Shading)它对每个顶点进行着色处理那就发生在顶点处理阶段(Vertex Processing),如果使用的片元着色(Phong Shading),它对每个片元(像素)进行着色,那么就发生在片元处理阶段(Fragment Processing)
以上是关于计算机图形学-深度缓存着色shadding着色模型着色频率渲染管线的主要内容,如果未能解决你的问题,请参考以下文章
计算机图形学-深度缓存着色shadding着色模型着色频率渲染管线