Unity3D逐顶点漫反射代码
2016-09-27 10:15
190 查看
之前的撸者小游戏泡汤了,哎,谁让咱只是一个小程序呢,水平太垃圾,自制力也太差,这不我又得学习Shader,当然了,shader的学习我早已经开始了,看的各种书籍也很多了,好了,废话不多说,直接接入代码阶段,今天我们撸出一段漫反射的一段shader代码。开撸:
首先我们要先撸一个逐定点的漫反射,在此之前我们要知道计算漫反射光照的一段公式,如下所示:
C(diffuse)=(C(light)*M(diffuse))max(0,N*I)
下面对上述的公式就行一番讲解,首先C(diffuse)表示的是漫反射光照,就是我们将要计算的那部分;C(light)表示的是入射光线的颜色和强度;M(diffuse)表示的是材质的漫反射系数;N和I则表示的是表面法线和光源方向,另外需要说明的所有的值都为单位矢量。
好了,现在开始上代码,Unity3D创建项目各种步骤省略,现在我们先创建一个shader,命名随意,我们命名为FirstDiffuseShader.打开文件,开始具体写代码:
好的代码码完,开始讲解,先看一张效果图,当然我们还要创建材质这些步骤省略:见下图,哎呀,没有效果图,传上来太费经,我们开始讲解代码,首先我们定义了一系列shader的名称(第一行),然后我们定义了shader的属性:Properties,该属性显示的是我们Inspector上面显示的材质属性。计算漫反射公式中的材质的反射系数即由此提供,然后我们开始shader子通道的书写,首先我们设置了光照模式为前置光照模式,接着我们定义了顶点和片段2个函数,函数名任意,这里我们用了vert和frag名称,方便记忆;由于我们代码中要用到Unity3D中的一些函数,所以我们引用了”Light.cginc”,然后我们定义了顶点着色器的输入和输出结构,分别为a2v和v2f,因为下面的代码中要用到顶点的法线,所以我们在结构体a2v中normal,另外我们要把顶点计算出来的颜色传递给片段着色器,所以我们在结构体v2f中定义了一个color;重点到了,我们要在函数vert中计算漫反射,而且我们要返回一个v2f的值,因为顶点着色器的首要任务就是把模型空间中的顶点位置变换为裁剪空间的顶点位置,所以我们用了mul(UNITY_MATRIX_MVP,v.vert)来实施这一想法。因为我们需要环境光的计算,我们用了UNITY_LIGHTMODEL_AMBIENT来表示环境光,现在我们需要的是计算法线和入射光的单位矢量,因为我们必须要在同一个坐标系下进行计算,所以我们统一转换为世界坐标,fixed3
worldNormal=normalized(mul(v.normal,float3x3(_WorldO2bject)),这行代码是为了计算世界空间下的法线;而worldLight=normalized(_WorldSpaceLightPos0.xyz);这行代码是为了计算世界空间下的光线强度,由于我们在这之前只确保我们当前场景下面只有一个平行光,所以我们可以用Unity自带的函数来进行简单计算,如果实际场景是有多种光,则不能通过这种方法计算。然后我们返回了光照的计算结果,因为我们是在逐顶点进行的漫反射计算,所以在函数frag中我们只需要返回输出的颜色即可。
首先我们要先撸一个逐定点的漫反射,在此之前我们要知道计算漫反射光照的一段公式,如下所示:
C(diffuse)=(C(light)*M(diffuse))max(0,N*I)
下面对上述的公式就行一番讲解,首先C(diffuse)表示的是漫反射光照,就是我们将要计算的那部分;C(light)表示的是入射光线的颜色和强度;M(diffuse)表示的是材质的漫反射系数;N和I则表示的是表面法线和光源方向,另外需要说明的所有的值都为单位矢量。
好了,现在开始上代码,Unity3D创建项目各种步骤省略,现在我们先创建一个shader,命名随意,我们命名为FirstDiffuseShader.打开文件,开始具体写代码:
SShader "Unity Shaders/Chapter1/FirstDiffuseShader"{ Properties{ _Diffuse("Diffuse",Color)=(1,1,1,1) } SubShader{ Pass{ Tags{"LightMode"="ForwardBase"} CGPROGRAM #pragma vertex vert #pragma fragment frag #include "Lighting.cginc" fixed4 _Diffuse; struct a2v{ float4 vert:POSITION; float3 normal:NORMAL; }; struct v2f{ float4 pos:SV_POSITION; float3 color:TEXCOORD0; }; v2f vert(a2v v){ v2f o; o.pos=mul(UNITY_MATRIX_MVP,v.vert); fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT; fixed3 worldNormal=normalize(mul(v.normal,(float3x3)_World2Object)); fixed3 worldLight=normalize(_WorldSpaceLightPos0.xyz); fixed3 diffuse=_LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal,worldLight)); o.color=diffuse+ambient; return o; } fixed4 frag(v2f i): SV_Target{ return fixed4(i.color,1.0); } ENDCG } } FallBack "Diffuse" }
好的代码码完,开始讲解,先看一张效果图,当然我们还要创建材质这些步骤省略:见下图,哎呀,没有效果图,传上来太费经,我们开始讲解代码,首先我们定义了一系列shader的名称(第一行),然后我们定义了shader的属性:Properties,该属性显示的是我们Inspector上面显示的材质属性。计算漫反射公式中的材质的反射系数即由此提供,然后我们开始shader子通道的书写,首先我们设置了光照模式为前置光照模式,接着我们定义了顶点和片段2个函数,函数名任意,这里我们用了vert和frag名称,方便记忆;由于我们代码中要用到Unity3D中的一些函数,所以我们引用了”Light.cginc”,然后我们定义了顶点着色器的输入和输出结构,分别为a2v和v2f,因为下面的代码中要用到顶点的法线,所以我们在结构体a2v中normal,另外我们要把顶点计算出来的颜色传递给片段着色器,所以我们在结构体v2f中定义了一个color;重点到了,我们要在函数vert中计算漫反射,而且我们要返回一个v2f的值,因为顶点着色器的首要任务就是把模型空间中的顶点位置变换为裁剪空间的顶点位置,所以我们用了mul(UNITY_MATRIX_MVP,v.vert)来实施这一想法。因为我们需要环境光的计算,我们用了UNITY_LIGHTMODEL_AMBIENT来表示环境光,现在我们需要的是计算法线和入射光的单位矢量,因为我们必须要在同一个坐标系下进行计算,所以我们统一转换为世界坐标,fixed3
worldNormal=normalized(mul(v.normal,float3x3(_WorldO2bject)),这行代码是为了计算世界空间下的法线;而worldLight=normalized(_WorldSpaceLightPos0.xyz);这行代码是为了计算世界空间下的光线强度,由于我们在这之前只确保我们当前场景下面只有一个平行光,所以我们可以用Unity自带的函数来进行简单计算,如果实际场景是有多种光,则不能通过这种方法计算。然后我们返回了光照的计算结果,因为我们是在逐顶点进行的漫反射计算,所以在函数frag中我们只需要返回输出的颜色即可。
相关文章推荐
- 零代码保存窗口运行状态
- 不改一行代码定位线上性能问题
- Delphi 程序员代码编写标准指南 (五)
- Delphi 程序员代码编写标准指南 (四)
- Delphi 程序员代码编写标准指南 (二)
- Delphi 程序员代码编写标准指南
- 如何在VC中加入汇编代码?
- 如何让VC只输出汇编代码?
- 关于Basic程序解释器及编译原理的简单化(1)---Basic器的语法分析及主要代码
- 一步一步开始Web Service (有代码和图) (上)
- 一步一步开始Web Service (有代码和图) (下)
- 提高Java代码可重用性的三个措施
- Win32 API资源分配释放速查,防止代码资源泄露
- C++Builder常用代码片断
- 代码的风格
- Delphi程序员代码编写标准指南
- VB 实现大文件的分割与恢复,引用 ADODB.Stream 提供一个过程代码
- 一段精简的使用 ADODB.Stream 读写"大字段"的 VB 代码!
- VB 实现大文件的分割与恢复,引用 ADODB.Stream 提供一个过程代码
- Java代码编写的一般性指导