Notifications
Article
关于Unity Shader的学习笔记(五)
Published 11 days ago
297
0
Aim:补充一下UnityShader的三种Shader类型介绍以及梳理一下UnityShader中需要的数学知识
承接着上一篇笔记补充一下UnityShader的三种Shader类型以及UnityShader中所需要的数学知识,为了进一步深入对UnityShader的学习,学习这些理论知识必不可少但同时也不能急于求成,我尽量总结的言简意赅方便理解和学习。再继续进行下面的学习之前有必要回顾下前几篇的笔记,不需要着重记忆只需要在脑海中过一遍有个印象就行,学习既快好省的方法就是将所学知识形成一个系统,当然自己已经有基础的就可以Pass了。
记得第一篇笔记里说到Unity的着色器有固定函数、顶点/片元、表面着色器三种。
表面着色器可以理解为Unity自己创造的一种Shader类型。目的是为了使用者操作更加的方便, 这也的确,相较于原本的Shader要写的代码要少很多。实际上当Unity要编译一个表面着色器时背后还是要转换成对应的顶点/片元着色器。一个简单的表面着色器代码如下:
表面着色器被定义在SubShader中的CGPROGRAM和ENDCG之间,这其中的代码是使用CG/HLSL写的,这与实际上的CG/HLSL代码几乎是一样的。当然你也可以用GLSL来写,跟CG/HLSL类似,GLSL的代码要嵌套在GLSLPROGRAM和ENDGLSL中,这就限制了能发布的平台,只能放在MacOSX,OpenGLES2.0等,放在DirectX平台上就不适用了。
顶点/片元着色器相比表面着色器要复杂一些,但灵活性也是更高。顶点/片元着色器代码也是写在CGPROGRAM和ENDCG之间,但是是在Pass块中而不是在SubShader块,这个需要我们自己去写代码定义每个Pass块的功能,这样我们可以控制实际渲染的细节,代码也是用CG/HLSL编写的,一个简单的顶点/片元着色器代码如下:
固定函数着色器一般是用在比较陈旧的设备上,这些设备不支持可编程管线着色器,固定函数着色器只能实现一些基本简单的功能,对于固定函数着色器的编写需要完全使用ShaderLab的语法而不是CG/HLSL。现在大多数GPU都支持可编程渲染,所以固定管线也就慢慢的被淘汰了。下面是一个简单的固定函数代码:
对于在写Shader时要选择哪一种形式,根据实际情况来看吧。如果项目里用到各种光源效果的话建议使用表面着色器,同时要考虑在发布平台上的性能问题。如果光的数量及种类比较少或者只有一个平行光,亦或者需要自定义渲染效果的话,建议使用顶点/片元着色器。
UnityShader中涉及到的数学知识,这一部分打算分两篇笔记来总结,有基础的可以Pass了。
1、笛卡尔坐标系 笛卡尔坐标系想必应该都不陌生,初中数学基础。笛卡尔坐标系有二维和三维。二维笛卡尔坐标系包含一个原点,以及过原点并相互垂直的两条向量,也就是X轴和Y轴。这是我们一般意义上的二维笛卡尔坐标系,而OpenGL和DirectX使用了不同的二维笛卡尔坐标系。具体如下图:
而三维笛卡尔坐标系是定义了三个坐标轴和原点,三个向量相交于原点并相互垂直,坐标轴也称为该坐标系的基矢量,当各个向量长度为1时称为标准正交基,当向量长度不为1的时候称为正交基。三维笛卡尔坐标系也有两种情况:左手坐标系和右手坐标系,如下图
可以看出左手坐标系和右手坐标系不但Z轴指向的方向不同,同时对正向旋转的定义也是不同的,这就是在初高中物理里学的左手法则和右手法则,这里不再用文字赘述,具体可以网上搜视频看更加直观理解。在Unity中,场景里面的世界坐标是以左手坐标系为主,但摄像机观察视锥空间是以右手坐标系为主,Z轴刚好与世界坐标系相反。具体可以自己打开Unity仔细观察一下。
2、点、向量和标量
点是多维空间中的一个位置,没有大小这个概念,一般用2到3个实数来表示,如P(Px,Py),表示二维空间中的点,P(Px,Py,Pz)表示三维空间中的点。向量也称矢量,用来描述偏移量,是指有大小和方向的有向线段,矢量的大小也称模,最简单的例子如速度即为典型的矢量。而标量是只有大小没有方向。矢量的表示方法和点有点类似,可以使用p=(x,y)表示二维矢量,p=(x,y,z)表示三维矢量,p=(x,y,z,w)表示四维矢量。
矢量的模,也就是矢量的大小,矢量的长度,假定有一个矢量P=(Px,Py,Pz),该矢量模的计算公式如下:
|P|=根号下(x^2+y^2+z^2)。其中x^2表示x的平方。模为1的矢量为单位矢量,零矢量是矢量的每个分量都是0,如P=(0,0,0);
矢量和标量的乘法和除法,公式很简单,假定有个矢量P=(Px,Py,Pz),标量K,则有:
KP=(KPx,KPy,KPz);
P/K=(Px/k,Py/K,Pz/K),K≠0;
我们不能把矢量和标量相加或者相减,就好像我们不能把速度和距离相加一样。
矢量间的乘法有两种,点积和叉积。例如在Unity Shader中,我们可以直接使用Dot(a,b)的代码来对两个矢量的值进行计算,点积的公式有两种:
其一:a·b=(ax,ay,az)·(bx,by,bz)=axbx+ayby+azbz
其二:a·b=|a||b|cosθ
点积的几何意义很重要,几乎应用到了图形学的各个方面,比如计算投影。投影的值可以是负数,投影结果的正负号与两计算矢量的方向有关。当它们方向相反(夹角大于90度),结果小于0,方向相互垂直时,结果等于0,方向相同时(夹角小于90度)结果大于0。如下图:
点积的计算结果是一个标量,所以它可以结合标量乘法或者矢量加法和减法,一个矢量和本身进行点积的结果是该矢量模的平方。
叉积,又称为外积,与点积不同的是计算后的结果是矢量而不是标量。叉积不满足交换律,两个矢量进行叉积结果会得到一个同时垂直于这两个矢量的新矢量。叉积通常用来计算垂直于一个平面或三角形的矢量,也可以判断三角形面片的朝向,我们一般说的法线垂直于平面以及法线翻转和叉积就有很大关系。叉积也有两个计算公式:
其一:aXb=(ax,ay,az)X(bx,by,bz)=(aybz-azby,azbx-axbz,axby-aybx);
其二:|aXb|=|a||b|sinθ;
矢量间的相加和相减,其结果是生成一个新的矢量。不同维度间的矢量不能参与运算。
假定有矢量a=(ax,ay,az)和矢量b=(bx,by,bz),则:
a+b=(ax+bx,ay+by,az+bz);
a-b=(ax-bx,ay-by,az-bz);
一般矢量间的加法和减法用来计算一点相对于另外一点的位移,比如空间中有点a和点b,我们可以用矢量矢量A和矢量B来表示它们相对于原点的位移(连接原点到点a的矢量为矢量A,连接原点到点b 的矢量为矢量B),如果想要计算点b相对于点a的位移,我们可以通过B减A得到。
未完待续..........
月三更
Programmer
5
Comments