笔者介绍:姜雪伟泰课海洋老师

网上有很多关于Shader的教程,我在这里就不给读者讲解基础知识了,我们直接讲重点,我会结合着C++底层代码一起讲解,帮助读者理解Unity3D引擎内部对于Shader加载的实现原理,下面就结合着Unity3D中的Shader的编写给读者解释,在Unity3D中的每个Shader中都有SubShader代码段。以下面的代码为例:

  1. SubShader {  
  2.   
  3.         Pass{  
  4.         // Dont write to the depth buffer  
  5.         ZWrite off  
  6.   
  7.         // Set up alpha blending  
  8.         Blend SrcAlpha OneMinusSrcAlpha  
  9.   
  10.         CGPROGRAM  
  11.         #pragma vertex vert  
  12.         #pragma fragment frag  
  13.         #include "UnityCG.cginc"  
  14.   
  15.         sampler2D _MainTex;  
  16.         float4 _Color;  
  17.   
  18.         struct v2f{  
  19.             float4 pos:SV_POSITION;  
  20.             float4 texcoord : TEXCOORD0;  
  21.         };  
  22.   
  23.         v2f vert(appdata_base v)  
  24.         {  
  25.             v2f o;  
  26.             o.pos = mul(UNITY_MATRIX_MVP, v.vertex);  
  27.             o.texcoord = v.texcoord;  
  28.             return o;  
  29.         }  
  30.   
  31.         half4 frag(v2f i):COLOR0  
  32.         {  
  33.             half4 col = _Color * tex2D(_MainTex, i.texcoord.xy);  
  34.             return col;  
  35.         }  
  36.   
  37.         ENDCG  
  38.         }  
  39.           
  40.         pass  
  41.         {  
  42.           
  43.         }  
  44.     }   
  45.       
  46.     SubShader  
  47.     {  
  48.         Pass  
  49.         {  
  50.           
  51.         }  
  52.     }  

SubShader中包含的代码段是核心程序,它中间还有Pass通道,Pass通道包含了定义的输出结构体和处理顶点函数和处理片段函数,在一个Shader中还可以包含多个SubShader,这些SubShader可以根据硬件自行适配,下面结合着C++代码给读者分析一下Unity3D中的Shader。先把DirectX中的Shader代码展示如下:

  1. //--------------------------------------------------------------  
  2. // 全局变量  
  3. //--------------------------------------------------------------  
  4. float4x4 matWorldViewProj;    
  5. float4x4 matWorld;    
  6. float4   vecLightDir;  
  7. float4   vecEye;  
  8.   
  9. float4   materialAmbient;  
  10. float4   materialDiffuse;  
  11. float4   materialSpecular;  
  12.   
  13. //-------------------------------------------------------------  
  14. // 顶点渲染器输出结构  
  15. //-------------------------------------------------------------  
  16. struct VS_OUTPUT  
  17. {  
  18.    float4 Pos   : POSITION;  
  19.    float4 Color : COLOR;  
  20. };  
  21.   
  22. //-------------------------------------------------------------  
  23. // 顶点渲染器  
  24. //-------------------------------------------------------------  
  25. VS_OUTPUT VS( float4 Pos: POSITION, float3 Normal: NORMAL,   
  26.               uniform bool bEnableSelfShadow )  
  27. {  
  28.    VS_OUTPUT Out = (VS_OUTPUT) 0;   
  29.      
  30.    //顶点坐标变换  
  31.    Out.Pos = mul(Pos, matWorldViewProj);  
  32.      
  33.    //单位化光照方向向量   
  34.    float3 LightDir = normalize( vecLightDir );  
  35.      
  36.    //计算观察方向  
  37.    float3 PosWorld = normalize( mul(Pos, matWorld) );  
  38.    float3 ViewDir  = normalize( vecEye - PosWorld );  
  39.      
  40.    //计算法向量方向和漫反射强度  
  41.    float3 NormalWorld = normalize( mul(Normal, matWorld) );  
  42.    float4 diff        = saturate( dot(NormalWorld, LightDir) );  
  43.      
  44.    //计算反射光方向( R = 2 * (N.L) * N - L)和镜面反射强度  
  45.    float3 Reflect = normalize( 2 * diff * NormalWorld - LightDir );  
  46.    float4 specu = pow( saturate(dot(Reflect, ViewDir)), 0.5 );  
  47.     
  48.    //各种光的颜色  
  49.    float4 ambientColor  = { 0.1f, 0.0f, 0.0f, 1.0f};  
  50.    float4 diffuseColor  = { 1.0f, 0.0f, 0.0f, 1.0f};      
  51.    float4 specularColor = { 1.0f, 0.0f, 0.0f, 1.0f};    
  52.      
  53.    //计算顶点颜色  
  54.    if(bEnableSelfShadow)  //启用自阴影  
  55.    {  
  56.        float shadow = saturate(4* diff);    
  57.      
  58.        //计算顶点颜色 = Ambient + Shadow * ( Diffuse + Specular )  
  59.        Out.Color = ambientColor * materialAmbient + shadow *   
  60.                   (diffuseColor  * materialDiffuse * diff +   
  61.                    specularColor * specu * materialSpecular);   
  62.     }  
  63.     else //禁用自阴影  
  64.     {  
  65.         Out.Color = ambientColor  * materialAmbient +   
  66.                     diffuseColor  * materialDiffuse * diff +   
  67.                     specularColor * specu * materialSpecular;   
  68.     }  
  69.      
  70.    return Out;  
  71. }  
  72.   
  73.   
  74. //--------------------------------------------------------------  
  75. // 技术  
  76. //--------------------------------------------------------------  
  77. technique TShaderSelfShadow  
  78. {  
  79.     pass P0  
  80.     {  
  81.         VertexShader = compile vs_2_0 VS(true);  
  82.     }  
  83. }  
  84.   
  85. technique TShaderNoSelfShadow  
  86. {  
  87.     pass P0  
  88.     {  
  89.         VertexShader = compile vs_2_0 VS(false);  
  90.     }  
  91. }  

上述Shader定义了输出结构体这个跟Unity3D中的定义的结构体很类似,DirectX中的Shader定义了顶点渲染器VS函数: view plain copy 

  1. VS_OUTPUT VS( float4 Pos: POSITION, float3 Normal: NORMAL,   
  2.               uniform bool bEnableSelfShadow )  

其中,VS函数是结合了顶点着色器和片段着色器一起实现的,另外,它还定义了technique,在technique中也有pass通道,这个technique跟SubShader类似,pass通道跟SubPass中的pass通道类似。因为Unity引擎内部我们是看不到的,那就以DirectX中的C++代码为例给读者解密一下引擎内部是如何实现的,C++完整代码如下所示:

 copy
 
 
  1. /-----------------------------------------------------------------------------  
  2. 标签: Unity 海洋
0