Skip to content

Instantly share code, notes, and snippets.

@aefreedman
Created December 3, 2021 23:01
Show Gist options
  • Save aefreedman/09f0375f1c10e2e2ed012250de63701d to your computer and use it in GitHub Desktop.
Save aefreedman/09f0375f1c10e2e2ed012250de63701d to your computer and use it in GitHub Desktop.
//Calico post processing with stencil mask
// https://twitter.com/CalicoGame/status/1121221295536951296
using System;
using UnityEngine;
using UnityEngine.Rendering;
[ExecuteInEditMode, ImageEffectAllowedInSceneView]
public class ScreenMaterialCommandBuffer : MonoBehaviour
{
public enum Mode
{
Stencil,
RenderTexture
}
public Mode RenderMode;
public DepthTextureMode DepthMode = DepthTextureMode.None;
//AfterForwardAlpha will work for most effects
public CameraEvent RenderOrder = CameraEvent.AfterForwardAlpha;
public Material EffectMaterial;
private CameraEvent _cameraEvent;
private CommandBuffer _commandBuffer;
// [SerializeField]
private string GlobalRenderTextureName = "_MappedNoise";
private int _globalRenderTextureName;
private Camera _camera;
private Camera Camera
{
get
{
if (_camera == null)
_camera = GetComponent<Camera>();
return _camera;
}
}
//Update settings when edited
private void OnValidate()
{
_globalRenderTextureName = Shader.PropertyToID(GlobalRenderTextureName);
Camera.depthTextureMode = DepthMode;
if (RenderOrder != _cameraEvent && _commandBuffer != null)
{
Camera.RemoveCommandBuffer(_cameraEvent, _commandBuffer);
Camera.AddCommandBuffer(RenderOrder, _commandBuffer);
_cameraEvent = RenderOrder;
}
else if (RenderOrder != _cameraEvent && EffectMaterial != null)
{
OnEnable();
}
}
private void BlitMaterialToRenderTexture()
{
if (_commandBuffer != null || EffectMaterial == null)
return;
var _previousTarget = BuiltinRenderTextureType.CurrentActive;
_commandBuffer = new CommandBuffer { name = "Blit Material to Render Texture" };
var downsampler = (int) Mathf.Pow(2, 1);
var tempRenderTexture = Shader.PropertyToID("_tempRenderTex");
_commandBuffer.GetTemporaryRT(tempRenderTexture, _camera.pixelWidth / downsampler, _camera.pixelHeight / downsampler, 0);
_commandBuffer.SetRenderTarget(tempRenderTexture);
_commandBuffer.ClearRenderTarget(true, true, Color.clear, 1f);
// _commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, tempRenderTexture);
// _commandBuffer.SetGlobalTexture("_MainTex", tempRenderTexture);
_commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, tempRenderTexture, EffectMaterial);
_commandBuffer.SetGlobalTexture(GlobalRenderTextureName, tempRenderTexture);
_commandBuffer.SetRenderTarget(_previousTarget);
// _commandBuffer.Blit(_globalRenderTex, BuiltinRenderTextureType.CameraTarget);
Camera.AddCommandBuffer(RenderOrder, _commandBuffer);
}
private void OnEnable()
{
switch (RenderMode)
{
case Mode.Stencil:
BlitMaterialToCameraTarget();
break;
case Mode.RenderTexture:
BlitMaterialToRenderTexture();
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private void BlitMaterialToCameraTarget()
{
if (_commandBuffer != null || EffectMaterial == null)
return;
_commandBuffer = new CommandBuffer { name = "Blit with Replacement Material" };
// 1: Get a render texture by the name defined in the inspector at screen size and clear it
var tempRenderTexture = Shader.PropertyToID("_tempRenderTex");
_commandBuffer.GetTemporaryRT(tempRenderTexture, -1, -1, 0);
_commandBuffer.SetRenderTarget(tempRenderTexture, tempRenderTexture);
_commandBuffer.ClearRenderTarget(true, true, Color.clear);
// 2: Blit the camera target into the temporary render texture
_commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, tempRenderTexture);
// 3: Active render target is now tempRenderTexture
// 4: Set _MainTex as the temporary render texture
_commandBuffer.SetGlobalTexture("_MainTex", tempRenderTexture);
// 5: Blit the camera target again, but this time using a replacement material
_commandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, BuiltinRenderTextureType.CameraTarget, EffectMaterial);
Camera.AddCommandBuffer(RenderOrder, _commandBuffer);
}
private void OnDisable()
{
if (_commandBuffer == null)
return;
Camera.RemoveCommandBuffer(RenderOrder, _commandBuffer);
_commandBuffer = null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment