Version: 2020.1
言語: 日本語
カスタムレンダーパイプラインでのレンダーパイプラインアセットとレンダーパイプラインインスタンスの作成
カメラ

カスタムレンダーパイプラインでのシンプルなレンダーループの作成

レンダーループとは、1 つのフレーム内で行われるすべてのレンダリング操作を意味します。このページでは、Unity のスクリプタブルレンダーパイプラインに基づいたカスタムレンダーパイプラインで、シンプルなレンダーループを作成する方法を説明します。

このページのコード例は、スクリプタブルレンダーパイプラインを使用する際の基本原則を示しています。この情報は、独自のカスタムスクリプタブルレンダーパイプラインを構築する際や、Unity にあらかじめ用意されているスクリプタブルレンダーパイプラインがどのように動作するかを理解するために利用できます。

プロジェクトの準備

レンダーループのコードを書き始める前に、プロジェクトの準備をする必要があります。

その手順は以下の通りです。

  1. Create an SRP-compatible Unity shader.
  2. レンダリングする 1 つまたは複数のゲームオブジェクトを作成 します。
  3. カスタム SRP の基本構造を作成 します。
  4. Optional: If you plan to extend your simple custom SRP to add more complex functionality, install the SRP Core package. The SRP Core package includes the SRP Core shader library (which you can use to make your Unity shaders SRP Batcher compatible), and utility functions for common operations. For more information, see the SRP Core package documentation.

Creating an SRP-compatible Unity shader

In the Scriptable Render Pipeline, you use the LightMode Pass tag in a Unity shader to determine how to draw geometry. For more information on assigning Pass tags to Unity shaders, see ShaderLab: assigning tags to a Pass.

This task shows you how to create a very simple unlit Unity shader with a LightMode Pass tag value of ExampleLightModeTag.

  1. Create a new Unity shader asset in your project. For instructions on creating a Unity shader asset, see Unity shader assets.
  2. In your Project view, double click the Unity shader asset to open the Unity shader source code in a text editor.
  3. Replace the existing shader code with the following:
// This is a simple unlit Unity shader that is compatible with a custom Scriptable Render Pipeline.
// It applies a hardcoded color, and demonstrates the use of the LightMode Pass tag.
// It is not compatible with SRP Batcher.

Shader "Examples/SimpleUnlitColor"
{
    SubShader
    {
        Pass
        {
            // The value of the LightMode Pass tag must match the ShaderTagId in ScriptableRenderContext.DrawRenderers
            Tags { "LightMode" = "ExampleLightModeTag"}

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

    float4x4 unity_MatrixVP;
            float4x4 unity_ObjectToWorld;

            struct Attributes
            {
                float4 positionOS   : POSITION;
            };

            struct Varyings
            {
                float4 positionCS : SV_POSITION;
            };

            Varyings vert (Attributes IN)
            {
                Varyings OUT;
                float4 worldPos = mul(unity_ObjectToWorld, IN.positionOS);
                OUT.positionCS = mul(unity_MatrixVP, worldPos);
                return OUT;
            }

            float4 frag (Varyings IN) : SV_TARGET
            {
                return float4(0.5,1,0.5,1);
            }
            ENDHLSL
        }
    }
}

レンダリングするゲームオブジェクトの作成

In order to test that your render loop works, you must create something to render. This task shows you how to put GameObjects in your scene that use the SRP-compatible Unity shader that you created in the previous task.

  1. Create a new material asset in your Unity project. For instructions on creating a material asset, see Materials.
  2. Assign the Unity shader to the material asset. For instructions on assigning a Unity shader to a material asset, see Materials.
  3. Create a cube in your scene. For instructions on creating a cube in your scene, see Primitive objects.
  4. Assign the material to it. For instructions on assigning a material to a GameObject, see Materials.

カスタム SRP の基本構造の作成

準備の最終段階では、カスタム SRP に必要な基本的なソースファイルを作成し、Unity にカスタム SRP を使ったレンダリングを開始するように指示します。

  1. レンダーパイプラインインスタンスとレンダーパイプラインアセットの作成 の手順に沿って、RenderPipeline を継承したクラスと互換性のあるレンダーパイプラインアセットを作成します。
  2. アクティブレンダーパイプラインアセットの設定 の指示に従って、アクティブなレンダーパイプラインアセットを設定します。Unity はカスタム SRP を使ってすぐにレンダリングを開始します。つまり、カスタム SRP にコードを加えるまでは、シーンビューとゲームビューは空白です。

レンダーループの作成

単純なレンダーループの基本的な操作は次のとおりです。

  • レンダーターゲットの消去。最後のフレームで描かれたジオメトリを削除します。
  • カリング。カメラに見えないジオメトリをフィルタリングします。
  • 描画。どのジオメトリを、どのように描画するかを GPU に指示します。

レンダーターゲットの消去

消去とは、最後のフレームで描画されたものを取り除くことです。レンダリングターゲットは通常スクリーンですが、テクスチャにレンダリングして「ピクチャーインピクチャー」効果を出すこともできます。これらの例では、Unity のデフォルト動作であるスクリーンへのレンダリング方法を示しています。

スクリプタブルレンダーパイプラインでレンダーターゲットを消去するには、以下を行います。

  1. CommandBufferClear コマンドで設定します。
  2. CommandBufferScriptableRenderContext のコマンドキューに加えます。これを行うには、ScriptableRenderContext.ExecuteCommandBuffer を呼び出します。
  3. グラフィックス API に ScriptableRenderContext のコマンドキューを実行するように指示します。これを行うには、ScriptableRenderContext.Submit を呼び出します。

