Unity Shader編程完全入門指南:從零到實戰 C#
本文將深入探討Unity Shader編程的高級技術,包括自定義光照模型、后處理效果、GPU實例化、表面著色器深度應用等,幫助開發者提升渲染效果與性能優化能力。
提示:內容純個人編寫,歡迎評論點贊。
文章目錄
- Unity Shader編程完全入門指南:從零到實戰 C#
- 1. 高級光照模型
- 1.1 光照模型理論基礎
- 1.2 實現PBR光照
- 1.3 自定義卡通光照
- 2. 后處理效果處理
- 2.1 后處理原理
- 2.2 Bloom效果實現
- 2.3 屏幕空間環境光遮蔽(SSAO)
- 3. 表面著色器深度應用
- 3.1 表面函數高級用法
- 3.2 自定義頂點修改
- 3.3 多光源支持
- 4. GPU實例化優化
- 4.1 實例化原理
- 4.2 靜態批處理 vs GPU實例化
- 4.3 實例化實戰:草地渲染
- 5. Shader變體管理
- 5.1 變體概念
- 5.2 變體控制技巧
- 5.3 變體優化策略
- 6. 計算著色器入門
- 6.1 計算著色器基礎
- 6.2 粒子系統優化
- 6.3 通用計算應用
- 7. 實戰案例:天氣系統
- 7.1 雨滴效果
- 7.2 雪地腳印
- 7.3 動態潮濕效果
- 8. 性能調優與調試
- 8.1 Shader性能分析
- 8.2 帶寬優化
- 8.3 跨平臺適配
- 9. 總結與資源
1. 高級光照模型
1.1 光照模型理論基礎
光照模型描述了光與物體表面相互作用的數學表示:
- Phong模型:環境光+漫反射+高光反射
I = I_ambient + I_diffuse + I_specular
- BRDF(雙向反射分布函數):更精確的物理模型
1.2 實現PBR光照
基于物理的渲染(PBR)核心公式:
// Unity Standard BRDF
half4 BRDF_Unity_PBS(half3 diffColor, half3 specColor, half oneMinusReflectivity, half smoothness,float3 normal, float3 viewDir,Light light, InputData data
) {// ... PBR計算過程
}
完整PBR表面著色器示例:
Shader "Custom/PBRShader"
{Properties {_Color ("Color", Color) = (1,1,1,1)_Metallic ("Metallic", Range(0,1)) = 0.0_Smoothness ("Smoothness", Range(0,1)) = 0.5_NormalMap ("Normal Map", 2D) = "bump" {}}SubShader {Tags { "RenderType"="Opaque" }CGPROGRAM#pragma surface surf Standard fullforwardshadowsstruct Input {float2 uv_NormalMap;};half _Metallic;half _Smoothness;half4 _Color;sampler2D _NormalMap;void surf (Input IN, inout SurfaceOutputStandard o) {o.Albedo = _Color.rgb;o.Metallic = _Metallic;o.Smoothness = _Smoothness;o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_NormalMap));}ENDCG}FallBack "Diffuse"
}
1.3 自定義卡通光照
// 卡通光照函數
void LightingRamp_GI (SurfaceOutput s,UnityGIInput data,inout UnityGI gi
) {// ... 全局光照設置
}void LightingRamp_CS (SurfaceOutput s,half3 viewDir,UnityGI gi,out half4 finalColor
) {// 離散化處理half NdotL = dot(s.Normal, gi.light.dir);half ramp = ceil(NdotL * _RampSteps) / _RampSteps;// 最終顏色finalColor.rgb = s.Albedo * gi.light.color * ramp;finalColor.a = s.Alpha;
}
2. 后處理效果處理
2.1 后處理原理
后處理在渲染完成后對屏幕圖像進行處理:
渲染場景 -> 獲取屏幕圖像 -> 應用后處理Shader -> 輸出最終圖像
2.2 Bloom效果實現
// Bloom效果Shader核心
half4 frag_bloom (v2f i) : SV_Target
{// 1. 亮度提取half4 col = tex2D(_MainTex, i.uv);half brightness = dot(col.rgb, float3(0.2126, 0.7152, 0.0722));if(brightness < _BloomThreshold)return 0;// 2. 高斯模糊half4 blur = 0;for(int i = 0; i < KERNEL_SIZE; i++) {blur += _BloomKernel[i] * tex2D(_MainTex, i.uv + _BloomOffsets[i]);}// 3. 混合原始圖像與模糊圖像return col + blur * _BloomIntensity;
}
2.3 屏幕空間環境光遮蔽(SSAO)
// SSAO核心計算
float ComputeAO(float2 uv, float3 viewNormal)
{float ao = 0.0;for(int i = 0; i < SAMPLE_COUNT; i++) {float3 samplePos = GetSamplePosition(uv, i);float sample = depthCompare(samplePos);ao += ComputeAOContribution(viewNormal, samplePos, sample);}return 1.0 - (ao / SAMPLE_COUNT) * _AOIntensity;
}
3. 表面著色器深度應用
3.1 表面函數高級用法
void surf (Input IN, inout SurfaceOutputStandard o)
{// 世界坐標計算float3 worldPos = IN.worldPos;// 三平面貼圖混合float3 triblend = pow(abs(IN.worldNormal), _BlendSharpness);triblend /= dot(triblend, float3(1,1,1));half4 colX = tex2D(_MainTex, IN.worldPos.yz);half4 colY = tex2D(_MainTex, IN.worldPos.xz);half4 colZ = tex2D(_MainTex, IN.worldPos.xy);o.Albedo = colX * triblend.x + colY * triblend.y + colZ * triblend.z;
}
3.2 自定義頂點修改
#pragma surface surf Lambert vertex:vertvoid vert (inout appdata_full v, out Input o)
{UNITY_INITIALIZE_OUTPUT(Input, o);// 頂點波浪動畫float wave = sin(_Time.y + v.vertex.x * _WaveFreq);v.vertex.y += wave * _WaveAmp;// 傳遞世界坐標o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
}
3.3 多光源支持
#pragma surface surf Standard fullforwardshadows
#pragma multi_compile_fwdaddvoid surf (Input IN, inout SurfaceOutputStandard o)
{// 表面函數
}// 額外光源處理
#ifdef _ADDITIONAL_LIGHTSuint pixelLightCount = GetAdditionalLightsCount();for (uint lightIndex = 0; lightIndex < pixelLightCount; lightIndex++) {Light light = GetAdditionalLight(lightIndex, IN.worldPos);// 光源貢獻計算}
#endif
4. GPU實例化優化
4.1 實例化原理
GPU實例化允許一次性繪制多個相同網格,減少Draw Call:
常規繪制: Draw Call 1 -> 網格1Draw Call 2 -> 網格1...
實例化: Draw Call 1 -> 網格1 (實例1, 實例2, ...)
4.2 靜態批處理 vs GPU實例化
4.3 實例化實戰:草地渲染
Shader "Custom/InstancedGrass"
{Properties { /* 屬性 */ }SubShader{Pass{Tags { "LightMode"="ForwardBase" }CGPROGRAM#pragma vertex vert#pragma fragment frag#pragma multi_compile_instancingUNITY_INSTANCING_BUFFER_START(Props)UNITY_DEFINE_INSTANCED_PROP(float4, _Color)UNITY_DEFINE_INSTANCED_PROP(float, _Height)UNITY_INSTANCING_BUFFER_END(Props)struct appdata{float4 vertex : POSITION;UNITY_VERTEX_INPUT_INSTANCE_ID};struct v2f{float4 pos : SV_POSITION;UNITY_VERTEX_INPUT_INSTANCE_ID};v2f vert (appdata v){v2f o;UNITY_SETUP_INSTANCE_ID(v);UNITY_TRANSFER_INSTANCE_ID(v, o);float height = UNITY_ACCESS_INSTANCED_PROP(Props, _Height);v.vertex.y += height;o.pos = UnityObjectToClipPos(v.vertex);return o;}fixed4 frag (v2f i) : SV_Target{UNITY_SETUP_INSTANCE_ID(i);return UNITY_ACCESS_INSTANCED_PROP(Props, _Color);}ENDCG}}
}
5. Shader變體管理
5.1 變體概念
Shader變體由預編譯指令組合生成:
#pragma multi_compile _ A B
#pragma multi_compile C D
5.2 變體控制技巧
- 精確控制:
#pragma shader_feature _ENABLE_FEATURE
- 跳過變體:
#pragma skip_variants POINT SPOT
5.3 變體優化策略
- 避免不必要的multi_compile
- 使用shader_feature替代multi_compile
- 拆分變體過多的Shader
- 使用變體集合(Variant Collections)
6. 計算著色器入門
6.1 計算著色器基礎
#pragma kernel CSMainRWTexture2D<float4> Result;
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{// 并行計算Result[id.xy] = float4(id.x & id.y, (id.x & 15)/15.0, (id.y & 15)/15.0, 0.0);
}
6.2 粒子系統優化
// 粒子更新計算著色器
RWStructuredBuffer<Particle> ParticleBuffer;[numthreads(64,1,1)]
void UpdateParticles (uint id : SV_DispatchThreadID)
{Particle p = ParticleBuffer[id];// 更新位置p.velocity += float3(0, -9.8, 0) * dt;p.position += p.velocity * dt;// 碰撞檢測if(p.position.y < 0) {p.position.y = 0;p.velocity.y *= -0.8;}ParticleBuffer[id] = p;
}
6.3 通用計算應用
- 網格變形
- 物理模擬
- 紋理生成
- 光線追蹤
7. 實戰案例:天氣系統
7.1 雨滴效果
// 雨滴表面著色器
void surf (Input IN, inout SurfaceOutput o)
{// 雨滴法線貼圖float2 rainUV = IN.worldPos.xz * _RainScale + float2 _Time.y * _RainSpeed;half3 rainNormal = UnpackNormal(tex2D(_RainNormalMap, rainUV));// 混合基礎法線o.Normal = BlendNormals(o.Normal, rainNormal);// 濕潤效果half wetFactor = saturate(_RainAmount * 2 - 1);o.Albedo = lerp(_DryColor, _WetColor, wetFactor);
}
7.2 雪地腳印
// 腳印渲染
float3 worldPos = IN.worldPos;
float2 footprintUV = worldPos.xz - _PlayerPos.xz;
half footprint = tex2D(_FootprintMask, footprintUV).r;// 混合雪地材質
o.Albedo = lerp(_SnowColor, _GroundColor, footprint);
o.Smoothness = lerp = lerp(_SnowSmoothness, 0.2, footprint);
7.3 動態潮濕效果
// 潮濕貼圖隨時間變化
float2 wetUV = IN.worldPos.xz * _WetScale;
half wetPattern = tex2D(_WetPatternMap, wetUV).r;// 隨時間增加的潮濕程度
half wetFactor = saturate(_Wetness * 2 - wetPattern);
o.Metallic = lerp(0.0, 0.8, wetFactor);
o.Smoothness = lerp(0.1, 0.9, wetFactor);
8. 性能調優與調試
8.1 Shader性能分析
GPU性能分析:
- Unity Frame Debugger
- RenderDoc
- XCode GPU Debugger
關鍵指標:
- Fill Rate(填充率)
- Overdraw(過度繪制)
- Shader復雜度
8.2 帶寬優化
- 壓縮紋理格式(ASTC, ETC2)
- Mipmap優化
- 減少紋理采樣次數
- 使用紋理圖集
8.3 跨平臺適配
// 平臺相關宏
#if defined(SHADER_API_MOBILE)// 移動端簡化版
#elif defined(SHADER_API_D3D11)// PC高級版
#endif// 精度調整
#if defined(SHADER_API_GLES)precision mediump float;
#elseprecision highp float;
#endif
9. 總結與資源
核心進階技術:
- 物理光照模型實現
- 后處理特效開發
- GPU實例化優化
- 計算著色器應用
繼續學習資源:
- Unity官方Shader文檔
- Catlike Coding教程
- 希望本文能幫助你在Unity開發中更加得心應手!如果有任何問題,請在評論區留言討論。
- 點贊收藏加關注哦~ 蟹蟹