0
\$\begingroup\$

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
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.