详解Unity3D Shader之Shader Lab框架

本文由IT专家姜雪伟撰写,深入探讨Unity3D Shader的内部实现,结合C++底层代码,解释Shader加载原理。通过示例代码讲解Unity3D中SubShader的使用,并对比Direct3D的SetTechnique函数,帮助读者理解3D渲染引擎的工作方式。博客中虽文字精炼,但代码注释详尽。
摘要由CSDN通过智能技术生成

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN课程视频网址:http://edu.csdn.net/lecturer/144

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

SubShader {

		Pass{
		// Dont write to the depth buffer
		ZWrite off

		// Set up alpha blending
		Blend SrcAlpha OneMinusSrcAlpha

		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "UnityCG.cginc"

		sampler2D _MainTex;
		float4 _Color;

		struct v2f{
			float4 pos:SV_POSITION;
			float4 texcoord : TEXCOORD0;
		};

		v2f vert(appdata_base v)
		{
			v2f o;
			o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
			o.texcoord = v.texcoord;
			return o;
		}

		half4 frag(v2f i):COLOR0
		{
			half4 col = _Color * tex2D(_MainTex, i.texcoord.xy);
			return col;
		}

		ENDCG
		}
		
		pass
		{
		
		}
	} 
	
	SubShader
	{
		Pass
		{
		
		}
	}

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

//--------------------------------------------------------------
// 全局变量
//--------------------------------------------------------------
float4x4 matWorldViewProj;	
float4x4 matWorld;	
float4   vecLightDir;
float4   vecEye;

float4   materialAmbient;
float4   materialDiffuse;
float4   materialSpecular;

//-------------------------------------------------------------
// 顶点渲染器输出结构
//-------------------------------------------------------------
struct VS_OUTPUT
{
   float4 Pos   : POSITION;
   float4 Color : COLOR;
};

//-------------------------------------------------------------
// 顶点渲染器
//-------------------------------------------------------------
VS_OUTPUT VS( float4 Pos: POSITION, float3 Normal: NORMAL, 
              uniform bool bEnableSelfShadow )
{
   VS_OUTPUT Out = (VS_OUTPUT) 0; 
   
   //顶点坐标变换
   Out.Pos = mul(Pos, matWorldViewProj);
   
   //单位化光照方向向量 
   float3 LightDir = normalize( vecLightDir );
   
   //计算观察方向
   float3 PosWorld = normalize( mul(Pos, matWorld) );
   float3 ViewDir  = normalize( vecEye - PosWorld );
   
   //计算法向量方向和漫反射强度
   float3 NormalWorld = normalize( mul(Normal, matWorld) );
   float4 diff        = saturate( dot(NormalWorld, LightDir) );
   
   //计算反射光方向( R = 2 * (N.L) * N - L)和镜面反射强度
   float3 Reflect = normalize( 2 * diff * NormalWorld - LightDir );
   float4 specu = pow( saturate(dot(Reflect, ViewDir)), 0.5 );
  
   //各种光的颜色
   float4 ambientColor  = { 0.1f, 0.0f, 0.0f, 1.0f};
   float4 diffuseColor  = { 1.0f, 0.0f, 0.0f, 1.0f};    
   float4 specularColor = { 1.0f, 0.0f, 0.0f, 1.0f};  
   
   //计算顶点颜色
   if(bEnableSelfShadow)  //启用自阴影
   {
       float shadow = saturate(4* diff);  
   
       //计算顶点颜色 = Ambient + Shadow * ( Diffuse + Specular )
       Out.Color = ambientColor * materialAmbient + shadow * 
                  (diffuseColor  * materialDiffuse * diff + 
                   specularColor * specu * materialSpecular); 
    }
    else //禁用自阴影
    {
        Out.Color = ambientColor  * materialAmbient + 
                    diffuseColor  * materialDiffuse * diff + 
                    specularColor * specu * materialSpecular; 
    }
   
   return Out;
}


//--------------------------------------------------------------
// 技术
//--------------------------------------------------------------
technique TShaderSelfShadow
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS(true);
    }
}

technique TShaderNoSelfShadow
{
    pass P0
    {
        VertexShader = compile vs_2_0 VS(false);
    }
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值