見出し画像

Unity2D(URP)で3Dオブジェクトのアウトラインを書いてみた(その2)

前回からの続きです。

おさらいすると、前回はリムライトシェーダーを使って、真ん中を透明にすることによりアウトライン化しました。

これだと、オブジェクト同士の接合部分が乗算されかえって目立ち、個々の存在として、物質感を感じさせてしまいます。

画像1

今回のゲームだと、虫達は、確固たる存在として表現し、ただ気持ち悪さを低減させるために、アウトラインで表現しようと思いました。

ただ、主人公は本当に居るのか居ないのか?を感じさせるところが一つのポイントと思い、キャラ全体のアウトラインを目指すことにしました。

出来た絵が、前回から張り付けているこれになります。

画像2

見てもらうと分かる通り、胴体や頭の切れ目がありません。これにより、空気や幻のような流体に近い表現を目指してます。今回のシェーダーはこのアウトラインを目指します。

SRPによるカスタムポストプロセスによる実装

SRPを敢えて実装する主な理由を説明として

・カリング等特殊な軽減処理を実装する
・最終的に出来上がった絵ずらに自分の思うような加工する(custom postprocess)があります。

主にCustomPostProcessを自分の思うように作りたいと言う動機から作成に踏み切ると思います。

今回postprocessとしてエッジ抽出に使用しようとしたメソッド
・Prewitt,SobelFillter

・robertCross

どれも、各Pixelからすると他点参照でそんな本格的な物は要らないと言う印象、しかもSqrtを何とかなくせないか?と言う事で更なる模索に

結局検討の結果メタボールの表現が近く、出来上がった絵に対して、輝度で閾値を持ち、クリッピングする代わりに折り返したらどうか?と言う発案の元作成してみました。

全体を描画する仕組みとして少し複雑な為、少し仕組みを説明

2つのカメラを使います。

①カメラはシーンを写します。更にアウトライン化したい(今回で言うとPlayer)は写す対象から外します。もう一方の②カメラで写します。又、ポストプロセスで、写しているシーンと②カメラの出力であるテクスチャとを合成します。

②カメラはアウトライン化したいオブジェクト、今回で言うとレイヤーにPlayerが設定されているオブジェクトを写します。更にそのカメラの出力先はレンダーテクスチャに貯めこみます

カメラとか必要な周辺設定

①カメラ・・・シーンを写すカメラ設定
 2Ðを写すカメラとして設定します。適当なフォルダの上で右クリック→作成→レンダリング→UniversalRenderPipeLine→2Ð Renderer(Experimental)を作成します。分かりやすいように名前を変えておいてください。

画像5編集→プロジェクト設定→グラフィックスに設定してあるUniversalRP-HighQualityの設定を見てみます。

画像4

その設定の上の方にあるレンダラーリストに作った2ÐRenderDataアセットを設定します

画像6

カメラの設定に行きます。ヒエラルキーのカメラをクリックしてインスペクターを確認します。

画像7

レンダリングのレンダラーが上で設定した2ÐRendataDataアセットに成って居たら成功です。
このカメラは2Ð(用のシェーダー)の世界を写すカメラになります。
カリングマスクでアウトライン対象のレイヤーを写さないように設定します。(下の例だとPlayer)

画像3

これらの設定で2Ð用のシェーダー(nameTagにUniversal2dがあるPass)を写すカメラとして機能します。
※蛇足ですが、URP標準のLitシェーダーは3dオブジェクトを写すシェーダーですが、nameTagに"Universal2D"があるPassが一つ設定されていますので2Ð用のカメラでも写るようになっています。

ここまでで、メインシーンのプレイヤー以外を写す設定が出来ました。
この後ポストプロセスでプレイヤーの絵を合成しますが、先にプレイヤーを写すカメラの設定をします。

②カメラ・・・アウトライン対象(Player)を写すカメラ設定
こちらは3Ðを普通に写す物で、事足ります。
(Playerは2Ðのオブジェクトで無くて3d用のオブジェクト予定しています。)

UniversalRP-HighQualityの設定に戻り

