四种空间:
1.模型空间:每一个物体都有一个以它自己的中心点为原点的三维坐标空间。
a.在unity中,可以通过transform.worldToLocalMatrix这个矩阵的MultiplyPoint()或者MultiplyVector()方法,把世界坐标表达的矢量转换为此物体的模型空间表达的矢量。
b.在shader中,可以通过左乘_World2Object这个矩阵来完成。
2.世界空间:模型空间在处理物体自身的一些相对关系时比较有用,而如果要表达多个模型间的关系,就需要一个统一的空间坐标,这就是世界坐标空间。
a.在unity中,可以通过transform.localToWorldMatrix这个矩阵的MultiplyPoint()或者MultiplyVector()方法,把模型空间矢量转换为世界空间矢量。
b.在shader中,可以通过左乘_Object2World这个矩阵来完成。
3.视空间:又称相机空间,是为了方便表达以相机为世界中心时所有物体的相互关系的一个空间。
a.在unity中,可以通过相机Camera组件的worldToCameraMatrix来把一个世界坐标的向量重新表示为一个以相机为中心的空间的表达形式。如果我们想把一个相机空间的向量重新表示到世界坐标,可以使用cameraToWorldMatrix来实现。
b.在shader中,有一个矩阵UNITY_MATRIX_MV可以把向量一次性从模型空间转换到视空间。
c.视锥体:unity只渲染出现在镜头中的物体,要判定物体是否在镜头中,就需要引入视锥体的概念:
只有处于视锥体内的物体才会被渲染。相机就处于这个锥体的顶尖上,这个过程的专业术语叫Culling。
4.剪切空间:
a.投影
之后我们需要准备把三维的物体表示到一个二维的平面上,这个过程首先需要投影一次,把视锥体转换为一个长方体,这次变换是顶点shader任务的终点。之后的引擎会自动处理下面的事情,把坐标转换到NDC(Normalized Device Coordinates),OpenGl和Direct3D稍有不同,OpenGL的值域是(-1,-1,-1)到(1,1,1);Direct3D的值域是(-1,0,-1)到(1,1,1)。(顶点对角)
b.在unity中,表示这个投影操作的是Camera组件的projectionMatrix。
c.在shader中,则是UNITY_MATRIX_MVP。
d.我们完全可以把上面这一系列的步骤一次完成,也就是把上面提到的几个矩阵组合到一起,从而得到UNITY_MATRIX_MVP这个矩阵。通过这个矩阵,可以直接把物体上的一个点投射到屏幕上,这也是正常显示一个物体的shader所必需完成的工作。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
我们可以把照射到物体上的光源简单地分为间接照明和直接照明:
1.间接照明:指光在物体间传播后,最终又对物体形成照明。间接照明一般要涉及到光线追踪,而光线追踪耗时很大,不可能让玩家等上半个小时让渲染器把场景渲染好了再做下一个动作,因此对此部分的照明进行实时计算在目前是不可能实现的。在实际运用中,这种照明一般是通过预先烘焙得到的。对于实时计算,间接照明一般作为一个常量。
2.直接照明:分为漫反射和镜面反射,其中镜面反射会形成强烈的高光。直接照明是实时渲染的计算重点。
a.漫反射(Lambert光照模型)
对于粗糙物体表面的某一点,其亮度应该和入射光线与该点的垂直程度有关,也就是入射光线与该点法线的夹角有关。如果我们用L表示单位长度的入射光线,C表示到达该点的光线的强度和颜色,N表示此点的法线,那么物体表面此点的亮度Lum就可以表示为:
b.镜面高光(Phong光照模型和BlinnPhong光照模型)
Phong:计算某一光线ray在某一法线为normal的点经反射后的光线,可以通过Cg标准函数库中的reflect(ray,normal)来完成。如果用R表示光线在此点的单位长反射方向向量(通过reflect函数可以求出),V表示视线的单位方向向量,那么高光部分Spec的计算方式表示为:
BlinnPhong:其计算方法就是使用入射光线和视线的中间平均值,即半角向量,然后使用此半角向量和法线计算出一个和视角相关的高光。