3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

シンプルなMRTのサンプル。

Last updated at Posted at 2020-06-19

散々ImageEffectを書いてきたわりに、
MRTについて触れていなかったので簡単なMRTのサンプルコードを置いておきます

今回のサンプルで必要なものは2つ。

  • カメラ用のスクリプト
    • 描画用のRenderTextureを作る(今回は4つ)
    • カメラの描画先をその4つのRenderTextureに設定する
    • 描画が終わったらメイン画像を、本来描画するはずだったフレームバッファにコピーする
  • MRT描画する用のシェーダ
    • MRTで4つの出力先を使用するので shader target 3.5を指定
    • FragmentShaderの出力先をSV_TargetからColor4つに変更
      • それ用の構造体を定義
      • 色の流し込み

まず、カメラに貼っ付けるコンポーネントのコードから。

MrtCamera.cs
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UI;

/// <summary>
/// MRTチェック用のカメラ
/// </summary>
[RequireComponent(typeof(Camera))]
public class MrtCamera : MonoBehaviour
{
    /// <summary>
    /// 出力先
    /// </summary>
    private RenderTexture _main;
    private RenderTexture _red;
    private RenderTexture _green;
    private RenderTexture _blue;

    /// <summary>
    /// 確認用
    /// </summary>
    [SerializeField]
    private RawImage[] _rawImages;

    private void Start()
    {
        
        
        var width = Screen.width;
        var height = Screen.height;
        
        //描画先作成(Mainだけ深度有り)
        _main = new RenderTexture(width, height, 24);
        _red = new RenderTexture(width, height, 0);
        _green = new RenderTexture(width, height, 0);
        _blue = new RenderTexture(width, height, 0);

        //描画先設定
        var cam = GetComponent<Camera>();
        cam.SetTargetBuffers(new []
        {
            _main.colorBuffer,
            _red.colorBuffer,
            _green.colorBuffer,
            _blue.colorBuffer
        }, _main.depthBuffer);

        //書き終わったmainをフレームバッファにコピーするコマンドを作成
        var commandBuffer = new CommandBuffer();
        var currentActiveRenderTargetIdentifier = new RenderTargetIdentifier(BuiltinRenderTextureType.CurrentActive);
        commandBuffer.SetRenderTarget (-1);
        commandBuffer.Blit(
            _main,
            currentActiveRenderTargetIdentifier);
        //全部終わった後でコマンド発行
        cam.AddCommandBuffer(CameraEvent.AfterEverything, commandBuffer );

        //確認用RawImageに貼り付ける
        _rawImages[0].texture = _main;
        _rawImages[1].texture = _red;
        _rawImages[2].texture = _green;
        _rawImages[3].texture = _blue;
    }
}

_rawImagesの辺りは確認する必要がなかったら除去して下さい。
念の為 SystemInfo.supportedRenderTargetCount でサポートしているRenderTarget数をチェックするとなお良いかと。


オブジェクトに貼り付けて複数の描画先に出力するシェーダはこちら。

MrtTest.shader
Shader "ScreenPocket/3d/MrtTest"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
            #pragma target 3.5

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };
            
            struct mrt
            {
                fixed4 color0 : COLOR0;
                fixed4 color1 : COLOR1;
                fixed4 color2 : COLOR2;
                fixed4 color3 : COLOR3;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            mrt frag (v2f i)
            {
                mrt o;
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                
                o.color0 = col;
                o.color1 = fixed4(col.r,0,0,1);
                o.color2 = fixed4(0,col.g,0,1);
                o.color3 = fixed4(0,0,col.b,1);
                
                return o;
            }
            ENDCG
        }
    }
}

Unlitシェーダの改変です。
ポイントは

mrt4: 複数のレンダーターゲット、少なくとも 4
一般に言う #pragma target ディレクティブは上の要件を簡略にしたものであり、以下に対応します。
3.5: 3.0 + interpolators15 + mrt4 + integers + 2darray + instancing

※なので#pragma require mrt4でも良いかも?

  • 出力用にstruct mrtを定義して、それをFragmentShaderの出力先に指定
  • o.color0〜3にそれぞれ色成分を出力

参考にしたサイトは下記
1つのカメラでMRT出力を用いたPostEffectを実現する
【Unity】カメラ1つでUI解像度を維持し、3D解像度だけを下げる方法

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?