LoginSignup
9
12

More than 3 years have passed since last update.

UnityのScriptable Render Pipeline(SRP)で最初の導入をやってみる

Last updated at Posted at 2019-10-05

UnityのSRPで最初の導入をやってみる

SPRの概念などに関しては、多くの方々が素晴らしい記事や講演をされているので、そちらをご覧ください。

LWRPがUnity2019.3でUniversalRPと名前を変えたようです。
ここでは、最初の最初、新しいSRPのセットアップを行い、簡単な画面が出るところまでやってみます。
image.png


Unityバージョンは2019.3.0b6
com.unity.render-pipelines.core 7.1.1
com.unity.render-pipelines.lightweight 7.1.1
com.unity.render-pipelines.universal 7.1.1

を利用しています

手順まとめ

コードを読んでみる
RenderPipelineクラスを継承してクラスを作る
RenderPipelineAssetクラスを継承してクラスを作る
RenderPipelineAssetの作成
RenderPipelineのRender関数内部の記載
RenderPipelineに即したシェーダとマテリアルの作成

上記手順にそってやってみます。

コードを読んでみる

PackageのコードはLibrary\PackageCacheフォルダの中に含まれています。

まずUniversalRenderPipeline.csを見てみます。このクラスはRenderPipelineを継承しています。
クラスの中にRender関数があります。

protected override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
{
    BeginFrameRendering(renderContext, cameras);

    GraphicsSettings.lightsUseLinearIntensity = (QualitySettings.activeColorSpace == ColorSpace.Linear);
    GraphicsSettings.useScriptableRenderPipelineBatching = asset.useSRPBatcher;
    SetupPerFrameShaderConstants();

    SortCameras(cameras);
    foreach (Camera camera in cameras)
    {
        BeginCameraRendering(renderContext, camera);
#if VISUAL_EFFECT_GRAPH_0_0_1_OR_NEWER
        //It should be called before culling to prepare material. When there isn't any VisualEffect component, this method has no effect.
        VFX.VFXManager.PrepareCamera(camera);
#endif
        RenderSingleCamera(renderContext, camera);

        EndCameraRendering(renderContext, camera);
    }

    EndFrameRendering(renderContext, cameras);
}

いいですね、いかにも僕レンダリングしてます!感があります。
レンダリングを行うためにはこの関数とクラスが必要そうです。

次に、このRenderPipelineを作成している箇所を探してみます。

protected override RenderPipeline CreatePipeline()
{
    // 色々処理していますが、省略。
    return new UniversalRenderPipeline(this);
}

ありました。UniversalRenderPipelineAsset.csです。
このクラスはRenderPipelineAssetを継承しています。

RenderPipelineAssetのCreatePipelineから、RenderPipelineを作成する流れのようですね。


RenderPipeline
RenderPipelineAsset

上記2つのクラスは、UnityEngine.Renderingの名前空間にいて、UniversalRPの中に含まれるコードではありません。
UniversalRPを使わないパイプラインの、最初のセットアップとしては、上記2つのクラスを利用する必要がありそうです。

RenderPipelineクラスを継承してクラスを作る

まずRenderPipelineクラスを作成します。
RenderPipelineを継承してクラスを作成します。

public class CustomRenderPipeline : RenderPipeline
{
    protected override void Render(ScriptableRenderContext context, Camera[] cameras)
    {
        //ここにレンダリング処理が入る
    }
}

RenderPipelineAssetクラスを継承してクラスを作る

次に、PipelineAssetクラスを作成します。
RenderPipelineAssetを継承してクラスを作成します。

public class CustomRenderPipelineAsset : RenderPipelineAsset
{
    protected override RenderPipeline CreatePipeline()
    {
        //パイプラインの作成
        return new CustomRenderPipeline();
    }
}

RenderPipelineAssetの作成

RenderPipelineAssetは、ScriptableObjectを継承しているクラスとなっていて、実際に利用するためには、Assetを作成する必要がありそうです。

public class CustomRenderCreate
{
    [MenuItem("Assets/Create/MySRP")]
    public static void CreateSRP()
    {
        var instance = ScriptableObject.CreateInstance<CustomRenderPipelineAsset>();
        AssetDatabase.CreateAsset(instance, "Assets/MyScriptableRenderPipeline.asset");
        GraphicsSettings.renderPipelineAsset = instance;    //勝手に設定してくれている
    }
}

