PostProcessing Stackのカスタムエフェクトで解像度を下げる (ダウンサンプリングする) 方法

f:id:ssr_maguro:20191120174741g:plain

参考にしたソース https://github.com/Unity-Technologies/PostProcessing/blob/v2/PostProcessing/Runtime/Effects/ScalableAO.cs

    // AO buffer
    var rtMask = ShaderIDs.OcclusionTexture1;
    int scaledWidth = context.width / ts;
    int scaledHeight = context.height / ts;
    context.GetScreenSpaceTemporaryRT(cmd, rtMask, 0, kFormat, kRWMode, kFilter, scaledWidth, scaledHeight);

ここらへん。

context.GetScreenSpaceTemporaryRT() などを使って、CommandBufferの操作が出来る。

解像度を下げるだけならshaderは不要で、下記で出来た。

    using System;
    using UnityEngine;
    using UnityEngine.Rendering.PostProcessing;
    
    namespace White
    {
        [Serializable]
        [PostProcess(typeof(DownSamplingRenderer), PostProcessEvent.AfterStack,
            "AAA/PostEffects/DownSamplilng", true)]
        public sealed class DownSampling : PostProcessEffectSettings
        {
            [Range(1f, 10f)] public FloatParameter downScale = new FloatParameter {value = 1f};
        }
    
        internal sealed class DownSamplingRenderer : PostProcessEffectRenderer<DownSampling>
        {
            public override void Render(PostProcessRenderContext context)
            {
                int scaledWidth = Mathf.RoundToInt(context.width / settings.downScale.value);
                int scaledHeight = Mathf.RoundToInt(context.height / settings.downScale.value);
    
                int tempId1 = Shader.PropertyToID("_Temp1");
                context.GetScreenSpaceTemporaryRT(context.command, tempId1, 0, RenderTextureFormat.ARGB32,
                    RenderTextureReadWrite.Linear, FilterMode.Bilinear,
                    scaledWidth, scaledHeight);
    
                // 元画像をtempId1にコピー
                context.command.BuiltinBlit(context.source, tempId1);
                // tempId1を出力
                context.command.BuiltinBlit(tempId1, context.destination);
                context.command.ReleaseTemporaryRT(tempId1);
            }
        }
    }

CommandBufferと同じ。

GetScreenSpaceTemporaryRT() contextのものを使うのは何でか?

context.command.GetTemporaryRT() に置き換えて試したが、これでも同じ結果が得られる。

context.command.GetTemporaryRT(tempId1, scaledWidth, scaledHeight, 0, FilterMode.Bilinear, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);

GetScreenSpaceTemporaryRT()のソースを見ると、 #if UNITY_2017_2_OR_NEWER で処理を分岐させている。

BuiltinBlit()に関してもCommandBufferに実装された関数ではなく、PostProcessing.RuntimeUtilitiesで宣言されている拡張メソッド。

将来的に何かの処理が挟まる可能性もあるのでCommandBufferのメソッドをそのまま使うのは止めたほうが良さそうだ。

GetScreenSpaceTemporaryRT 等の詳しいapi documentはこちら。https://docs.unity3d.com/Packages/com.unity.postprocessing@2.2/api/UnityEngine.Rendering.PostProcessing.RuntimeUtilities.html?q=BlitFullscreenTriangle#UnityEngine_Rendering_PostProcessing_RuntimeUtilities_CopyTexture_CommandBuffer_RenderTargetIdentifier_RenderTargetIdentifier_