画像8

レンダーリストの右下の+ボタンを押下し、一行追加します。ここには最初からあるFowardRendererを設定します。
カメラを追加します。
シーンにあるカメラを選択した状態で右クリック→カメラを押下します。

画像9

インスペクターのレンダラーをFowardRendererに変えます。

画像10

カメラの出力のレンダーテクスチャを作成します。
適当なフォルダ上で右クリック→作成→レンダーテクスチャを選択します。

画像11

出来たテクスチャのサイズを実際のゲーム画面にします。
他はそのままでOKです。
カメラの設定に戻って、OutputTextureに作ったテクスチャを設定します。

画像12

画像13

カリングマスクにPlayerを設定します。
これにより、このカメラはPlayerだけをテクスチャに写し続ける為だけのカメラとして機能します。

プレイヤー用(アウトラインの材料)のシェーダー作成

プレイヤーをアウトライン化する為に、メタボールの概念に則り、まずプレイヤーを2D上で見た、輝度だけの存在にします。

前回の記事で作った、Rimシェーダーをフォルダ毎コピーして改変します。

Shader "test/Metaball"
{
   Properties
   {
       // Specular vs Metallic workflow
       [HideInInspector] _WorkflowMode("WorkflowMode", Float) = 1.0

       [MainTexture] _BaseMap("Albedo", 2D) = "white" {}
       [MainColor] _BaseColor("Color", Color) = (1,1,1,1)

       _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5

       _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5
       _GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0
       _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0

       _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
       _MetallicGlossMap("Metallic", 2D) = "white" {}

       _SpecColor("Specular", Color) = (0.2, 0.2, 0.2)
       _SpecGlossMap("Specular", 2D) = "white" {}

       [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
       [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0

       _BumpScale("Scale", Float) = 1.0
       _BumpMap("Normal Map", 2D) = "bump" {}

       _Parallax("Scale", Range(0.005, 0.08)) = 0.005
       _ParallaxMap("Height Map", 2D) = "black" {}

       _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
       _OcclusionMap("Occlusion", 2D) = "white" {}

       [HDR] _EmissionColor("Color", Color) = (0,0,0)
       _EmissionMap("Emission", 2D) = "white" {}

       _DetailMask("Detail Mask", 2D) = "white" {}
       _DetailAlbedoMapScale("Scale", Range(0.0, 2.0)) = 1.0
       _DetailAlbedoMap("Detail Albedo x2", 2D) = "linearGrey" {}
       _DetailNormalMapScale("Scale", Range(0.0, 2.0)) = 1.0
       [Normal] _DetailNormalMap("Normal Map", 2D) = "bump" {}

       _RimEffect("_RimEffect", Float) = 1.0
       [HDR]_RimColor("_RimColor", Color) = (0,0,0,0)      
       // SRP batching compatibility for Clear Coat (Not used in Lit)
       [HideInInspector] _ClearCoatMask("_ClearCoatMask", Float) = 0.0
       [HideInInspector] _ClearCoatSmoothness("_ClearCoatSmoothness", Float) = 0.0

       // Blending state
       _Surface("__surface", Float) = 0.0
       _Blend("__blend", Float) = 0.0
       _AlphaClip("__clip", Float) = 0.0
       _SrcBlend("__src", Float) = 1.0
       _DstBlend("__dst", Float) = 0.0
       _ZWrite("__zw", Float) = 1.0
       _Cull("__cull", Float) = 2.0

       _ReceiveShadows("Receive Shadows", Float) = 1.0
       // Editmode props
       [HideInInspector] _QueueOffset("Queue offset", Float) = 0.0

       // ObsoleteProperties
       [HideInInspector] _MainTex("BaseMap", 2D) = "white" {}
       [HideInInspector] _Color("Base Color", Color) = (1, 1, 1, 1)
       [HideInInspector] _GlossMapScale("Smoothness", Float) = 0.0
       [HideInInspector] _Glossiness("Smoothness", Float) = 0.0
       [HideInInspector] _GlossyReflections("EnvironmentReflections", Float) = 0.0

       [HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {}
       [HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {}
       [HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {}
   }

   SubShader
   {
       // Universal Pipeline tag is required. If Universal render pipeline is not set in the graphics settings
       // this Subshader will fail. One can add a subshader below or fallback to Standard built-in to make this
       // material work with both Universal Render Pipeline and Builtin Unity Pipeline
       Tags{"RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "UniversalMaterialType" = "Lit" "IgnoreProjector" = "True" "ShaderModel"="4.5"}
       LOD 300

       // ------------------------------------------------------------------
       //  Forward pass. Shades all light in a single pass. GI + emission + Fog
       Pass
       {
           // Lightmode matches the ShaderPassName set in UniversalRenderPipeline.cs. SRPDefaultUnlit and passes with
           // no LightMode tag are also rendered by Universal Render Pipeline
           Name "ForwardLit"
           Tags{"LightMode" = "UniversalForward"}

           Blend[_SrcBlend][_DstBlend]
           ZWrite[_ZWrite]
           Cull[_Cull]

           HLSLPROGRAM
           #pragma exclude_renderers gles gles3 glcore
           #pragma target 4.5

           // -------------------------------------
           // Material Keywords
           #pragma shader_feature_local _NORMALMAP
           #pragma shader_feature_local_fragment _ALPHATEST_ON
           #pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON
           #pragma shader_feature_local_fragment _EMISSION
           #pragma shader_feature_local_fragment _METALLICSPECGLOSSMAP
           #pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
           #pragma shader_feature_local_fragment _OCCLUSIONMAP
           #pragma shader_feature_local _PARALLAXMAP
           #pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED
           #pragma shader_feature_local_fragment _SPECULARHIGHLIGHTS_OFF
           #pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF
           #pragma shader_feature_local_fragment _SPECULAR_SETUP
           #pragma shader_feature_local _RECEIVE_SHADOWS_OFF

           // -------------------------------------
           // Universal Pipeline keywords
           #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
           #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
           #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
           #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
           #pragma multi_compile_fragment _ _SHADOWS_SOFT
           #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
           #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
           #pragma multi_compile _ SHADOWS_SHADOWMASK

           // -------------------------------------
           // Unity defined keywords
           #pragma multi_compile _ DIRLIGHTMAP_COMBINED
           #pragma multi_compile _ LIGHTMAP_ON
           #pragma multi_compile_fog

           //--------------------------------------
           // GPU Instancing
           #pragma multi_compile_instancing
           #pragma multi_compile _ DOTS_INSTANCING_ON

           #pragma vertex LitPassVertex
           #pragma fragment LitPassFragment

           #include "LitInput.hlsl"
           #include "LitForwardPass.hlsl"
           ENDHLSL
       }
   }

   FallBack "Hidden/Universal Render Pipeline/FallbackError"
   //CustomEditor "UnityEditor.Rendering.Universal.ShaderGUI.LitShader"
}

前回のRimシェーダーが作れているのであれば余り特筆する事はありません。
改変する箇所は2か所です。
まず、1行目の

Shader "test/Metaball"

を好きなシェーダー名にしてください。
それと

           Tags{"LightMode" = "UniversalForward"}

Tagを前回変えたUniversal2D→UniversalForwardに変更して、3Ð用のカメラに映るように変更します。

LitInputは前回変えたパラメータと同じなので、そのまま使います。

LitForwardPassを改変します。

half4 LitPassFragment(Varyings input) : SV_Target
{
   UNITY_SETUP_INSTANCE_ID(input);
   UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

   float val = max((dot(input.viewDirWS.xyz, input.normalWS) *  _RimEffect),0);
   half4 color = (_RimColor * val * val );
   return color;
}

前回からの変更点は、光の当たり具合を全く考慮しないのでUNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);以降をさっぱり消します。

float val = max((dot(input.viewDirWS.xyz, input.normalWS) *  _RimEffect),0);

その上でこの行に注目します。
前回は、この一行が1-dot積にして、外周強調してたのに対して、今回は外周を抑えて内部を強調します。テクスチャ的に見たら各ピクセルを真正面から見たような感じに成ります。

このシェーダーを置いたオブジェクトを試しに数点置いてみます。
但し、3Dをエディタに描画するカメラは無いので、テクスチャで確認します。

画像14

複数の球のLayerをPlayerに変更します。それを数体置いて、上で作成したシェーダーのマテリアルを当てます。

画像27

カメラ①の結果がレンダーテクスチャに描画している様子を確認
このレンダーテクスチャの結果に対して加工をしていきます。

カメラ①とレンダーテクスチャとの合成

ここまでで、2Dシーンを写すカメラとプレイヤーを写したテクスチャが出来ました。
シーンの絵とプレイヤーが写ってるテクスチャとの合成をします。

SRP設定

SRPで合成をします。Updateと並行に動いているカメラのUpdateで処理をすると思ってください。

PostProcess のパラメータ作成

using System;
using System.Diagnostics;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Serialization;

namespace srp
{
   public class MetaBallPostProcess : VolumeComponent, IPostProcessComponent{
       public MaterialParameter material = new MaterialParameter(null);
       public bool IsActive() => material.value != null;

       public bool IsTileCompatible() => false;
   }
   [Serializable, DebuggerDisplay(k_DebuggerDisplay)]
   public class MaterialParameter : VolumeParameter<Material>{
       public MaterialParameter(Material value, bool overrideState = false)
           : base(value, overrideState) {}
   }
}

これを作成すると、カスタムポストプロセス用のパラメータが設定できるようになります。(標準だと、Materialはパラメータに指定できません。上記のうちのMaterialParameterクラスがそれを可能にしています。)

画像19

ScriptableRendererFeatureの作成

using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.Serialization;

namespace srp{
   public class MetaBallSrpFeature : ScriptableRendererFeature
   {
       public MetaBallSrpPass metaBallPass;

       public override void Create(){
           metaBallPass = new MetaBallSrpPass(RenderPassEvent.BeforeRenderingPostProcessing);
       }

       public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData){
           renderer.EnqueuePass(metaBallPass);
       }
   }
}

AddRendererPassesが毎フレーム動く予定の処理

ScriptableRenderPassの作成

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

namespace srp{
   public class MetaBallSrpPass : ScriptableRenderPass{
       static readonly string k_RenderTag = "MetaBall Effects";
       private FilteringSettings _filteringSettings; // レンダリングのフィルタリング設定
       private MetaBallPostProcess _metaBall;

       private RenderTargetIdentifier passSource;
       private RenderTargetHandle passDestination;
       RenderTargetHandle _TemporaryColorTexture;

       public MetaBallSrpPass(RenderPassEvent evt){
           renderPassEvent = evt;
       }

       public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData){

           if (!renderingData.cameraData.postProcessEnabled) return;
           
           var stack = VolumeManager.instance.stack;
           _metaBall = stack.GetComponent<MetaBallPostProcess>();
           if (_metaBall == null) { return; }
           if (_metaBall.material == null){Debug.LogError("Material not created.");return;}
           if (!_metaBall.IsActive()) { return; }
           var cmd = CommandBufferPool.Get(k_RenderTag);
           Blit(cmd,passSource,passDestination.Identifier(), _metaBall.material.value, 0);
           
           context.ExecuteCommandBuffer(cmd);
           CommandBufferPool.Release(cmd);
       }
       //public override void FrameCleanup(CommandBuffer cmd){
           //cmd.ReleaseTemporaryRT(_TemporaryColorTexture.id);
       //}
       public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData){
           var renderer = renderingData.cameraData.renderer;
           passSource = renderer.cameraColorTarget;
           passDestination = RenderTargetHandle.CameraTarget;
       }
   }
}

解説すると、ここまでに2Ðカメラで描画が出来ています。
その上で、以下の一文で、materialで描画したテクスチャを出力結果(passDestination)に描画しています。

Blit(cmd,passSource,passDestination.Identifier(), _metaBall.material.value, 0);

このマテリアル(_metaBall.material.value)は未だ作成していませんが、最終的にPlayerを写したレンダーテクスチャをアウトライン化して描画するマテリアルがここに入ります。(postprocessパラメータに当てはめて、ここにやってくる予定)

マテリアル作成

shader作成…前回作った"test/Metaball"を又フォルダ毎コピーしてください。

Shader "test/MetaBallCaster"
{
   Properties
   {
       // Specular vs Metallic workflow
       [HideInInspector] _WorkflowMode("WorkflowMode", Float) = 1.0

       [MainTexture] _BaseMap("Albedo", 2D) = "white" {}
       [MainColor] _BaseColor("Color", Color) = (1,1,1,1)

       _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5

       _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5
       _GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0
       _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0

       _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
       _MetallicGlossMap("Metallic", 2D) = "white" {}

       _SpecColor("Specular", Color) = (0.2, 0.2, 0.2)
       _SpecGlossMap("Specular", 2D) = "white" {}

       [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0
       [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0

       _BumpScale("Scale", Float) = 1.0
       _BumpMap("Normal Map", 2D) = "bump" {}

       _Parallax("Scale", Range(0.005, 0.08)) = 0.005
       _ParallaxMap("Height Map", 2D) = "black" {}

       _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
       _OcclusionMap("Occlusion", 2D) = "white" {}

       [HDR] _EmissionColor("Color", Color) = (0,0,0)
       _EmissionMap("Emission", 2D) = "white" {}

       _DetailMask("Detail Mask", 2D) = "white" {}
       _DetailAlbedoMapScale("Scale", Range(0.0, 2.0)) = 1.0
       _DetailAlbedoMap("Detail Albedo x2", 2D) = "linearGrey" {}
       _DetailNormalMapScale("Scale", Range(0.0, 2.0)) = 1.0
       [Normal] _DetailNormalMap("Normal Map", 2D) = "bump" {}

       _RimRatio("_RimRatio", Float) = 1.0
       _RimGain("_RimGain", Float) = 1.0
       _RimPower("_RimPower", Float) = 1.0
       [HDR]_RimColor("_RimColor", Color) = (0,0,0,0)      

――――以下略

前回と違うところは、下の方で改変パラメータが変わっています。
_RimRatio…輝度を折り返す閾値
_RimGain…折り返す時の減少係数(drainと言う方が良かったかもしれない。)
_RimPower…出来上がったRimを持ち上げている。まあ_RimColorがHDRだからこれの輝度を上げればよかっただけかもしれない。お好みで

LitInput

――――前略

float  _RimRatio;
float  _RimGain;
float  _RimPower;
half4  _RimColor;
CBUFFER_END

パラメータを変えてます。ここに入れる意味は前回の記事参照

LitForwardPass

half4 LitPassFragment(Varyings input) : SV_Target
{
   UNITY_SETUP_INSTANCE_ID(input);
   UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

   half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv.xy);
   
   float distsq = (color.r * color.r) + (color.g * color.g) + (color.b * color.b) + (color.a * color.a);  
   float a = step(_RimRatio,distsq) * distsq  * _RimGain;
   float ca = color.a - a;
   ca = max(ca,0);
   color.a = ca;
   color *= _RimColor * _RimPower;
   return color;
}

又FragmentShaderだけ改変します。UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);以降ががらっと変わっています。

half4 color = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv.xy);

この一行でレンダーテクスチャのピクセルを取得します。

float distsq = (color.r * color.r) + (color.g * color.g) + (color.b * color.b) + (color.a * color.a);  

この行はピクセルの輝度です。

   float a = step(_RimRatio,distsq) * distsq  * _RimGain;

この一行が今回の記事のポイントです。step関数を使うことにより、輝度が_RimRatioを越えると、1に成り、以降の掛け算数値がいきなり数値化します。それまでは0なので越えるまでは、以降の掛け算が無効になる感じです。

残りの行はアルファが0以下にならないようにして、輝度、発色整形をしているだけです。

Materialを作成します

好きなフォルダで右クリック→作成→マテリアル
Shaderを作ったtest/MetaBallCasterに変更します。

画像20

Albedoに上の方で作ったレンダーテクスチャを当てはめます。

画像21

__surface~レンダーキューはショットの通りの設定にしてください。

こうして出来たマテリアルを作成したポストプロセスのマテリアルに当てはめます。

画像22

ここまでを行って、普通の3Ðなら、FowardRenderer設定にRenderFeatureを追加すれば簡単にポストエフェクトを差し込めます。ですが、今回差し込みたいのは2D用のカメラです。

RendererFeatureの設定

普通にRenderer2ÐDataにアセットを設定できません。まだ現時点だとサポートしていません。近いうちに設定できるようになると思います。

Renderer2ÐDataアセットを選択した状態で通常モードからデバッグモードに変更します。

画像17

画像25

設定する為には、ScriptableRendererFeatureをアセットにする必要があります。

適当なフォルダ上で右クリック→作成→レンダリング→UniversalRendererPipeLine→FowardRendererを作成します。

画像24

作成したFowardRendererの下のAddRendererFeatureを押下して、作成したFeatureを選択します。

画像25

これで、FowardRendererの子にScriptableRendererFeatureアセットが作成されます。このアセットをデバッグモードにした2ÐRendererDataに設定します。

画像26


ここまで設定すれば差し込める???と思います。が…もう少し続きます。

もう一度言いますが、2Ðカメラ用の差し込み処理は現在機能していません。2Dカメラ用のポストプロセスは現在出来ませんので、少し機能を改変する必要があります。
(2021/03時点だと、ありませんが、期待されている機能で数か月後にはURP側で対応するとフォーラムでやり取りがありました。)

画像16

この画面の下側辺りにFowardRenderer同様AddRendererFeatureボタンが付いてくれることに期待!

今は無いので魔改造します。

まず、packages配下のUniversal RPを選択し、右クリック→エクスプローラーで表示を選択します。

Package直下のフォルダも右クリック→エクスプローラーで表示し、UniversalRPのフォルダ毎Package配下に移動して改変可能な状態にします。
(下記のような状態にします。)

画像18

さらにこの中のPackages\com.unity.render-pipelines.universal\Runtime\2D\Renderer2D.cs
を開いて以下のように改変します。

        public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData)
       {
           ref CameraData cameraData = ref renderingData.cameraData;
           ref var cameraTargetDescriptor = ref cameraData.cameraTargetDescriptor;
           bool stackHasPostProcess = renderingData.postProcessingEnabled;
           bool lastCameraInStack = cameraData.resolveFinalTarget;
           var colorTextureFilterMode = FilterMode.Bilinear;

ーーーーーーーーーーーーーーーーーーーー中略ーーーーーーーーーーーーーーーーーーーーーーー

           else if (lastCameraInStack && colorTargetHandle != RenderTargetHandle.CameraTarget)
           {
               m_FinalBlitPass.Setup(cameraTargetDescriptor, colorTargetHandle);
               EnqueuePass(m_FinalBlitPass);
           }
           
           //2d addfeature
           for (var i = 0; i < rendererFeatures.Count; i++) 
           {
               if (rendererFeatures[i].isActive)
               {
                   rendererFeatures[i].AddRenderPasses(this, ref renderingData);
               }
           }
       }

一番下に以下の部分を張り付けてます。この状態で保存(なんて事はない、Renderer FeatureのAddRenderPassesが呼ばれて無いだけなんですね!)

           //2d addfeature
           for (var i = 0; i < rendererFeatures.Count; i++) 
           {
               if (rendererFeatures[i].isActive)
               {
                   rendererFeatures[i].AddRenderPasses(this, ref renderingData);
               }
           }

これで描画のタイミングで表示されるように成ります。

そして出来た絵がこちらに成ります。
後ろの2Ð絵とPlayer(球)が合成されて描画されていますね!

画像27

以上長くなりましたが、SRPを使ったアウトライン描画でした。


この記事が気に入ったらサポートをしてみませんか?