Unity Shader编程是游戏开发中不可或缺的一部分,它能够显著增强游戏画面的表现力。Shader作为图形渲染的核心,通过编写Shader代码,可以实现各种复杂的材质效果和光影效果。本文将带领读者从入门到实战,深入解析Unity Shader编程。
在Unity中,Shader主要分为两类:表面着色器(Surface Shaders)和顶点/片段着色器(Vertex/Fragment Shaders)。表面着色器是一种高级抽象,通过简单的语法即可实现复杂的渲染效果;而顶点/片段着色器则提供了更底层的控制,适合实现自定义渲染逻辑。
表面着色器主要使用HLSL(高级着色语言)编写,通过定义一些属性如光照模型、颜色、法线等,Unity会自动生成相应的顶点/片段着色器代码。以下是一个简单的表面着色器示例:
Shader "Custom/SimpleSurfaceShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
sampler2D _BumpMap;
half4 _Color;
half _Glossiness;
half _Metallic;
struct Input
{
float2 uv_MainTex;
float2 uv_BumpMap;
};
// Adding a second light source
void surf (Input IN, inout SurfaceOutputStandard o)
{
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and glossiness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
顶点/片段着色器提供了更灵活的渲染控制,适用于需要自定义渲染逻辑的场景。以下是一个简单的顶点/片段着色器示例:
Shader "Custom/SimplePassThroughShader"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct appdata_t
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
};
v2f vert (appdata_t v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 返回一个简单的颜色值
return fixed4(i.normal * 0.5 + 0.5, 1.0);
}
ENDCG
}
}
}
通过顶点/片段着色器,可以实现一个简单的水波效果。以下是实现该效果的Shader代码:
Shader "Custom/WaterWaveShader"
{
Properties
{
_WaveSpeed ("Wave Speed", Float) = 1.0
_WaveHeight ("Wave Height", Float) = 0.1
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
float _WaveSpeed;
float _WaveHeight;
struct Input
{
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o)
{
float2 uv = IN.uv_MainTex;
float wave = sin(_Time.y * _WaveSpeed + uv.x * 10.0) * _WaveHeight;
uv.y += wave;
fixed4 c = tex2D(_MainTex, uv);
o.Albedo = c.rgb;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
卡通渲染效果是游戏开发中常用的一种渲染风格,通过调整光照模型和颜色,可以实现简洁明快的画面效果。以下是实现该效果的Shader代码:
Shader "Custom/ToonShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_OutlineColor ("Outline Color", Color) = (0,0,0,1)
_OutlineWidth ("Outline Width", Range(0, 0.1)) = 0.02
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata_t
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
};
sampler2D _MainTex;
float4 _OutlineColor;
float _OutlineWidth;
v2f vert (appdata_t v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 计算轮廓线
float3 viewDir = normalize(WorldSpaceViewDir(i.pos));
float outline = step(_OutlineWidth, abs(dot(i.normal, viewDir)));
// 采样纹理颜色
fixed4 col = tex2D(_MainTex, i.pos.xy / i.pos.w);
// 应用轮廓线颜色
col = lerp(col, _OutlineColor, outline);
// 应用卡通渲染效果(简单色调分离)
float3 toneMapped = step(0.5, col.rgb) * fixed3(1, 0.7, 0.5);
return fixed4(toneMapped, col.a);
}
ENDCG
}
}
FallBack "Diffuse"
}