XR のシングルパスインスタンスレンダリングでフルスクリーン転送を実行する方法
このページの例は、XR のシングルパスインスタンスレンダリングでフルスクリーン転送を実行するカスタム Renderer Feature を作成する方法を示しています。
例の概要
この例では、以下のソリューションを実装します。
カスタム レンダーパス を呼び出す カスタム Renderer Feature。
この レンダーパス は、不透明なテクスチャを、現在のレンダラーの カメラのカラーターゲット に転送します。レンダーパスはコマンドバッファを使用して、両目のフルスクリーンメッシュを描画します。
この例には、レンダリングの GPU 面を実行する シェーダー が含まれています。このシェーダーは、XR サンプラーマクロを使用してカラーバッファをサンプリングします。
前提条件
この例の前提条件は以下のとおりです。
- Scriptable Render Pipeline Settings プロパティが URP アセットを参照している (Project Settings > Graphics > Scriptable Render Pipeline Settings)。
サンプルのシーンとゲームオブジェクトの作成
この例のステップを実行するために、以下のゲームオブジェクトが含まれる新しいシーンを作成します。
キューブを作成します。メインカメラからキューブがはっきりと見えるようにします。
これで、この例のステップの実行に必要なシーンを用意できました。
実装例
このセクションは、サンプルのシーンとゲームオブジェクトの作成 の説明のとおりにシーンが作成されていることを前提としています。
以下の手順に従って、カスタム レンダーパス を使用する カスタム Renderer Feature を作成します。
新しい C# スクリプトを作成します。
ColorBlitRendererFeature.cs
という名前を付けます。このスクリプトは、カスタム Renderer Feature を実装します。using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; internal class ColorBlitRendererFeature : ScriptableRendererFeature { public Shader m_Shader; public float m_Intensity; Material m_Material; ColorBlitPass m_RenderPass = null; public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (renderingData.cameraData.cameraType == CameraType.Game) { // ScriptableRenderPassInput.Color 引数を指定して ConfigureInput を呼び出すことで、レンダーパスで不透明なテクスチャを利用できるようにします m_RenderPass.ConfigureInput(ScriptableRenderPassInput.Color); m_RenderPass.SetTarget(renderer.cameraColorTarget, m_Intensity); renderer.EnqueuePass(m_RenderPass); } } public override void Create() { if (m_Shader != null) m_Material = new Material(m_Shader); m_RenderPass = new ColorBlitPass(m_Material); } protected override void Dispose(bool disposing) { CoreUtils.Destroy(m_Material); } }
新しい C# スクリプトを作成します。
ColorBlitPass.cs
という名前を付けます。このスクリプトは、カスタム転送ドローコールを実行するカスタムレンダーパスを実装します。このレンダーパスは、
cmd.DrawMesh
メソッドを使用して、フルスクリーンクアッドを描画し、転送処理を実行します。ノート:
cmd.Blit
メソッドは URP XR 統合との互換性に問題があるため、URP XR プロジェクトでは使用しないでください。cmd.Blit
を使用すると、XR シェーダーキーワードが暗黙的に有効または無効になり、XR SPI レンダリングが停止する可能性があります。using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; internal class ColorBlitPass : ScriptableRenderPass { ProfilingSampler m_ProfilingSampler = new ProfilingSampler("ColorBlit"); Material m_Material; RenderTargetIdentifier m_CameraColorTarget; float m_Intensity; public ColorBlitPass(Material material) { m_Material = material; renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; } public void SetTarget(RenderTargetIdentifier colorHandle, float intensity) { m_CameraColorTarget = colorHandle; m_Intensity = intensity; } public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) { ConfigureTarget(new RenderTargetIdentifier(m_CameraColorTarget, 0, CubemapFace.Unknown, -1)); } public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) { var camera = renderingData.cameraData.camera; if (camera.cameraType != CameraType.Game) return; if (m_Material == null) return; CommandBuffer cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, m_ProfilingSampler)) { m_Material.SetFloat("_Intensity", m_Intensity); cmd.SetRenderTarget(new RenderTargetIdentifier(m_CameraColorTarget, 0, CubemapFace.Unknown, -1)); // RenderingUtils.fullscreenMesh 引数で、描画するメッシュがクアッドであることを指定します。 cmd.DrawMesh(RenderingUtils.fullscreenMesh, Matrix4x4.identity, m_Material); } context.ExecuteCommandBuffer(cmd); cmd.Clear(); CommandBufferPool.Release(cmd); } }
転送処理を実行するシェーダーを作成します。シェーダーファイルに
ColorBlit.shader
という名前を付けます。vertex 関数はフルスクリーンクアッドの位置を出力します。fragment 関数はカラーバッファをサンプリングし、値color * float4(0, _Intensity, 0, 1)
をレンダーターゲットに返します。Shader "ColorBlit" { SubShader { Tags { "RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"} LOD 100 ZWrite Off Cull Off Pass { Name "ColorBlitPass" HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionHCS : POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; UNITY_VERTEX_OUTPUT_STEREO }; Varyings vert(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); // ノート: このパスはすでにクリップスペースに存在するメッシュを // 使用して設定されているため、頂点の位置を出力するだけで // 十分です output.positionCS = float4(input.positionHCS.xyz, 1.0); #if UNITY_UV_STARTS_AT_TOP output.positionCS.y *= -1; #endif output.uv = input.uv; return output; } TEXTURE2D_X(_CameraOpaqueTexture); SAMPLER(sampler_CameraOpaqueTexture); float _Intensity; half4 frag (Varyings input) : SV_Target { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); float4 color = SAMPLE_TEXTURE2D_X(_CameraOpaqueTexture, sampler_CameraOpaqueTexture, input.uv); return color * float4(0, _Intensity, 0, 1); } ENDHLSL } } }
ColorBlitRendererFeature
をユニバーサルレンダラーアセットに追加します。Renderer Feature を追加する方法の詳細については、Renderer Feature をレンダラーに追加する方法 のページを参照してください。
この例では、Intensity プロパティを 1.5 に設定します。
このサンプルを可視化するために、XR SDK を使用するようにプロジェクトを設定します。MockHMD XR プラグインをプロジェクトに追加 します。Render Mode プロパティを Single Pass Instanced に設定します。
以下のようなビューが表示されます。
再生モードに入ります。カラーバッファが表示されます。
これでこの例は完成です。