一个好的Shader总是从一个基本的 diffuse 光照模型开始
因此,我们从 Diffuse 入手开始写 Shader ~
Shader 中的 Diffuse 部分描述从一个表面上向各个方向反射的光
在Unity中创建 Shader 并打开
得到了一个 Unity 的 Shader 模板
Shader "HineNotes/CookbookCh_01/BasicDiffuse" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
其中 Shader 关键字后的字符串 “Cookbook_01/BasicDiffuse”
为 Shader 名,利用 / 可以为 Shader 设置分级菜单
新建一个 Material, 也起名 BasicDiffuse 把这个Shader赋给它
再把这个 Material 赋给模型,得到的效果就是这样~
这是一个 Surface Shader, Unity 为我们做了很多幕后工作
随着我们深入学习,对于其背后的 Cg 语言,以及 Unity 如何处理背后的底层 GPU 任务,会有更多的了解
有关 Unity 内置的 Cg 函数,参考 Unity安装目录\Editor\Data\CGIncludes
目前值得我们关注的有
UnityCG.cginc, Lighting.cginc, UnityShaderVariables.cginc
我们当前的这个 Shader 用到了这些文件
选中刚刚的 BasicDiffuse 材质,在 Inspector 面板中,我们可以看到 Shader 属性 Base (RGB)
也就是 BasicDiffuse 中的这一段
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
}
定义属性的语法为
Properties { Property [Property …] }
而通常的写法为
_name (“display name”, type) = “defaulttexture” {}
name 为属性名,在Unity中属性名通常以下划线 _开始,display name 为该属性在 Inspector 面板中显示的名字,type 表示属性的类型(具体见下面的表格)赋值符号后面的字符串是默认值,根据不同属性类型来提供,而最后的大括号中则是可选的选项
属性类型 | 描述 |
---|---|
Range (min, max) | 在 Inspector 面板中创建一个滑条,在最大最小值之间滑动,接受 float 参数 |
Color | 在 Inspector 面板中创建一个颜色面板,可以打开拾色器,获取颜色 float4 = (float,float,float,float) |
2D | 在 Inspector 面板中创建一个贴图面板,允许用户为 Shader 指定贴图对于 2D 和 Cube 类型,默认值可以使用空字符串”“,或“white”,”black”,”gray”,”bump” |
3D | 在 Inspector 面板中创建一个贴图面板,允许用户为 Shader 指定3D贴图 |
Rect | 在 Inspector 面板中创建一个不以2的整数幂为大小的贴图 |
Cube | 在 Inspector 面板中创建一个 cube map 面板,允许用户为 Shader 指定 cube map |
Float | 在 Inspector 面板中创建一个 float 值输入框,但没有滑条 |
Int | 在 Inspector 面板中创建一个 int 值输入框 |
Vector | 在 Inspector 面板中创建一组4个 float 值输入框,可以用来传入方向和颜色 |
将初始 Shader 的标题改为
“HineNotes/CookbookCh_01/UseOfProperties”
其中的属性段改为
Properties {
_Slider ("Slider", Range(0, 10)) = 5
_Float ("Float", Float) = 1.0
_Int ("Int", Int) = 1
_Color ("Clolr", Color) = ( 0.262, 0.612, 1.0, 1.0)
_Vector ("Vector", Vector) = (1.0, 1.0, 1.0, 1.0)
_TwoD("2D", 2D) = "" {}
_Cube("Cube", Cube) = "" {}
_ThreeD("3D", 3D) = "" {}
_MainTex ("Base (RGB)", 2D) = "white" {}
}
存储后切换到 Unity, Unity 会对更改后的 Shder 自动进行编译,我们可以在 Inspector 中看到属性效果
Base( RGB ) 上方就是我们刚刚新添加的属性
对于 Property 部分的介绍,可以参考 Unity 官方文档
http://docs.unity3d.com/Manual/SL-Properties.html
想要在 SubShader 块中使用属性,我们需要在其中创建与 Properties 块中同名的属性
将 CGPROGRAM 段修改为
CGPROGRAM
#pragma surface surf Lambert
float4 _Color;
float _Slider;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
float4 c;
c = pow(_Color, _Slider);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
即可得到由 _Color 和 _Slider 两个属性共同控制的 Shader
其中 _Color 控制漫反射颜色,_Slider 控制强度
最终的 UseOfProperties Shader 如下
Shader "HineNotes/CookbookCh_01/UseOfProperties" {
Properties {
_Slider ("Slider", Range(0, 10)) = 5
_Float ("Float", Float) = 1.0
_Int ("Int", Int) = 1
_Color ("Clolr", Color) = ( 0.262, 0.612, 1.0, 1.0)
_Vector ("Vector", Vector) = (1.0, 1.0, 1.0, 1.0)
_TwoD("2D", 2D) = "" {}
_Cube("Cube", Cube) = "" {}
_ThreeD("3D", 3D) = "" {}
_MainTex ("Base (RGB)", 2D) = "white" {}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
float4 _Color;
float _Slider;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o) {
float4 c;
c = pow(_Color, _Slider);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
其中 pow(arg1, arg2) 函数是 Cg 语言内置的函数,提供指数运算
关于更多 Cg 内置函数,参考
http://http.developer.nvidia.com/CgTutorial/cg_tutorial_appendix_e.html