Scriptable Render Pipline入門

# 目的
SRPを1から触ってみたい！
URPやHDRPを読む足掛けがほしい！

なのでSRPで無から物体を簡単に描画するまで行っていきます

# Scriptable Render Piplineとは？
Unity2019からUnityのレンダリングパイプラインを開発者側でもいじれるように提供されている
URPやHDRPもSRPで記述されていて、ソースコードを閲覧することができる

具体的なSRP変更例は下記参照

https://learning.unity3d.jp/3284/

# SRPのサンプルを作ろう
## 検証環境
Unity 2019.4.16f1

## サンプルシーン
プロジェクト作成時に「UniversalRenderPipeline」で作成

シーンには透過と不透過を混ぜましょう
シェーダーは別途作成し、Tagsに `SRPDefaultUnlit` と指定しておいてください

![完成形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/9ba3dc5f-8f21-492e-a2c8-772b2f8baca0.png)

## 検証リポジトリ

https://github.com/tsune2ne/SRPSample_blog

## 自作のSRPを適用する
### 1.MyRenderPipelineAsset.cs作成

```c#
using UnityEngine;
using UnityEngine.Rendering;

namespace Assets.CustomRP.MyRP
{
	[CreateAssetMenu(menuName = "Rendering/MyRP")]
	public class MyRenderPipelineAsset : RenderPipelineAsset
	{
		protected override RenderPipeline CreatePipeline()
		{
			return new MyRenderPipeline();
		}
	}
}
```

### 2.MyRenderPipeline.cs作成
```c#
using UnityEngine;
using UnityEngine.Rendering;

namespace Assets.CustomRP.MyRP
{
    public class MyRenderPipeline : RenderPipeline
    {
        MyCameraRenderer renderer = new MyCameraRenderer();

        protected override void Render(ScriptableRenderContext context, Camera[] cameras)
        {
            foreach (Camera camera in cameras)
            {
                renderer.Render(context, camera);
            }
        }
    }
}
```

### 3.MyRenderPipelineAsset作成
Projectビュー -> Create -> Rendering -> MyRenderPipelineAsset

ProjectにMyRenderPipelineAsset.assetが作成されます

### 4.RenderingをMyRenderPipelineAssetに変更
Project Settings -> Quality -> Rendering を ExampleRenderPipelineAsset に変更

これでSceneビューになにも映らなくなりますが、これが正解です
レンダリング処理が何もかかれていないのでなにも映りません

![無.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/c3313286-e99c-401e-49f9-0e8c6f60d7c4.png)


## Skyboxを描写
ではまずSkyboxを描画します

```c#
	public void Render (ScriptableRenderContext context, Camera camera) {
		this.context = context;
		this.camera = camera;

		DrawVisibleGeometry();
		Submit();
	}

	void Submit () {
		context.Submit();
	}
```

![Skybox.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/a0311e94-b292-7d42-6068-d2352964fa5a.png)

空が映りました🎉

## カメラ設定を受け取る
カメラを回転するとわかりますが、カメラのアングルが適用されません
適用していきましょう

```c#
	public void Render (ScriptableRenderContext context, Camera camera) {
		this.context = context;
		this.camera = camera;

		Setup();
		DrawVisibleGeometry();
		Submit();
	}

	void Setup () {
		context.SetupCameraProperties(camera);
	}
```

![Skybox2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/bfd183f4-be0a-735d-2af8-0bf07a510f2d.png)

これでカメラアングルが反映されました🎉

## カリング
オブジェクトを映していきたいところですが、
先にカメラから見える範囲のオブジェクトを取得しましょう
描画候補を `cullingResults` に格納します

```c#
        CullingResults cullingResults;

        public void Render (ScriptableRenderContext context, Camera camera) {
                this.context = context;
                this.camera = camera;

                if (!Cull()) {
                        return;
                }

                Setup();
                DrawVisibleGeometry();
                Submit();
        }
        
        bool Cull () {
                if (camera.TryGetCullingParameters(out ScriptableCullingParameters p)) {
                        cullingResults = context.Cull(ref p);
                        return true;
                }
                return false;
        }
```


## オブジェクトを映す
オブジェクトを描写します。
ここではTagIDが `SRPDefaultUnlit` を対象とします

```c#
        static ShaderTagId unlitShaderTagId = new ShaderTagId("SRPDefaultUnlit");

        void DrawVisibleGeometry () {
                var sortingSettings = new SortingSettings(camera);
                var drawingSettings = new DrawingSettings(
                        unlitShaderTagId, sortingSettings
                );
                var filteringSettings = new FilteringSettings(RenderQueueRange.all);

                context.DrawRenderers(
                        cullingResults, ref drawingSettings, ref filteringSettings
                );

                context.DrawSkybox(camera);
        }
```

![UnLit+Lit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/773224e8-32d7-09c4-0418-8d975820ddb9.png)

見えました🎉

## 透過オブジェクトの描画タイミングを移動
不透過オブジェクトをズームアップすると変なことに気づきます
透過オブジェクトの後ろにSkyboxが描写されていません

![不透明の向こうにSkyboxがない.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/8d03cad2-58d0-2d9d-be7d-108354735c54.png)

これは Skybox -> 不透過オブジェクト の順番で描画していて
透過オブジェクトを描画するときに透過部分の前後関係がわからないため
上書きしてしまうためです
（透過シェーダーが深度バッファに書き込みしないため？）

これを防ぐために描画順を変更します

透過オブジェクト -> Skybox -> 不透過オブジェクト

※不透過オブジェクトをskyboxより後ろにしているのは、手前のオブジェクトから描画するほうがピクセル単位の計算を省略できるためです

```c#
        void DrawVisibleGeometry () {
                // 不透過オブジェクトだけ先に描画
                var sortingSettings = new SortingSettings(camera);
                var drawingSettings = new DrawingSettings(
                        unlitShaderTagId, sortingSettings
                );
                var filteringSettings = new FilteringSettings(RenderQueueRange.all);

                context.DrawRenderers(
                        cullingResults, ref drawingSettings, ref filteringSettings
                );

                // Skyboxを描画
                context.DrawSkybox(camera);

                // 透過オブジェクトを描画
                sortingSettings.criteria = SortingCriteria.CommonTransparent;
                drawingSettings.sortingSettings = sortingSettings;
                filteringSettings.renderQueueRange = RenderQueueRange.transparent;

                context.DrawRenderers(
                        cullingResults, ref drawingSettings, ref filteringSettings
                );
        }
```

![不透明の向こうにSkyboxがある.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/1f1444f8-9ccc-5c67-374c-e83fb16d701e.png)

これで正しく描画されました🎉

# まとめ

![完成形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7680/49d79f0b-0d18-86e3-b6b1-4d6090c8bf29.png)


なんとなくSRPでできることが見えてきました
まだ初歩的なので、次のステップとしてはURPのソースコードの読解でしょうか

URPのソースコードは下記にあるので是非読んでみてください
筆者はこれから読みます( ｀ー´)
`Library\PackageCache\com.unity.render-pipelines.universal@7.3.1`


# 参考資料

https://catlikecoding.com/unity/tutorials/custom-srp/custom-render-pipeline/

https://docs.unity3d.com/ja/2020.2/Manual/ScriptableRenderPipeline.html