【从UnityURP开始探索游戏渲染】专栏-直达
Film Grain的定义与作用
Film Grain是一种模拟传统摄影胶片颗粒感的后期处理效果,通过添加随机噪点纹理增强画面的艺术表现力。其核心用途包括:
- 复古风格模拟:重现胶片摄影的颗粒质感,增强怀旧氛围
- 画面细节强化:掩盖低分辨率纹理的瑕疵,提升视觉丰富度
- 电影感塑造:配合色调映射、色差等效果构建电影级视觉风格
发展历史
- 传统胶片时代:物理银盐颗粒形成的自然噪点
- 数字时代初期:通过简单噪声算法模拟(如Perlin噪声)
- 现代游戏引擎:HDRP/URP等管线集成预设化系统,支持物理准确的颗粒分布模型(如Kodak系列预设)
原理
Unity URP中的Film Grain效果通过噪声纹理叠加和亮度响应曲线实现胶片颗粒模拟.
噪声生成机制
- 预设纹理采样:内置Kodak/Agfa等胶片颗粒的预烘焙LUT纹理(64x64分辨率),通过屏幕UV坐标进行双线性采样
- 动态噪声合成:当选择"Custom"模式时,使用Simplex噪声算法实时生成3D噪声场,通过时间参数实现动态流动效果
- 色彩空间转换:噪声值在YCoCg色彩空间进行混合,避免RGB通道直接叠加导致的色偏问题
亮度响应系统
c
hlsl
float grainIntensity = intensity * (1 - smoothstep(0.5, 1.0, luminance));
该公式根据像素亮度动态调节颗粒强度,使暗部保留更多噪点(响应曲线参数控制过渡斜率)
实现示例
该Shader实现包含噪声纹理平铺、亮度自适应调节和色彩安全混合三个关键技术点
-
Filmgrain.shader
cShader "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
csharpusing 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
csharpusing 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开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)