他のスクリプタブルレンダーパイプラインの操作と同様に、このコードのエントリーポイントとして、RenderPipeline.Render メソッドを使用します。以下のサンプルコードは、その方法を示しています。

/* 
これは、カスタムのスクリプタブルレンダーパイプラインの簡略化された例です。
基本的なレンダーループがどのように機能するかを示しています。
最も効率的なランタイムパフォーマンスというよりは、最も明確なワークフローを示しています。
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // 現在のレンダーターゲットを消去するコマンドを作成してスケジューリングします
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // スケジュールされたすべてのコマンドを実行するようにグラフィックス API に指示します
        context.Submit();
    }
}

カリング

カリングとは、カメラに映らないジオメトリをフィルタリングする処理です。

スクリプタブルレンダーパイプラインでカリングを行うには、以下を行います。

  1. ScriptableCullingParameters 構造体にカメラに関するデータを収集します。これを行うには、Camera.TryGetCullingParameters を呼び出します。
  2. 任意: ScriptableCullingParameters 構造体の値を手動で更新します。
  3. ScriptableRenderContext.Cull を呼び出して、その結果を CullingResults 構造体に格納します。

このサンプルコードは、上の例を拡張したもので、レンダーターゲットをクリアしてからカリング操作を行う方法を示しています。

/* 
これは、カスタムのスクリプタブルレンダーパイプラインの簡略化された例です。
基本的なレンダーループがどのように機能するかを示しています。
最も効率的なランタイムパフォーマンスというよりは、最も明確なワークフローを示しています。
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // コマンドを作成してスケジューリングし、現在のレンダーターゲットを消去します。
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // すべてのカメラに繰り返します
        foreach (Camera camera in cameras)
        {
            // 使用しているカメラからカリングパラメーターを取得します。
            camera.TryGetCullingParameters(out var cullingParameters);

            // カリングパラメーターを使ってカリング操作を行い、結果を保存します。
            var cullingResults = context.Cull(ref cullingParameters);
        }

        // すべてのスケジュールされたコマンドを行うよう、グラフィックス API に指示します。
        context.Submit();
    }
}

描画

描画とは、指定した設定で指定した 1 組のジオメトリを描画するようにグラフィックス API に指示するプロセスです。

SRP で描画するには、以下を行います。

  1. 上述のようにカリング操作を実行し、その結果を CullingResults 構造体に格納します。
  2. FilteringSettings 構造体を作成して設定します。この構造体には、カリングの結果をフィルタリングする方法が記述されています。
  3. DrawingSettings 構造体を作成して設定します。この構造体には、どのジオメトリをどのように描画するかが記述されています。
  4. Optional: By default, Unity sets the render state based on the Unity shader. If you want to override the render state for some or all of the geometry that you are about to draw, you can use a RenderStateBlock struct to do this.
  5. ScriptableRenderContext.DrawRenderers を呼び出して、作成した構造体をパラメーターとして渡します。Unity は、設定に応じてフィルタリングされたジオメトリを描画します。

このサンプルコードでは、上の例を基に、レンダーターゲットの消去、カリング操作の実行、その結果のジオメトリの描画を行います。

/* 
これは、カスタムのスクリプタブルレンダーパイプラインの簡略化された例です。
これは、基本的なレンダーループがどのように機能するかを示しています。 最も効率的なランタイムパフォーマンスというよりは、最も明確なワークフローを示しています。
*/

using UnityEngine;
using UnityEngine.Rendering;

public class ExampleRenderPipeline : RenderPipeline {
    public ExampleRenderPipeline() {
    }

    protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
        // 現在のレンダーターゲットを消去するコマンドを作成してスケジューリングします
        var cmd = new CommandBuffer();
        cmd.ClearRenderTarget(true, true, Color.black);
        context.ExecuteCommandBuffer(cmd);
        cmd.Release();

        // すべてのカメラに繰り返します
        foreach (Camera camera in cameras)
        {
            // 現在のカメラからカリングパラメーターを取得します
            camera.TryGetCullingParameters(out var cullingParameters);

            // カリングパラメーターを使用してカリング操作を実行し、結果を保存します
            var cullingResults = context.Cull(ref cullingParameters);

            // 現在のカメラに基づいて、ビルトインのシェーダー変数の値を更新します
            context.SetupCameraProperties(camera);

            // LightMode パスタグの値に基づいて、 Unity に描画するジオメトリを指示します
            ShaderTagId shaderTagId = new ShaderTagId("ExampleLightModeTag");

            //現在のカメラに基づいて、Unity にジオメトリを並べ替える方法を指示します
            var sortingSettings = new SortingSettings(camera);

            // どのジオメトリを描画するかとその描画方法を説明する DrawingSettings 構造体を作成します
            DrawingSettings drawingSettings = new DrawingSettings(shaderTagId, sortingSettings);

            // カリング結果をフィルタリングする方法を Unity に指示し、描画するジオメトリをさらに指定します
            // FilteringSettings.defaultValue を使用して、フィルタリングなしを指定します
            FilteringSettings filteringSettings = FilteringSettings.defaultValue;
        
            // 定義した設定に基づいて、ジオメトリを描画するコマンドをスケジューリングします
            context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);

            // 必要に応じて、スカイボックスを描画するコマンドをスケジューリングします
            if (camera.clearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null)
            {
                context.DrawSkybox(camera);
            }

            // スケジュールされたすべてのコマンドを実行するようにグラフィックス API に指示します
            context.Submit();
        }
    }
}
カスタムレンダーパイプラインでのレンダーパイプラインアセットとレンダーパイプラインインスタンスの作成
カメラ