117 lines
4.4 KiB
C#
117 lines
4.4 KiB
C#
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
/**
|
|
* https://www.febucci.com/2022/05/custom-post-processing-in-urp/
|
|
*
|
|
*/
|
|
|
|
namespace Shaders
|
|
{
|
|
[System.Serializable]
|
|
public class CustomPostProcessPass : ScriptableRenderPass
|
|
{
|
|
// Used to render from camera to post processings
|
|
// back and forth, until we render the final image to
|
|
// the camera
|
|
RenderTargetIdentifier source;
|
|
RenderTargetIdentifier destinationA;
|
|
RenderTargetIdentifier destinationB;
|
|
RenderTargetIdentifier latestDest;
|
|
|
|
readonly int temporaryRTIdA = Shader.PropertyToID("_TempRT");
|
|
readonly int temporaryRTIdB = Shader.PropertyToID("_TempRTB");
|
|
|
|
public CustomPostProcessPass()
|
|
{
|
|
// Set the render pass event
|
|
renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
|
|
}
|
|
|
|
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
|
|
{
|
|
// Grab the camera target descriptor. We will use this when creating a temporary render texture.
|
|
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
|
|
descriptor.depthBufferBits = 0;
|
|
|
|
var renderer = renderingData.cameraData.renderer;
|
|
source = renderer.cameraColorTarget;
|
|
|
|
// Create a temporary render texture using the descriptor from above.
|
|
cmd.GetTemporaryRT(temporaryRTIdA , descriptor, FilterMode.Bilinear);
|
|
destinationA = new RenderTargetIdentifier(temporaryRTIdA);
|
|
cmd.GetTemporaryRT(temporaryRTIdB , descriptor, FilterMode.Bilinear);
|
|
destinationB = new RenderTargetIdentifier(temporaryRTIdB);
|
|
}
|
|
|
|
// The actual execution of the pass. This is where custom rendering occurs.
|
|
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
|
|
{
|
|
// Skipping post processing rendering inside the scene View
|
|
if(renderingData.cameraData.isSceneViewCamera)
|
|
return;
|
|
|
|
// Here you get your materials from your custom class
|
|
// (It's up to you! But here is how I did it)
|
|
var materials = CustomPostProcessingMaterials.Instance;
|
|
if (materials == null)
|
|
{
|
|
Debug.LogError("Custom Post Processing Materials instance is null");
|
|
return;
|
|
}
|
|
|
|
CommandBuffer cmd = CommandBufferPool.Get("Custom Post Processing");
|
|
cmd.Clear();
|
|
|
|
// This holds all the current Volumes information
|
|
// which we will need later
|
|
var stack = VolumeManager.instance.stack;
|
|
|
|
#region Local Methods
|
|
|
|
// Swaps render destinations back and forth, so that
|
|
// we can have multiple passes and similar with only a few textures
|
|
void BlitTo(Material mat, int pass = 0)
|
|
{
|
|
var first = latestDest;
|
|
var last = first == destinationA ? destinationB : destinationA;
|
|
Blit(cmd, first, last, mat, pass);
|
|
|
|
latestDest = last;
|
|
}
|
|
|
|
#endregion
|
|
|
|
// Starts with the camera source
|
|
latestDest = source;
|
|
|
|
//---Custom effect here---
|
|
var customEffect = stack.GetComponent<CustomEffectComponent>();
|
|
// Only process if the effect is active
|
|
if (customEffect.IsActive())
|
|
{
|
|
var customMaterial = materials.customEffect;
|
|
// P.s. optimize by caching the property ID somewhere else
|
|
customMaterial.SetFloat(Shader.PropertyToID("_Intensity"), customEffect.intensity.value);
|
|
|
|
BlitTo(customMaterial);
|
|
}
|
|
|
|
// Add any other custom effect/component you want, in your preferred order
|
|
// Custom effect 2, 3 , ...
|
|
|
|
// DONE! Now that we have processed all our custom effects, applies the final result to camera
|
|
Blit(cmd, latestDest, source);
|
|
|
|
context.ExecuteCommandBuffer(cmd);
|
|
CommandBufferPool.Release(cmd);
|
|
}
|
|
|
|
//Cleans the temporary RTs when we don't need them anymore
|
|
public override void OnCameraCleanup(CommandBuffer cmd)
|
|
{
|
|
cmd.ReleaseTemporaryRT(temporaryRTIdA);
|
|
cmd.ReleaseTemporaryRT(temporaryRTIdB);
|
|
}
|
|
}
|
|
} |