最近在学习Unity3D中的着色器编程,看了几个例子,但是对Shader的结构还不是很理解,于是上网搜索了一些资料,整理如下:
1.surface shader的主方法原来是在fragment shader中调用的,使用一个inout类型SurfaceOutput参数
参考链接:点击打开链接
2.通过一个自定义的着色器实例解析着色器的结构,着色器代码如下:
Shader "Custom/BlinnPhong"
{
//其中的属性可以在Inspect窗口中进行可视化设置
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
_MainTint ("Diffuse Tint", Color) = (1, 1, 1, 1)
_SpecularColor ("Specular Color", Color) = (1, 1, 1, 1)
_SpecularPower ("Specular Power", Range(0.1, 60)) = 3
}
//可以有多个SubShader,根据编译指示选择不同的SubShader进行渲染
SubShader
{
// 绘制类型,只是用于Replaced Shaders的标记,并不是必须的。
// 如果需要定义对象的绘制顺序,请使用Queue标记
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
//该语句的原型是这样的:#pragma surface surfaceFunction lightModel [optionalparams]
//其中 surface 是声明为 表面Shader, surfaceFuction 是Shader的指定实现方法,
//lightMode[optionalparams]是Shader使用的光照模型
// 定义着色器类型为surface,着色器入口方法为surf(),光照模型为CustomBlinnPhong
#pragma surface surf CustomBlinnPhong
sampler2D _MainTex;
sampler2D _SpecularMask;
float4 _MainTint;
float4 _SpecularColor;
float _SpecularPower;
struct Input
{
// Unity3D中shader的默认规则,纹理定义前面加uv前缀代表是对应的纹理坐标
float2 uv_MainTex;
};
//自定义的光照模型,不使用内置的光照模型
inline fixed4 LightingCustomBlinnPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
{
float sDotN = max(dot(s.Normal, lightDir), 0.0);
float3 h = normalize(lightDir + viewDir);
float hDotN = max(dot(s.Normal, h), 0.0);
float spec = pow(hDotN, _SpecularPower);
fixed4 c;
c.rgb = (s.Albedo * _LightColor0.rgb * sDotN) + (_LightColor0.rgb * _SpecularColor.rgb * spec) * (atten * 2);
c.a = s.Alpha;
return c;
}
//这里的 surf 相当于 C语言的main函数,可以认为是Shader的执行入口,不过跟main不同的是,
//他可以随意命名,然后在 #pragma surface 指定就行了
//surf 方法其实对输入结构 Input IN 进行处理,得到输出 SurfaceOutput o的像素结构
void surf (Input IN, inout SurfaceOutput o)
{
half4 c = tex2D (_MainTex, IN.uv_MainTex) * _MainTint;
float4 specMask = tex2D(_SpecularMask, IN.uv_MainTex) * _SpecularColor;
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
// 如果当前GPU不支持本shader,默认使用Diffuse
FallBack "Diffuse"
}