【從UnityURP開始探索遊戲渲染】專欄-直達
Film Grain的定義與作用
Film Grain是一種模擬傳統攝影膠片顆粒感的後期處理效果,通過添加隨機噪點紋理增強畫面的藝術表現力。其核心用途包括:
- 復古風格模擬:重現膠片攝影的顆粒質感,增強懷舊氛圍
- 畫面細節強化:掩蓋低分辨率紋理的瑕疵,提升視覺豐富度
- 電影感塑造:配合色調映射、色差等效果構建電影級視覺風格
發展歷史
- 傳統膠片時代:物理銀鹽顆粒形成的自然噪點
- 數字時代初期:通過簡單噪聲算法模擬(如Perlin噪聲)
- 現代遊戲引擎:HDRP/URP等管線集成預設化系統,支持物理準確的顆粒分佈模型(如Kodak系列預設)
原理
Unity URP中的Film Grain效果通過噪聲紋理疊加和亮度響應曲線實現膠片顆粒模擬.
噪聲生成機制
- 預設紋理採樣:內置Kodak/Agfa等膠片顆粒的預烘焙LUT紋理(64x64分辨率),通過屏幕UV座標進行雙線性採樣
- 動態噪聲合成:當選擇"Custom"模式時,使用Simplex噪聲算法實時生成3D噪聲場,通過時間參數實現動態流動效果
- 色彩空間轉換:噪聲值在YCoCg色彩空間進行混合,避免RGB通道直接疊加導致的色偏問題
亮度響應系統
hlsl
float grainIntensity = intensity * (1 - smoothstep(0.5, 1.0, luminance));
該公式根據像素亮度動態調節顆粒強度,使暗部保留更多噪點(響應曲線參數控制過渡斜率)
實現示例
該Shader實現包含噪聲紋理平鋪、亮度自適應調節和色彩安全混合三個關鍵技術點
-
Filmgrain.shader
Shader "PostProcessing/FilmGrain" { Properties { _GrainTex ("Noise Texture", 2D) = "white" {} _Intensity ("Intensity", Range(0,1)) = 0.5 _Response ("Response", Range(0,1)) = 0.8 } SubShader { Pass { HLSLPROGRAM #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" TEXTURE2D(_GrainTex); SAMPLER(sampler_GrainTex); float _Intensity; float _Response; float4 Frag(Varyings input) : SV_Target { float2 uv = input.uv * float2(80,45); // 平鋪噪聲 float3 grain = SAMPLE_TEXTURE2D(_GrainTex,sampler_GrainTex,uv).rgb; float luminance = Luminance(SceneColor.rgb); float adaptive = lerp(1.0, 1.0-luminance, _Response); return SceneColor * (1.0 + grain * _Intensity * adaptive); } ENDHLSL } } }
管線集成流程
- 渲染階段:在URP的PostProcessingStack中插入FilmGrainPass,執行順序在Tonemapping之後、FXAA之前
- 性能優化:採用1/4分辨率渲染噪聲紋理,通過硬件線性濾波降低帶寬消耗
- 移動端適配:使用ARM NEON指令集加速噪聲計算,在GPU Tile-Based架構下減少內存訪問次數
URP實現流程
-
FilmGrainExample.cs
using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; [VolumeComponentMenu("Post-processing/Film Grain")] public class CustomFilmGrain : VolumeComponent, IPostProcessComponent { public FilmGrainLookupParameter type = new FilmGrainLookupParameter(FilmGrainLookup.Kodak_200); public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f); public ClampedFloatParameter response = new ClampedFloatParameter(0.8f, 0f, 1f); public bool IsActive() => intensity.value > 0f; public bool IsTileCompatible() => false; } -
FilmGrainRenderer.cs
using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class FilmGrainRenderer : ScriptableRendererFeature { class CustomPass : ScriptableRenderPass { // 渲染邏輯實現... } public override void Create() { // 初始化代碼... } }
參數詳解與用例
| 參數 | 類型 | 説明 | 典型用例 |
|---|---|---|---|
| Type | Enum | 預設顆粒類型(Kodak200/400等) | 選擇Agfa400模擬16mm膠片 |
| Intensity | 0-1 | 顆粒可見度 | 0.3-0.5用於復古RPG遊戲 |
| Response | 0-1 | 亮度響應曲線 | 0.7使亮部顆粒減弱 |
| Texture | 2D | 自定義噪點貼圖 | 製作數字故障藝術效果 |
操作步驟(URP 2022.1+)
- 創建Volume對象:
GameObject > Volume - 添加Film Grain覆蓋:
Add Override > Film Grain -
配置參數示例:
Type = Kodak500T
Intensity = 0.4
Response = 0.65
性能優化建議
- 移動端使用Quarter分辨率
- 動態調整Intensity(劇情過場時增強)
- 禁用非必要時的Volume更新
【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)