Shader "Custom/SimpleShader" {
Properties {
// 定义着色器的属性
_MainTex ("Texture", 2D) = "white" {} // 纹理属性,默认为白色纹理
_Color ("Color", Color) = (1,1,1,1) // 颜色属性,默认为白色
_Speed ("Speed", Range(0, 10)) = 1 // 速度属性,默认值为1,最小值为0,最大值为10
}
SubShader {
// 定义子着色器的Tag
Tags {"Queue"="Transparent" "RenderType"="Opaque"}
CGPROGRAM
// 定义实际的着色器代码
#pragma surface surf Lambert // 使用Lambert光照模型渲染表面
// 定义结构体Input,包含纹理坐标和世界坐标
struct Input {
float2 uv_MainTex;
float3 worldPos;
};
// 定义着色器属性
sampler2D _MainTex;
float4 _Color;
float _Speed;
// 定义表面着色函数
void surf (Input IN, inout SurfaceOutput o) {
// 使用_MainTex纹理和_Color颜色计算表面的漫反射颜色
o.Albedo = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Alpha = 1; // 设置不透明度为1
o.Emission = 0; // 设置自发光为0
o.Metallic = 0; // 设置金属度为0
o.Smoothness = 0; // 设置平滑度为0
IN.worldPos += float3(sin(_Time.y * _Speed), cos(_Time.x * _Speed), 0); // 根据时间和速度修改世界坐标
o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_MainTex)); // 从法线纹理中获取法线
}
ENDCG
}
FallBack "Diffuse" // 如果硬件不支持,回退到Diffuse着色器
}
现在,让我解释一下这个着色器的每个部分:
Shader “Custom/SimpleShader” { … }: 定义了着色器的名称和属性。在这个示例中,我们把它命名为“Custom/SimpleShader”,并定义了三个属性:一张名为“_MainTex”的纹理,一个名为“_Color”的颜色和一个名为“_Speed”的范围(Range)。
SubShader { … }: 定义了着色器的子着色器,这个子着色器的Tag定义了绘制顺序和渲染类型。在这个示例中,我们把绘制顺序设置为“Transparent”,渲染类型设置为“Opaque”。
CGPROGRAM … ENDCG: 定义了实际的着色器代码。在这个示例中,我们使用了Surface Shader结构,并且定义了一个结构体Input,它包含了纹理坐标和世界坐标。
#pragma surface surf Lambert: 声明使用Lambert光照模型来渲染表面。这里也可以使用其他光照模型,例如Phong或Blinn-Phong。
sampler2D _MainTex; float4 _Color; float _Speed;: 定义了着色器的属性。这里我们定义了_MainTex、_Color和_Speed三个属性,用来存储纹理、颜色和速度。
void surf (Input IN, inout SurfaceOutput o) { … }: 定义了表面着色函数。在这个函数中,我们使用了_MainTex纹理和_Color颜色来计算表面的漫反射颜色,然后使用_UnpackNormal函数从法线纹理中获取法线。
CGPROGRAM 和 ENDCG: 用于定义CG语言的代码块,其中的代码将被编译为GPU可执行的代码。
#pragma surface: 用于指定表面着色器函数的使用和属性设置,本例中指定使用Lambert光照模型。
sampler2D: 纹理类型的变量,用于存储纹理数据,本例中使用了_MainTex纹理属性。
SurfaceOutput: 用于定义表面着色函数的输出数据结构体,其中包含了表面的漫反射颜色、自发光、金属度、平滑度、法线等信息。
UnpackNormal: 用于从法线纹理中获取法线信息。
_Time: Unity内置的系统变量,包含了游戏运行的时间信息,可以用于实现时间相关的效果。
FallBack: 定义着色器在硬件不支持时的回退方案,默认为Diffuse着色器。