I'm working on an outline effect for my game. I want to do the render buffer based methods since the outlines are imo of much higher quality. I can render the selected objects into the buffer as expected. I now need to use that render texture in the next stage .... however, I can't find a way to bind the temporary texture generated by the previous stage to the next step. The post processing effect is a work in progress, so I know it is not done yet. Want to visualize each step to make sure it works as expected.
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering.HighDefinition;
[Serializable, VolumeComponentMenu("Post-processing/Custom/JumpFloodOutline")]
public sealed class JumpFloodOutline : CustomPostProcessVolumeComponent, IPostProcessComponent
{
[Tooltip("Controls the thickness of the outline")]
public ClampedFloatParameter Thickness = new ClampedFloatParameter(4.0f,0.0f,50.0f);
[ColorUsage(true,true)]
[Tooltip("Outline color")]
public ColorParameter OutlineColor = new ColorParameter(Color.white,true,true,true);
private Material m_FlatRender;
//private Material m_BlurRender;
private Material m_MergeOutline;
private int silhouetteBufferID = Shader.PropertyToID("_SilhouetteBuffer");
private int inputTextureID = Shader.PropertyToID("_InputTexture");
private int colorID = Shader.PropertyToID("_Color");
public bool IsActive()
{
return m_FlatRender != null && OutlineObjects.Count > 0 && Thickness.value > 0f && OutlineColor.value.a > 0.0f;
}
// Do not forget to add this post process in the Custom Post Process Orders list (Project Settings > HDRP Default Settings).
public override CustomPostProcessInjectionPoint injectionPoint => CustomPostProcessInjectionPoint.BeforeTAA;
const string kBlurShader = "Hidden/Shader/Blur";
const string kFlatShader = "Hidden/Shader/FlatRender";
const string kMergeShader = "Hidden/Shader/MergeOutline";
public static List<OutlineObject> OutlineObjects = new List<OutlineObject>();
private Material LoadMaterial(string shaderName)
{
var shader = Shader.Find(shaderName);
if (shader != null)
{
return new Material(shader);
}
else
{
Debug.LogError($"Unable to find shader '{shaderName}'. Post Process Volume JumpFloodOutline is unable to load.");
return null;
}
}
public override void Setup()
{
m_FlatRender = LoadMaterial(kFlatShader);
m_MergeOutline = LoadMaterial(kMergeShader);
}
public override void Render(CommandBuffer cmd, HDCamera camera, RTHandle source, RTHandle destination)
{
RenderTextureDescriptor silhouetteRTD = new RenderTextureDescriptor()
{
dimension = TextureDimension.Tex2D,
width = camera.actualWidth,
height = camera.actualHeight,
depthBufferBits = 8,
volumeDepth = 1,
msaaSamples = 1,
useMipMap = false,
autoGenerateMips = false,
colorFormat = RenderTextureFormat.ARGB32
};
RenderTexture silhouetteTexture = RenderTexture.GetTemporary(silhouetteRTD);
silhouetteTexture.Create();
//cmd.GetTemporaryRT(silhouetteBufferID, silhouetteRTD);
cmd.SetRenderTarget(silhouetteTexture);
//cmd.SetRenderTarget(silhouetteTexture);
cmd.ClearRenderTarget(false, true, Color.clear);
m_FlatRender.SetColor(colorID, OutlineColor.value);
for (int i = 0; i < OutlineObjects.Count; i++)
{
var obj = OutlineObjects[i];
if (GeometryUtility.TestPlanesAABB(camera.frustum.planes, obj.Renderer.bounds))
{
for (int m = 0; m < obj.Mesh.subMeshCount; m++)
{
cmd.DrawRenderer(obj.Renderer, m_FlatRender, m);
}
}
}
cmd.SetRenderTarget(destination);
m_MergeOutline.SetTexture("_InputTexture", source);
m_MergeOutline.SetTexture("_OutlineTexture", silhouetteTexture);
HDUtils.DrawFullScreen(cmd, m_MergeOutline, destination);
cmd.ReleaseTemporaryRT(silhouetteBufferID);
RenderTexture.ReleaseTemporary(silhouetteTexture);
}
public override void Cleanup()
{
CoreUtils.Destroy(m_FlatRender);
CoreUtils.Destroy(m_MergeOutline);
}
}
Merge Shader
Shader "Hidden/Shader/MergeOutline"
{
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;
}
// List of properties to control your post process effect
TEXTURE2D_X(_InputTexture);
TEXTURE2D_X(_OutlineTexture);
float4 CustomPostProcess(Varyings input) : SV_Target
{
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
uint2 positionSS = input.texcoord * _ScreenSize.xy;
float3 sourceColor = LOAD_TEXTURE2D_X(_InputTexture, positionSS).rgb;
float4 outlineColor = LOAD_TEXTURE2D_X(_OutlineTexture, positionSS);
float3 output = lerp(sourceColor,outlineColor.rgb, outlineColor.a);
return float4(output,1);
}
ENDHLSL
SubShader
{
Pass
{
Name "MergeOutline"
ZWrite Off
ZTest Always
Blend Off
Cull Off
HLSLPROGRAM
#pragma fragment CustomPostProcess
#pragma vertex Vert
ENDHLSL
}
}
Fallback Off
}