UnityのSRPで最初の導入をやってみる
SPRの概念などに関しては、多くの方々が素晴らしい記事や講演をされているので、そちらをご覧ください。
LWRPがUnity2019.3でUniversalRPと名前を変えたようです。
ここでは、最初の最初、新しいSRPのセットアップを行い、簡単な画面が出るところまでやってみます。
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
のコードを参考にさせて頂きました。
とりあえず画面に何も出ないことが確認できました。虚無ですね。ありがとうございます。
(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
}
}
}
上記シェーダを利用したマテリアルを作成して、適当なテクスチャを貼り付けると、下記のような画面が出ます。
だんだん雑になってきました。
以上!
余談
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 (おすすめ)