본문 바로가기
유니티/셰이더 그래프 포스트프로세스

Unity 2021에서 Add Renderer Feature에서 Blit 적용을 통한 셰이더그래프를 통한 포스트포로세스 흉내 내보기 + 간단한 예제 사용법

by NGVI 2021. 5. 4.

Unity 2021에서 Add Renderer Feature에서 Blit 적용을 통한 셰이더그래프를 통한 포스트프로세스 흉내 내보기 + 간단한 예제 사용법

셰이더 그래프를 만지작 거리다 보니,

 

후처리, 포스트 프로세스에서도 쓸 수 있을까란 의문이 생겼고,

 

또 자료를 이것저것 찾아보았다.

 

유튜브를 이것저것 뒤지도 보면 되어 보인다.

 

아래 영상들을 보면, 한글 버전이라 가져와 보았다.

오 포스트 프로세싱 노 코딩으로 되는건가?

위의 영상을 보실 필요는 없다. 

결론적으로 2021에서는 저렇게 안된다.

 

특정 기능이 빠져있기 때문에, 이 글에서 살리는 법을 적을 예정인 것이고,

 

뭐가 안되냐면

랜더러에 add 설정

Renderer에서 Renderer Features에서 + 시킬 때

과거 버전(정확히 어디까지 있는 건지 모르겠다.)에서는 Blit로 추가가 가능한데

 

2021에서는 해당 기능이 존재하지 않는다.

 

아마 동일한 아픔을 겪으시는 분들이 있을 거라 생각된다.

 

그래서 구글님께 좀 물어보면, 그거 빠졌다. 과거 버전에서 가져와서 쓰거나, 만들어 써야 한다라고 답변이 나온다.

 

찾아본 것 중 하나가 아래 질문

forum.unity.com/threads/2019-1-5-f1-lwrp-5-16-no-blit-renderer-feature.694264/

 

2019.1.5.f1 LWRP 5.16 - No Blit renderer feature

There is no blit renderer feature included in my project, I have only "Render Objects (Experimental)". Is this a separate download. If so, where is it...

forum.unity.com

역시 보실 필요는 없음..

 

그래서 선택한 건 과거 프로젝트 중에서 Blit 구현된 것을 찾는 것이었다.

인터넷을 검색하면 몇 개가 나온다.

 

그중 성공적으로 사용된 걸 공유한다.

 

BattleDawnNZ/Image-Effects-with-Shadergraph

creating image effect shaders with shadergraph. Contribute to BattleDawnNZ/Image-Effects-with-Shadergraph development by creating an account on GitHub.

github.com

해당 파일을 당신의 프로젝트에 담으면 당신도 Blit를 사용할수 있다.

 

혹시라도 파일이 삭제됐을 수도 있으니, 코드를 남겨둔다.

 

a

using System.Collections.Generic;
using UnityEngine.Serialization;

namespace UnityEngine.Rendering.LWRP {
    public class Blit : UnityEngine.Rendering.Universal.ScriptableRendererFeature {
        [System.Serializable]
        public class BlitSettings {
            public UnityEngine.Rendering.Universal.RenderPassEvent Event = UnityEngine.Rendering.Universal.RenderPassEvent.AfterRenderingOpaques;

            public Material blitMaterial = null;
            public int blitMaterialPassIndex = -1;
            public Target destination = Target.Color;
            public string textureId = "_BlitPassTexture";
        }

        public enum Target {
            Color,
            Texture
        }

        public BlitSettings settings = new BlitSettings ();
        UnityEngine.Rendering.Universal.RenderTargetHandle m_RenderTextureHandle;

        BlitPass blitPass;

        public override void Create () {
            var passIndex = settings.blitMaterial != null ? settings.blitMaterial.passCount - 1 : 1;
            settings.blitMaterialPassIndex = Mathf.Clamp (settings.blitMaterialPassIndex, -1, passIndex);
            blitPass = new BlitPass (settings.Event, settings.blitMaterial, settings.blitMaterialPassIndex, name);
            m_RenderTextureHandle.Init (settings.textureId);
        }

        public override void AddRenderPasses (UnityEngine.Rendering.Universal.ScriptableRenderer renderer, ref UnityEngine.Rendering.Universal.RenderingData renderingData) {
            var src = renderer.cameraColorTarget;
            var dest = (settings.destination == Target.Color) ? UnityEngine.Rendering.Universal.RenderTargetHandle.CameraTarget : m_RenderTextureHandle;

            if (settings.blitMaterial == null) {
                Debug.LogWarningFormat ("Missing Blit Material. {0} blit pass will not execute. Check for missing reference in the assigned renderer.", GetType ().Name);
                return;
            }

            blitPass.Setup (src, dest);
            renderer.EnqueuePass (blitPass);
        }
    }
}

 

b

