Unity无能狂怒效果-游戏打击感-径向模糊-HDRP设定

Unity无能狂怒效果-游戏打击感-径向模糊-HDRP设定

功能描述

径向模糊在游戏中主要可以用来描述速度感,比如无能狂怒效果,振刀效果,或者瞬移

都可以用 径向模糊 组合 摄像机震荡 来提升 打击感 , 震撼画面感

大部分主流AAA游戏都有这样的效果

黑神话悟空片段效果

实现原理

第一步:确定径向模糊采样中心点,一般取图像中心点

第二步:计算采样像素与中心点距离

第三步:将采样点颜色值加权求和

第四步:与原图像像素做差值运算合成

uv采样求和加权

HDRP渲染设定

我们主要通过PostProcessing像素后处理来实现.

添加一个shader

Shader "Hidden/Shader/RadialBlur"
    HLSLINCLUDE
    #pragma target 4.5
    #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
    #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/FXAA.hlsl"
    #include "Packages/com.unity.render-pipelines.high-definition/Runtime/PostProcessing/Shaders/RTUpscale.hlsl"
    struct Attributes
        uint vertexID : SV_VertexID;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    struct Varyings
        float4 positionCS : SV_POSITION;
        float2 texcoord   : TEXCOORD0;
        UNITY_VERTEX_OUTPUT_STEREO
    Varyings Vert(Attributes input)
        Varyings output;
        UNITY_SETUP_INSTANCE_ID(input);
        UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
        output.positionCS = GetFullScreenTriangleVertexPosition(input.vertexID);
        output.texcoord = GetFullScreenTriangleTexCoord(input.vertexID);
        return output;
    float _Intensity;	// 强度
    float _SampleCount;	// 采样次数
    TEXTURE2D_X(_InputTexture);
    float4 CustomPostProcess(Varyings input) : SV_Target
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
        half3 col = 0;
        // uv到中心点距离
        half2 symmetryUv = input.texcoord - 0.5;
        half distance = length(symmetryUv);
        half factor = _Intensity / _SampleCount * distance;
        for(int i = 0; i < _SampleCount; i++)
            half uvOffset = 1 - factor * i;
            half2 uv = symmetryUv * uvOffset + 0.5;
            uint2 positionSS = uv * _ScreenSize.xy;
	    // 加权求和
            col += LOAD_TEXTURE2D_X(_InputTexture, positionSS).rgb;
        // 除于采样次数得到最终值
        col /= _SampleCount;
        return float4(col, 1);
    ENDHLSL
    SubShader
            Name "RadialBlur"
            ZWrite Off
            ZTest Always
            Blend Off
            Cull Off
            HLSLPROGRAM
                #pragma fragment CustomPostProcess
                #pragma vertex Vert
            ENDHLSL
    Fallback Off

c#代码

using System;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
[Serializable]
[VolumeComponentMenu("Post-processing/Custom/RadialBlur")]
public sealed class RadialBlur : CustomPostProcessVolumeComponent, IPostProcessComponent
    private const string ShaderName = "Hidden/Shader/RadialBlur";
    private static readonly int Intensity = Shader.PropertyToID("_Intensity");
    private static readonly int SampleCount = Shader.PropertyToID("_SampleCount");
    private static readonly int InputTexture = Shader.PropertyToID("_InputTexture");
    public ClampedFloatParameter intensity = new ClampedFloatParameter(0f, 0f, 1f);
    public ClampedIntParameter sampleCount = new ClampedIntParameter(8, 4, 16);
    private Material _material;
    public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.AfterPostProcess;
    public bool IsActive()
        return _material != null && intensity.value > 0f;
    public override void Setup()
        if (Shader.Find(ShaderName) != null)
            _material = new Material(Shader.Find(ShaderName));
            Debug.LogError($"Unable to find shader '{ShaderName}'. Post Process Volume RadialBlur is unable to load.");
    public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
        if (_material == null)
            return;
        _material.SetFloat(Intensity, intensity.value);
        _material.SetFloat(SampleCount, sampleCount.value);
        _material.SetTexture(InputTexture, source);
        HDUtils.DrawFullScreen(cmd, _material, destination);
    public override void Cleanup()
        CoreUtils.Destroy(_material);
}

Project setting设置

添加自定义后处理,加入我们写的后处理

设置自定义处理程序

在游戏中动态控制

关联好本地的volume,通过VolumeComponent获取到参数,并在游戏中进行控制

关联好本地的volume
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class VolumeManager1 : MonoBehaviour
    [SerializeField] private Volume volume;         // 关联当前的volume
    public static VolumeManager1 Instance { get; private set; }
    private FloatParameter vp;  // 当前参数
    private void Awake()
        Instance = this;
    void Start()
        List<VolumeComponent> list=volume.profile.components;
        // 获取第一个float参数
        vp = (FloatParameter)list[0].parameters[0];
    /// <summary>
    /// 径向模糊控制
    /// </summary>
    /// <param name="From">初始值</param>
    /// <param name="To">目标值</param>
    /// <param name="Duration">时间</param>
    /// <param name="StartDelay">延迟</param>
   public void DoRadialBlur(float From, float To, float Duration, float StartDelay)
       StartCoroutine(FadeCoroutine(From,To,Duration,StartDelay));
    IEnumerator FadeCoroutine(float From, float To, float Duration, float StartDelay)
        if (StartDelay>0)
            yield return new WaitForSeconds(StartDelay);
        float t=0;
        while(t<1)
            float v = Mathf.Lerp (From, To, t);