迎脾 发表于 2025-11-6 10:45:01

【URP】Unity[后处理]胶片颗粒FilmGrain

【从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;


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() {
      // 初始化代码...
    }
}
参数详解与用例

参数类型说明典型用例TypeEnum预设颗粒类型(Kodak200/400等)选择Agfa400模拟16mm胶片Intensity0-1颗粒可见度0.3-0.5用于复古RPG游戏Response0-1亮度响应曲线0.7使亮部颗粒减弱Texture2D自定义噪点贴图制作数字故障艺术效果操作步骤(URP 2022.1+)


[*]创建Volume对象:GameObject > Volume
[*]添加Film Grain覆盖:Add Override > Film Grain
[*]配置参数示例:
Type = Kodak500T
Intensity = 0.4
Response = 0.65

性能优化建议


[*]移动端使用Quarter分辨率
[*]动态调整Intensity(剧情过场时增强)
[*]禁用非必要时的Volume更新
<blockquote>
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

晦险忿 发表于 2025-11-18 14:20:37

谢谢分享,试用一下

赘暨逢 发表于 2025-11-27 04:52:11

过来提前占个楼

饮邺谲 发表于 前天 09:21

谢谢分享,辛苦了

骆贵 发表于 前天 16:07

感谢发布原创作品,程序园因你更精彩
页: [1]
查看完整版本: 【URP】Unity[后处理]胶片颗粒FilmGrain