上記コードは
https://connect.unity.com/p/scriptablerenderpipelinewozi-zuo-shitemita
のコードを参考にさせて頂きました。

ここまでやると、ゲーム画面はこうなります。
image.png

とりあえず画面に何も出ないことが確認できました。虚無ですね。ありがとうございます。
(Qiitaさんこんな画像に容量つかってすみません)

RenderPipelineのRender関数内部の記載

上記で作成した、CustomRenderPipelineのRender関数には何も記載がないので
当然なにも表示されません。
そこで、最低限のレンダリングを行うコードを書いてみます

あまり長くないので全文載せます

public class CustomRenderPipeline : RenderPipeline
{
    void SortCameras(Camera[] cameras)
    {
        Array.Sort(cameras, (lhs, rhs) => (int)(lhs.depth - rhs.depth));
    }

    /// <summary>
    /// レンダリング実装箇所
    /// </summary>
    /// <param name="context"></param>
    /// <param name="cameras"></param>
    protected override void Render(ScriptableRenderContext context, Camera[] cameras)
    {
        BeginFrameRendering(context, cameras);

        GraphicsSettings.lightsUseLinearIntensity = (QualitySettings.activeColorSpace == ColorSpace.Linear);

        SortCameras(cameras);

        // カメラごとに処理
        foreach (var camera in cameras)
        {
            BeginCameraRendering(context, camera);

            // カメラプロパティ設定
            context.SetupCameraProperties(camera);

            //カリングの実行
            CullingResults cullResults = new CullingResults();
            ScriptableCullingParameters cullingParameters;
            if(!camera.TryGetCullingParameters(false,out cullingParameters)) continue;
            cullResults = context.Cull(ref cullingParameters);

            //フィルタリング、ソート
            SortingSettings sortingSettings = new SortingSettings(camera) {criteria = SortingCriteria.CommonOpaque};
            var settings = new DrawingSettings(new ShaderTagId("lbDeferred"), sortingSettings);
            var filterSettings = new FilteringSettings(new RenderQueueRange(
                0,
                (int) RenderQueue.GeometryLast), 
                camera.cullingMask);

            //描画処理
            context.DrawRenderers(cullResults, ref settings, ref filterSettings);

            EndCameraRendering(context, camera);
        }

        //サブミット(終了処理)
        context.Submit();
        EndFrameRendering(context, cameras);
    }
}

実際のレンダリングのコードは、以下講演から引用させて頂きました。
https://www.youtube.com/watch?v=nLjT1bwz2P4

上記処理について細かく説明している&今年行われた、実践的で分かりやすい講演なので、ぜひご覧になってみてください。

RenderPipelineに即したシェーダとマテリアルの作成

Shader "Unlit/NewUnlitShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            Tags { "LightMode" = "lbDeferred" }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

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

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            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;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // sample the texture
                fixed4 col = tex2D(_MainTex, i.uv);
                // apply fog
                UNITY_APPLY_FOG(i.fogCoord, col);
                return col;
            }
            ENDCG
        }
    }
}

上記シェーダを利用したマテリアルを作成して、適当なテクスチャを貼り付けると、下記のような画面が出ます。
だんだん雑になってきました。

image.png

以上!

余談

Packageのコードを読もうとすると、VisualStudioだとPackageの参照が正常に読み込まれず
Preference→ExternalToolsのGenerate all .csprojをONにする必要がありました。

ただ、VisualStudioだとPackage内部のコードにはブレークポイントが貼れませんでした。。。
(Riderを使ってみると、ブレークポイントが貼れました)
ここらへんお詳しい方いたら、ご教授いただけると助かります (*_ _)

参考リンク
https://connect.unity.com/p/scriptablerenderpipelinewozi-zuo-shitemita (少し古め)
https://catlikecoding.com/unity/tutorials/scriptable-render-pipeline/ (おすすめ。英語ですが、SRP関連の情報が多い)
https://www.youtube.com/watch?v=nLjT1bwz2P4 (おすすめ)

9
12
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
9
12