namespace UnityEngine.Rendering.LWRP {
    /// <summary>
    /// Copy the given color buffer to the given destination color buffer.
    ///
    /// You can use this pass to copy a color buffer to the destination,
    /// so you can use it later in rendering. For example, you can copy
    /// the opaque texture to use it for distortion effects.
    /// </summary>
    internal class BlitPass : UnityEngine.Rendering.Universal.ScriptableRenderPass {
        public enum RenderTarget {
            Color,
            RenderTexture,
        }

        public Material blitMaterial = null;
        public int blitShaderPassIndex = 0;
        public FilterMode filterMode { get; set; }

        private RenderTargetIdentifier source { get; set; }
        private UnityEngine.Rendering.Universal.RenderTargetHandle destination { get; set; }

        UnityEngine.Rendering.Universal.RenderTargetHandle m_TemporaryColorTexture;
        string m_ProfilerTag;

        /// <summary>
        /// Create the CopyColorPass
        /// </summary>
        public BlitPass (UnityEngine.Rendering.Universal.RenderPassEvent renderPassEvent, Material blitMaterial, int blitShaderPassIndex, string tag) {
            this.renderPassEvent = renderPassEvent;
            this.blitMaterial = blitMaterial;
            this.blitShaderPassIndex = blitShaderPassIndex;
            m_ProfilerTag = tag;
            m_TemporaryColorTexture.Init ("_TemporaryColorTexture");
        }

        /// <summary>
        /// Configure the pass with the source and destination to execute on.
        /// </summary>
        /// <param name="source">Source Render Target</param>
        /// <param name="destination">Destination Render Target</param>
        public void Setup (RenderTargetIdentifier source, UnityEngine.Rendering.Universal.RenderTargetHandle destination) {
            this.source = source;
            this.destination = destination;
        }

        /// <inheritdoc/>
        public override void Execute (ScriptableRenderContext context, ref UnityEngine.Rendering.Universal.RenderingData renderingData) {
            CommandBuffer cmd = CommandBufferPool.Get (m_ProfilerTag);

            RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
            opaqueDesc.depthBufferBits = 0;

            // Can't read and write to same color target, create a temp render target to blit. 
            if (destination == UnityEngine.Rendering.Universal.RenderTargetHandle.CameraTarget) {
                cmd.GetTemporaryRT (m_TemporaryColorTexture.id, opaqueDesc, filterMode);
                Blit (cmd, source, m_TemporaryColorTexture.Identifier (), blitMaterial, blitShaderPassIndex);
                Blit (cmd, m_TemporaryColorTexture.Identifier (), source);
            } else {
                Blit (cmd, source, destination.Identifier (), blitMaterial, blitShaderPassIndex);
            }

            context.ExecuteCommandBuffer (cmd);
            CommandBufferPool.Release (cmd);
        }

        /// <inheritdoc/>
        public override void FrameCleanup (CommandBuffer cmd) {
            if (destination == UnityEngine.Rendering.Universal.RenderTargetHandle.CameraTarget)
                cmd.ReleaseTemporaryRT (m_TemporaryColorTexture.id);
        }
    }
}

 

2021 프로젝트에 넣은 뒤, 당신이 사용하는 랜더러에서 Add Render Feature를 시도해보면,

Blit가 추가됨

Blit가 추가됐음을 알 수 있다.

 

이로써 셰이더 그래프를 통해 포스트 프로세싱 흉내를 내볼 수 있게 된 것 디이다.

 

위에 Test를 간단하게 셰이더 그래프를 통한 후처리를 연결해본 것이다.

 

머티리얼에는 내가 제작한 셰이더 그래프 파일이 연결되어 있다.

 

간단하게나마 소개를 해보겠다.

 

후처리 화면 출력(화면 그대로 출력해보기) 노드 구성

택스쳐를 그대로 출력시킨다.

Base라는 속성의 텍스처가 화면을 담고 있다.

 

후처리에서는 화면 텍스처를 쓸려면 약속이 있다. 

 

Base 노드의 구성을 아래와 같이 해야 한다.

Reference확인

이름이 같아야 동작이 보장된다.

 

그리고 우리의 게임 화면을 보면 뭐 달라진 게 없다.

화면을 그대로 출력한 것이니...

 

정말 되는지 보기 위해서 변화되는 칼라를 lerp 시켜보도록 하자.

노드 구성

적당히 칼라를 lerp해봄

실행결과

 

흐음 된다.

왜 2021에는 사라진 기능인지

불안하지만, 일단은 해볼 수 있는 단계까지는 부활시켜 보았다.

 

뭔가 셰이더 그래프를 통해 후처리 비슷한걸 간단히 해볼 수 있는 환경이 되었다.

 

혹시 같은 문제가 있으신 분들께 도움이 되었으면 합니다.

 

감사합니다.

댓글