前言
现实中,光照射到物体上,物体反射光进入人眼,形成颜色,组合成视觉效果,相机模拟这一过程,图形亦然。图形渲染根据3d场景生成2d图像,图像尽可能模拟自然,尽可能真实。
渲染有两种方式,射线追踪和光栅化,前者更接近自然规则,实现简单效果好,不过计算量大,广泛应用电影CG等离线渲染,后者效率高,实现自然效果比较麻烦,同时GPU硬件支持,广泛应用游戏等实时渲染。
简介
计算机图形,通过计算机模拟3d世界,并最终通过2d屏幕展示。主要包括Modeling/Rendering/Animation。
Modeling,通过数学方式建立3d几何数据。可以通过3dMax、Blender等建模软件,也可以通过数学公式表达。
Rendering,接受3d几何数据,最终显示在2d屏幕上,常见有光栅化和射线追踪。
Animation,间隔一定时间变换屏幕显示,造成动画错觉。
这里主要是介绍Rendering即渲染,模型和动画会在后续3ds Max详解。
数学
数学是一切自然科学的基石,图形学大量使用数学知识。
坐标系
为了描述位置、方向等信息,需要选择一个度量的参考点,这个就是坐标系,常见的有笛卡尔坐标系,用互相垂直的轴作为原点参考。2d的有x和y轴,3d的有xyz三个互相垂直的轴,常见的有左手坐标系和右手坐标系,dx采用左手坐标系,opengl采用右手坐标系。计算机的显示屏幕,本质上是一个横竖布局的画布,左上角为原点,向下为正,y轴依次增加,向左为正,x轴依次增加。手机屏幕1920 x 1080,横向x轴1920个像素,y轴1080个像素,最终手机渲染的图像会显示在这个像素区域。
向量和矩阵
向量用来表达几何数据,矩阵用来变换向量。向量用来表达3d空间的位置、方向、法线等等几何数据,向量常见的运算有,求长、归一、相乘、点积和叉积等等,有良好的数学和几何属性,用来表达基础几何数据。矩阵的初衷用来解决数学函数的求解,有良好的数学表达能力,被发觉用来做变量变换。矩阵常见的运算有、相乘、转置、求反等等。向量常见的三种变化移动、缩放和旋转,3d向量坐标系转换、转换成2d并最终转换成屏幕空间的2d像素等等,用矩阵都可以很好很高效的实现。
几何
使用数据来表达3d世界,可以使用网格(Mesh),也可以使用数学公式,前者是渲染和很多操作的基石,后者也用于很多地方的计算。一个圆形,既可以用mesh,很多三角形来模拟,也可以使用数学公式,(x-x0) * (x - x0) + (y - y0) * (y - y0) = r * r来表达。比如在引擎中导入模型,基础的mesh数据外面往往带有包围盒或者包围球,渲染的时候,首先判定包围盒或球是否在视锥体,如果在进行后续流程,不在的话,直接剔除,这个叫做摄像机剔除,大大提高场景渲染效率。射线相交的时候,首先判定射线是否和包围盒或者包围球相交,如果相交,进行后续步骤,大大提高相交效率。
两者都有大量运用,这里主要是讲Mesh。网格主要包括点(Vector),线(Egde)和面(Face)。面有很多拓扑单元,使用比较多的三角形,三角关系比较稳定,三角组成了最简单的面,没有歧义,适用于大量数学运算并且被GPU支持,效率非常高。
渲染
根据3d场景生成2d图像,并在屏幕上显示,图像可以是真实感的,也可以是非真实感的,前者需要模拟大自然的模拟现象。
渲染流程的话,大概如下3d场景->渲染过程->显示屏幕
1,显示屏幕,本质横向和纵向的像素画布,连续的量转换成离散的量会出现锯齿,减少锯齿的话,有三个方面,加大屏幕分辨率,抗锯齿算法和动画
2,3d场景,主要包括Model,Camera和Light,Model的话,可以使用网格来表示,也可以数学方式来表达。
3,渲染过程,渲染主要包括两个阶段,透视和着色。
人眼看自然世界,远处看起来更小,秋水共长天一色,远处的山和水竟然连在一起啦!这个是透视现象,照相机和图形渲染时候,都采用相同原理。人眼看到各种颜色主要是有光,光通过各种反射折射等等最终传播到人眼形成颜色,这个过程称为着色。
渲染过程
3.1 透视
透视将3d场景转换成2d像素。
光栅化的话,通过矩阵投影将3d转换成2d(透视除法)和深度信息(z-buffer),根据深度判定前后关系,离摄像机进的覆盖远处。射线追踪通过从摄像机射出射线,判定是否相交,距离近的覆盖远的。光栅化效率更高,目前被GPU支持。
3.2 着色
着色生成像素的颜色。着色计算所有的光照信息在材质表面的行为,并最终生成反射形成颜色。
光由大量光子构成,光子传播到材质上,会根据表面的垂直方向(法线)和入射方向形成反射,反射最终到达人眼形成颜色,材质的感觉比如镜面、塑料、金属也跟材质的各种属性决定。漫反射,材质表面比较粗糙,光朝这个各个方向反射,效果取决与光的方向和表面法线,用于模拟塑料等材质。镜面(光泽)反射,光的反射主要集中在特定方向,效果取决与光的方向、表面法线和观察方向,用于模拟镜子、金属等材质。
透明,光传播到类似于玻璃球这样的透明材质,会有反射和折射现象,反射和折射满足菲涅耳公式。用于模拟,玻璃球、水等透明的材质。
次表面反射,实现半透明效果,用于模拟皮肤等。
间接光照,光的效果不是来自光源,而是其他材质的反射。
全局光照,关照即来自光源,也来自其他材质的反射等,用于模拟更真实
射线追踪
该算法能够比较好的模拟自然现象,不过计算量大,广泛应用离线渲染。
射线追踪的路径
1,Farward Tracing(light tracing),模拟自然界光子的运动,不过,光子的运动随机,光子与表达介质的几何数据求交消耗大,现实中,光源包括大量大量的光子,实现这种机制,计算消耗大,效果随机,大量采样才能保证效果。
2,Backward Tracing(eye tracing),从摄像机射出射线(primary ray),判定当前摄像是否和模型相交,根据模型的材质,反射生成新的射线(shadow ray),这样射线和运算都可以控制下来。主要的话采用这种方式实现。
算法步骤:
1,生成射线。屏幕相当于摄像机前面的画布,从摄像机位置出发,对屏幕上每个像素生成射线,carema ray(primary ray)
2,射线几何相交。判定射线和几何体相交,着色距离最近的片段,传递给下一阶段,没有任何相交片段的话,重复步骤1.
3, 着色片段,根据介质属性和光的传播特性,生成shadow ray,最终着色,形成像素,传递下一阶段。
4,显示阶段,更新FrameBuffer,给屏幕显示。
光栅化
实时渲染的主流技术,理论形成较早,有成熟的pipeline支持,性能较好,实现各种复杂效果比较麻烦,广泛应用于游戏等领域,被GPU硬件支持。
算法步骤:
1,投影阶段,3d点转换成2d点。转换过程为局部坐标系->世界坐标系->摄像机坐标系->NDC->屏幕坐标系,输出2d点,给下阶段使用。
2,光栅阶段,2d点组成2d面,2d面填充片段,这个过程中,连续的量通过离散的量表示,会出现锯齿。插值单个片段,获得单个片段的属性。输出片段,给下阶段使用。这个过程,需要透视矫正。
3,着色阶段,着色单个片段。根据片段的材质属性比如光照、纹理等形成最终颜色,输出像素,给下阶段使用。
4,显示阶段,投影阶段会存储相应的深度值,离摄像机进的片段输出像素至FrameBuffer,最终给屏幕显示。