之前实现了一个屏幕后处理高度雾,但这个是在Built-in管线下的。现在需要改成URP管线下,然后发现了改动量挺大的,原来的OnRenderImage、OnPreRender都失效了,所以记录一下。
具体代码如下:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
[System.Serializable, VolumeComponentMenu("zxz/HeightFog")]
public class HeightFogVolume : VolumeComponent, IPostProcessComponent
{
[Tooltip("雾强度")]
public ClampedFloatParameter FogDensity = new ClampedFloatParameter(1.0f, 0.0f,5f);
[Tooltip("雾的起始高度")]
public FloatParameter FogStart = new FloatParameter(0f);
[Tooltip("雾的终止高度")]
public FloatParameter FogEnd = new FloatParameter(2.0f);
[Tooltip("雾的颜色")]
public ColorParameter FogColor = new ColorParameter(new Color(130 / 255f, 130 / 255f, 130 / 255f, 1.0f));
[Tooltip("雾X方向流动速度")]
public ClampedFloatParameter FogXSpeed = new ClampedFloatParameter(0.05f, -0.5f, 0.5f);
[Tooltip("雾Z方向流动速度")]
public ClampedFloatParameter FogZSpeed = new ClampedFloatParameter(0.05f, -0.5f, 0.5f);
[Tooltip("雾噪声图权重")]
public ClampedFloatParameter NoiseWeight = new ClampedFloatParameter(1.0f, 0.0f, 3.0f);
[Tooltip("雾噪声图参数")]
public ClampedFloatParameter NoiseAmount = new ClampedFloatParameter(1.0f, 0.0f, 30.0f);
public bool IsActive() => true;
public bool IsTileCompatible() => false;
}
下面是核心代码:
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
public class HeightFogRenderFeature : ScriptableRendererFeature
{
[System.Serializable]
public class Settings
{
public RenderPassEvent renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
public Shader shader;
public Texture noise_tex;
}
public Settings settings = new Settings();
HeightFogPass pass;
public override void Create()
{
this.name = "HeightFogPass";
pass = new HeightFogPass(settings.renderPassEvent, settings.shader, settings.noise_tex);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
pass.Setup(renderer.cameraColorTarget);
renderer.EnqueuePass(pass);
}
}
public class HeightFogPass : ScriptableRenderPass
{
static readonly string k_RenderTag = "HeightFogPass Effects";
static readonly int MainTexId = Shader.PropertyToID("_MainTex");
static readonly int NoiseTexId = Shader.PropertyToID("_NoiseTex");
static readonly int TempTargetId = Shader.PropertyToID("_TempTarget");
static readonly int FogDensityId = Shader.PropertyToID("_FogDensity");
static readonly int FogStartId = Shader.PropertyToID("_FogStart");
static readonly int FogEndId = Shader.PropertyToID("_FogEnd");
static readonly int FogColorId = Shader.PropertyToID("_FogColor");
static readonly int FogXSpeedId = Shader.PropertyToID("_FogXSpeed");
static readonly int FogZSpeedId = Shader.PropertyToID("_FogYSpeed");
static readonly int NoiseWeightId = Shader.PropertyToID("_NoiseWeight");
static readonly int NoiseAmountId = Shader.PropertyToID("_NoiseAmount");
HeightFogVolume volume;
Material material;
Texture noise_tex;
RenderTargetIdentifier currentTarget;
public HeightFogPass(RenderPassEvent evt, Shader shader, Texture noise)
{
renderPassEvent = evt;
//var shader = Shader.Find("Universal Render Pipeline/Dejavu/HeightFog");
if (shader == null)
{
Debug.LogError("Shader not found.");
return;
}
material = CoreUtils.CreateEngineMaterial(shader);
noise_tex = noise;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
if (material == null)
{
Debug.LogError("Material not created.");
return;
}
if (!renderingData.cameraData.postProcessEnabled) return;
var stack = VolumeManager.instance.stack;
volume = stack.GetComponent<HeightFogVolume>();
if (volume == null) { return; }
if (!volume.IsActive()) { return; }
var cmd = CommandBufferPool.Get(k_RenderTag);
Render(cmd, ref renderingData);
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
public void Setup(in RenderTargetIdentifier currentTarget)
{
this.currentTarget = currentTarget;
}
void Render(CommandBuffer cmd, ref RenderingData renderingData)
{
ref var cameraData = ref renderingData.cameraData;
var source = currentTarget;
int destination = TempTargetId;
var w = cameraData.camera.scaledPixelWidth;
var h = cameraData.camera.scaledPixelHeight;
material.SetFloat(FogDensityId, volume.FogDensity.value);
material.SetFloat(FogStartId, volume.FogStart.value);
material.SetFloat(FogEndId, volume.FogEnd.value);
material.SetColor(FogColorId, volume.FogColor.value);
material.SetFloat(FogXSpeedId, volume.FogXSpeed.value);
material.SetFloat(FogZSpeedId, volume.FogZSpeed.value);
material.SetFloat(NoiseWeightId, volume.NoiseWeight.value);
material.SetFloat(NoiseAmountId, volume.NoiseAmount.value);
material.SetTexture(NoiseTexId, noise_tex);
int shaderPass = 0;
cmd.SetGlobalTexture(MainTexId, source);
cmd.GetTemporaryRT(destination, w, h, 0, FilterMode.Point, RenderTextureFormat.Default);
cmd.Blit(source, destination);
cmd.Blit(destination, source, material, shaderPass);
}
}
后处理的HLSL下的Shader代码:
Shader "URP/zxz/HeightFog"
{
Properties
{
_MainTex("Base (RGB)", 2D) = "white" {}
}
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
float4 _NoiseTex_ST;
half _FogDensity;
float _FogStart;
float _FogEnd;
half4 _FogColor;
half _FogXSpeed;
half _FogYSpeed;
half _NoiseWeight;
half _NoiseAmount;
CBUFFER_END
sampler2D _MainTex;
sampler2D _NoiseTex;
TEXTURE2D(_CameraDepthTexture);
SAMPLER(sampler_CameraDepthTexture);
struct appdata {
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct v2f {
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
float3 viewRayWorld : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
v2f vert(appdata v)
{
v2f o;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
o.positionCS = TransformObjectToHClip(v.positionOS.xyz);
float sceneRawDepth = 1;
#if defined(UNITY_REVERSED_Z)
sceneRawDepth = 1 - sceneRawDepth;
#endif
float3 worldPos = ComputeWorldSpacePosition(v.uv, sceneRawDepth, UNITY_MATRIX_I_VP);
o.viewRayWorld = worldPos - _WorldSpaceCameraPos.xyz;
o.uv = v.uv;
return o;
}
float4 frag(v2f i) : SV_Target
{
float sceneRawDepth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, i.uv);
float linear01Depth = Linear01Depth(sceneRawDepth, _ZBufferParams);
float3 worldPos = _WorldSpaceCameraPos.xyz + ( linear01Depth) * i.viewRayWorld;
float2 speed = _Time.y * float2(_FogXSpeed, _FogYSpeed);
float noise = (tex2D(_NoiseTex, worldPos.xz / _NoiseAmount + speed).r - 0.5) * _NoiseWeight;
float fogDensity = (_FogEnd - worldPos.y) / (_FogEnd - _FogStart);
fogDensity = saturate(fogDensity * _FogDensity * (1 + noise));
half4 finalColor = tex2D(_MainTex, i.uv);
//half4 finalColor = tex2D(_NoiseTex, i.uv);
finalColor.rgb = lerp(finalColor.rgb, _FogColor.rgb, fogDensity);
return finalColor;
}
ENDHLSL
SubShader
{
//Tags {"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
Tags{ "RenderPipeline" = "UniversalPipeline" "RenderType" = "Overlay" "Queue" = "Transparent-499" "DisableBatching" = "True" }
LOD 100
ZTest Always Cull Off ZWrite Off
Blend one zero
Pass
{
Name "HeightFog"
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
ENDHLSL
}
}
}
坑:
创建Demo项目时,用的是3D URP模板。结果配置好后发现没效果。折腾了一天!!!!!!!!!下班了才发现是用下面的模板就可以了。最后第二天发现问题所在:
如上图,需要选取Always选项。
参考文章:https://blog.csdn.net/yinfourever/article/details/121047957
github:https://github.com/982464509/URP-PostProcessingFog.git