إنشاء تأثير مخطط تفصيلي في خط أنابيب العرض العالمي للوحدة

في Universal Render Pipeline ، من خلال إنشاء ميزة Renderer الخاصة بك ، يمكنك بسهولة توسيع إمكانات العرض. تسمح لك إضافة تمريرات جديدة إلى خط أنابيب التقديم بإنشاء تأثيرات متنوعة. في هذه المقالة ، باستخدام ScriptableRendererFeature و ScriptableRenderPass ، سننشئ تأثير المخطط التفصيلي للكائن ونأخذ في الاعتبار بعض ميزات تنفيذه.

تأثير المخطط التفصيلي


مقدمة أو بضع كلمات عن Render Pipeline


يسمح لك Scriptable Render Pipeline بالتحكم في عرض الرسومات من خلال البرامج النصية في C # والتحكم في ترتيب معالجة الكائنات والأضواء والظلال والمزيد. Universal Render Pipeline هو خط أنابيب Renderable جاهز للبرامج النصية تم تطويره بواسطة Unity وتم تصميمه ليحل محل RP القديم المدمج.

يمكن توسيع إمكانات Universal RP من خلال إنشاء وإضافة تصاريح الرسم الخاصة بك (ScriptableRendererFeature و ScriptableRenderPass). ستكون هذه المقالة الحالية. سيكون مفيدًا لأولئك الذين سوف يتحولون إلى Universal RP ، وربما يساعدون في فهم عمل ScriptableRenderPass'ov الحالي في Universal RP بشكل أفضل.

تمت كتابة هذه المقالة في Unity 2019.3 و Universal RP 7.1.8.

خطة عمل


سوف نفهم كيف يعمل ScriptableRendererFeature و ScriptableRenderPass على مثال إنشاء تأثير الحد للكائنات المعتمة.

للقيام بذلك ، قم بإنشاء ScriptableRendererFeature يقوم بتنفيذ الإجراءات التالية:

  • رسم الكائنات المحددة
  • تعتيم الأشياء المرسومة
  • الحصول على ملامح الأشياء من الصور التي تم الحصول عليها في الممرات السابقة

إطار المصدر -

وتسلسل النتائج التي يجب أن نحققها:


في سياق العمل ، سنقوم بإنشاء تظليل ، في الخصائص العالمية سيتم حفظ نتائج الممر الأول والثاني. سيعرض التمرير الأخير نتيجة التظليل نفسه على الشاشة.

الخصائص العالمية
, , Properties. — .

— . .

إنشاء ميزة المخطط التفصيلي


يتم استخدام ScriptableRendererFeature لإضافة مقاطع عرض مخصصة (ScriptableRenderPass) إلى Universal RP. إنشاء فئة OutlineFeature التي ترث من ScriptableRenderFeature وتنفيذ أساليبها.

using UnityEngine;
using UnityEngine.Rendering.Universal;

public class OutlineFeature : ScriptableRendererFeature
{
    public override void Create()
    { }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    { }
}

يتم استخدام الأسلوب Create () لإنشاء وتكوين التمريرات. وأسلوب AddRenderPasses () لحقن التمريرات التي تم إنشاؤها في قائمة انتظار العرض.

الحجج AddRenderPasses ()
ScriptableRenderer — Universal RP. Universal RP Forward Rendering.

RenderingData — , , .

لنبدأ الآن في إنشاء تصاريح العرض ، وسنعود إلى الفصل الحالي بعد تنفيذ كل منها.

تمرير الكائنات


تتمثل مهمة هذا المقطع في رسم كائنات من طبقة معينة مع استبدال المادة في خاصية النسيج الشاملة للتظليل. ستكون هذه نسخة مبسطة من مرور RenderObjectsPass المتاح في Universal RP ، مع الاختلاف الوحيد في الهدف (RenderTarget) حيث سيتم تنفيذ العرض.

إنشاء فئة MyRenderObjectsPass الموروثة من ScriptableRenderPass. نقوم بتطبيق أسلوب Execute () ، الذي سيحتوي على كل منطق المرور ، بالإضافة إلى إعادة تعريف طريقة Configure ().

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

public class MyRenderObjectsPass : ScriptableRenderPass
{
    {
        public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
        { }
        public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
        { }
    }
}

يتم استخدام طريقة Configure () لتحديد الغرض من عرض وإنشاء مواد مؤقتة. بشكل افتراضي ، الهدف هو هدف الكاميرا الحالية ، وبعد الانتهاء من التمرير ، سيتم تحديده افتراضيًا مرة أخرى. يتم استدعاء هذه الطريقة قبل تشغيل المنطق الأساسي.

جعل استبدال الهدف


قم بتعريف RenderTargetHandle لهدف عرض جديد. باستخدامه ، قم بإنشاء نسيج مؤقت وحدده كهدف. يحتوي RenderTargetHandle على معرف RenderTexture المؤقت المستخدم. كما يسمح لك بالحصول على RenderTargetIdentifier ، والذي يستخدم لتحديد هدف العرض الذي يمكن تعيينه ، على سبيل المثال ، على أنه RenderTexture أو كائن Texture أو RenderTexture مؤقت أو مضمّن (تستخدمه الكاميرا عند عرض إطار).

سيتم إنشاء كائن RenderTargetHandle في OutlineFeature وتمريره إلى بطاقة المرور عند إنشائه.

private RenderTargetHandle _destination;

public MyRenderObjectsPass(RenderTargetHandle destination)
{
    _destination = destination;
}

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{  
    cmd.GetTemporaryRT(_destination.id, cameraTextureDescriptor);
}

ينشئ الأسلوب GetTemporaryRT () نص RenderTexture مؤقتًا مع المعلمات المحددة ويعينه كخاصية تظليل عمومي بالاسم المحدد (سيتم تعيين الاسم في الميزة).

إزالة RenderTexture
ReleaseTemporaryRT() RenderTexture. Execute() FrameCleanup.
, RenderTexture, , .

لإنشاء RenderTexture مؤقت ، نستخدم واصف الكاميرا الحالية التي تحتوي على معلومات حول الحجم والتنسيق والمعلمات الأخرى لهدف الكاميرا.

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{        
    cmd.GetTemporaryRT(_destination.id, cameraTextureDescriptor);
    ConfigureTarget(_destination.Identifier());
    ConfigureClear(ClearFlag.All, Color.clear);
}

يجب أن يحدث الغرض من الهدف وتنظيفه فقط في Configure () باستخدام أساليب ConfigureTarget () و ClearTarget ().

يجعل


لن نفكر في تقديم التفاصيل ، لأنه هذا يمكن أن يقودنا بعيدًا وبعيدًا عن الموضوع الرئيسي. للتقديم ، سنستخدم طريقة ScriptableRenderContext.DrawRenderers (). قم بإنشاء إعدادات لتقديم الكائنات المعتمة فقط من الطبقات المحددة فقط. سيتم تمرير قناع الطبقة إلى المنشئ.

...
private List<ShaderTagId> _shaderTagIdList = new List<ShaderTagId>() { new ShaderTagId("UniversalForward") };
private FilteringSettings _filteringSettings;
private RenderStateBlock _renderStateBlock;
...
public MyRenderObjectsPass(RenderTargetHandle destination, int layerMask)
{
    _destination = destination;

    _filteringSettings = new FilteringSettings(RenderQueueRange.opaque, layerMask);
    _renderStateBlock = new RenderStateBlock(RenderStateMask.Nothing);
}

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
    SortingCriteria sortingCriteria = renderingData.cameraData.defaultOpaqueSortFlags;
    DrawingSettings drawingSettings = CreateDrawingSettings(_shaderTagIdList, ref renderingData, sortingCriteria);

    context.DrawRenderers(renderingData.cullResults, ref drawingSettings, ref _filteringSettings, ref _renderStateBlock);
}

لفترة وجيزة للغاية حول المعلمات
CullingResults — ( RenderingData)
FilteringSettings — .
DrawingSettings — .
RenderStateBlock — , (, ..)

حول RenderObjectsPass النهائي في UniversalRP
, . . RenderObjectsPass, Universal RP, . RenderFeature - :)

استبدال المواد


نحن نعيد تعريف المواد المستخدمة في التقديم ، لأننا نحتاج فقط إلى حدود الأشياء.

private Material _overrideMaterial;

public MyRenderObjectsPass(RenderTargetHandle destination, int layerMask,, Material overrideMaterial)
{
...
    _overrideMaterial = overrideMaterial;
...
}

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
...
    DrawingSettings drawingSettings = CreateDrawingSettings(_shaderTagIdList, ref renderingData, sortingCriteria);
    drawingSettings.overrideMaterial = _overrideMaterial;
...
}

شادر للعرض


قم بإنشاء تظليل مادة في ShaderGraph سيتم استخدامه عند رسم الكائنات في التمرير الحالي.


أضف ممرًا إلى OutlineFeature


عودة إلى OutlieFeature. أولاً ، قم بإنشاء فئة لإعدادات المقطع الخاص بنا.

public class OutlineFeature : ScriptableRendererFeature
{
    [Serializable]
    public class RenderSettings
    {
        public Material OverrideMaterial = null;
        public LayerMask LayerMask = 0;
    }
    ...
}

قم بتعريف حقول إعدادات MyRenderPass واسم خاصية النسيج العامة المستخدمة كهدف العرض من خلال تصريحنا.

[SerializeField] private string _renderTextureName;
[SerializeField] private RenderSettings _renderSettings;

قم بإنشاء معرف لخاصية النسيج ومثيل MyRenderPass.

private RenderTargetHandle _renderTexture;
private MyRenderObjectsPass _renderPass;

public override void Create()
{
    _renderTexture.Init(_renderTextureName);

    _renderPass = new MyRenderObjectsPass(_renderTexture, _renderSettings.LayerMask, _renderSettings.OverrideMaterial);
}

في طريقة AddRendererPass ، نضيف تصريحنا إلى قائمة انتظار التنفيذ.

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

أتطلع قدما
. , .

يجب أن تكون نتيجة التمرير لمشهد المصدر كما يلي:


تصحيح الأخطاء
Frame Debug (Windows-Analysis-FrameDebugger).

تمرير طمس


الغرض من هذا المقطع هو طمس الصورة التي تم الحصول عليها في الخطوة السابقة وتعيينها إلى خاصية التظليل الشاملة.

للقيام بذلك ، سنقوم بنسخ النسيج الأصلي عدة مرات إلى مؤقت ، باستخدام تظليل طمس عليه. في هذه الحالة ، يمكن تقليل حجم الصورة الأصلية (إنشاء نسخة مخفضة) ، مما سيسرع العمليات الحسابية ولن يؤثر على جودة النتيجة.

لنقم بإنشاء فئة BlurPass الموروثة من ScriptableRenderPass.

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

public class BlurPass : ScriptableRenderPass
{
    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    { }
}

دعنا نحصل على متغيرات المصدر والهدف والقوام المؤقت (ومعرفها).

private int _tmpBlurRTId1 = Shader.PropertyToID("_TempBlurTexture1");
private int _tmpBlurRTId2 = Shader.PropertyToID("_TempBlurTexture2");

private RenderTargetIdentifier _tmpBlurRT1;
private RenderTargetIdentifier _tmpBlurRT2;

private RenderTargetIdentifier _source;
private RenderTargetHandle _destination;

يتم تعيين جميع معرفات RenderTexture من خلال Shader.PropertyID (). هذا لا يعني أنه في مكان ما يجب أن توجد خصائص التظليل بالضرورة.

أضف حقولًا للمعلمات المتبقية ، والتي نقوم بتهيئتها على الفور في المُنشئ.

private int _passesCount;
private int _downSample;
private Material _blurMaterial;

public BlurPass(Material blurMaterial, int downSample, int passesCount)
{
    _blurMaterial = blurMaterial;
    _downSample = downSample;
    _passesCount = passesCount;
}

_blurMaterial - مادة بها تظليل طمس.
_downSample - معامل لتقليل حجم النسيج
_passesCount - عدد التمريرات الضبابية المطلوب تطبيقها.

لإنشاء مواد مؤقتة ، قم بإنشاء واصف بكل المعلومات الضرورية عنه - الحجم والتنسيق والمزيد. سيتم قياس الارتفاع والحجم بالنسبة لموصف الكاميرا.

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
    var width = Mathf.Max(1, cameraTextureDescriptor.width >> _downSample);
    var height = Mathf.Max(1, cameraTextureDescriptor.height >> _downSample);
    var blurTextureDesc = new RenderTextureDescriptor(width, height, RenderTextureFormat.ARGB32, 0, 0);
سنقوم أيضًا بإنشاء المعرفات و RenderTexture المؤقت بأنفسهم.
    _tmpBlurRT1 = new RenderTargetIdentifier(_tmpBlurRTId1);
    _tmpBlurRT2 = new RenderTargetIdentifier(_tmpBlurRTId2);

    cmd.GetTemporaryRT(_tmpBlurRTId1, blurTextureDesc, FilterMode.Bilinear);
    cmd.GetTemporaryRT(_tmpBlurRTId2, blurTextureDesc, FilterMode.Bilinear);

نغير هدف العرض مرة أخرى ، لذا أنشئ نسيجًا مؤقتًا آخر وحدده كهدف.

    cmd.GetTemporaryRT(_destination.id, blurTextureDesc, FilterMode.Bilinear);
    ConfigureTarget(_destination.Identifier());
}

طمس


يمكن تنفيذ بعض مهام العرض باستخدام طرق ScriptableRenderContext الخاصة التي تقوم بتكوين الأوامر وإضافتها إليها. لتنفيذ أوامر أخرى ، ستحتاج إلى استخدام CommandBuffer ، والتي يمكن الحصول عليها من التجمع.
بعد إضافة الأوامر وإرسالها إلى السياق ، يجب إعادة المخزن المؤقت إلى التجمع.

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
    var cmd = CommandBufferPool.Get("BlurPass");
    ...
    context.ExecuteCommandBuffer(cmd);
    CommandBufferPool.Release(cmd);
}

سيكون التنفيذ النهائي لطريقة Execute () على النحو التالي.

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
    var cmd = CommandBufferPool.Get("BlurPass");

    if (_passesCount > 0)
    {
        cmd.Blit(_source, _tmpBlurRT1, _blurMaterial, 0);
        for (int i = 0; i < _passesCount - 1; i++)
        {
            cmd.Blit(_tmpBlurRT1, _tmpBlurRT2, _blurMaterial, 0);
            var t = _tmpBlurRT1;
            _tmpBlurRT1 = _tmpBlurRT2;
            _tmpBlurRT2 = t;
        }
        cmd.Blit(_tmpBlurRT1, _destination.Identifier());
    }
    else
        cmd.Blit(_source, _destination.Identifier());
    context.ExecuteCommandBuffer(cmd);
    CommandBufferPool.Release(cmd);
}

بليت
Blit() .

شادر


للتعتيم ، أنشئ تظليلًا بسيطًا يحسب لون البكسل مع مراعاة أقرب جيرانه (متوسط ​​قيمة اللون لخمس وحدات بكسل).

تظليل طمس
Shader "Custom/Blur"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}

SubShader
{
HLSLINCLUDE

#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};

struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
};

TEXTURE2D_X(_MainTex);
SAMPLER(sampler_MainTex);
float4 _MainTex_TexelSize;

Varyings Vert(Attributes input)
{
Varyings output;
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
output.uv = input.uv;
return output;
}

half4 Frag(Varyings input) : SV_Target
{
float2 offset = _MainTex_TexelSize.xy;
float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);

half4 color = SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2(-1, 1) * offset);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2( 1, 1) * offset);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2( 1,-1) * offset);
color += SAMPLE_TEXTURE2D_X(_MainTex, sampler_MainTex, input.uv + float2(-1,-1) * offset);

return color/5.0;
}

ENDHLSL

Pass
{
HLSLPROGRAM

#pragma vertex Vert
#pragma fragment Frag

ENDHLSL
}
}
}

لماذا لا ShaderGraph؟
ShaderGraph , 13 :)

أضف ممرًا إلى OutlineFeature


سيكون الإجراء مشابهًا لإضافة تصريحنا الأول. أولاً ، قم بإنشاء الإعدادات.

    [Serializable]
    public class BlurSettings
    {
        public Material BlurMaterial;
        public int DownSample = 1;
        public int PassesCount = 1;
    }

ثم الحقول.

[SerializeField] private string _bluredTextureName;
[SerializeField] private BlurSettings _blurSettings;
private RenderTargetHandle _bluredTexture;
private BlurPass _blurPass;

...

public override void Create()
{
    _bluredTexture.Init(_bluredTextureName);

    _blurPass = new BlurPass(_blurSettings.BlurMaterial, _blurSettings.DownSample, _blurSettings.PassesCount);
}

وتضاف إلى قائمة الانتظار للتنفيذ.

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

نتيجة النجاح:


تمرير مخطط تفصيلي


سيتم الحصول على الصورة النهائية مع حد الأشياء باستخدام جهاز تظليل. وستظهر نتيجة عمله أعلى الصورة الحالية على الشاشة.

أدناه هو رمز المرور بأكمله دفعة واحدة ، كما كل منطق في خطين.

public class OutlinePass : ScriptableRenderPass
{
    private string _profilerTag = "Outline";
    private Material _material;

    public OutlinePass(Material material)
    {
        _material = material;
    }

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        var cmd = CommandBufferPool.Get(_profilerTag);

        using (new ProfilingSample(cmd, _profilerTag))
        {
            var mesh = RenderingUtils.fullscreenMesh;
            cmd.DrawMesh(mesh, Matrix4x4.identity, _material, 0, 0);
        }

        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
    }
}

يعرض RenderingUtils.fullscreenMesh شبكة 1 في 1.

شادر


قم بإنشاء تظليل للحصول على المخطط التفصيلي. يجب أن يحتوي على خاصيتين عالميتين للنسيج. _OutlineRenderTexture و _OutlineBluredTexture لصورة الكائنات المحددة وإصدارها الباهت.

كود تظليل
Shader "Custom/Outline"
{
    Properties
    {
        _Color ("Glow Color", Color ) = ( 1, 1, 1, 1)
        _Intensity ("Intensity", Float) = 2
        [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend ("Src Blend", Float) = 1
        [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend ("Dst Blend", Float) = 0
    }
    
    SubShader
    {       
        HLSLINCLUDE
 
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        
        struct Attributes
        {
            float4 positionOS   : POSITION;
            float2 uv           : TEXCOORD0;
        };
        
        struct Varyings
        {
            half4 positionCS    : SV_POSITION;
            half2 uv            : TEXCOORD0;
        };
 
        TEXTURE2D_X(_OutlineRenderTexture);
        SAMPLER(sampler_OutlineRenderTexture);
 
        TEXTURE2D_X(_OutlineBluredTexture);
        SAMPLER(sampler_OutlineBluredTexture);
 
        half4 _Color;
        half _Intensity;
 
        Varyings Vertex(Attributes input)
        {
            Varyings output;
            output.positionCS = float4(input.positionOS.xy, 0.0, 1.0); 
            output.uv = input.uv;
            if (_ProjectionParams.x < 0.0) 
                output.uv.y = 1.0 - output.uv.y;    
            return output;      
        }
 
        half4 Fragment(Varyings input) : SV_Target
        {
            float2 uv = UnityStereoTransformScreenSpaceTex(input.uv);
            half4 prepassColor = SAMPLE_TEXTURE2D_X(_OutlineRenderTexture, sampler_OutlineRenderTexture, uv);
            half4 bluredColor = SAMPLE_TEXTURE2D_X(_OutlineBluredTexture, sampler_OutlineBluredTexture,uv);
            half4 difColor = max( 0, bluredColor - prepassColor);
            half4 color = difColor* _Color * _Intensity;
            color.a = 1;    
            return color;
        }
        
        ENDHLSL        
     
        Pass
        {
            Blend [_SrcBlend] [_DstBlend]
            ZTest Always    //  ,      
            ZWrite Off      //      
            Cull Off        //    
 
            HLSLPROGRAM
           
            #pragma vertex Vertex
            #pragma fragment Fragment        
 
            ENDHLSL         
        }
    }
}

, . Unity . , _ProjectionParams..

نتيجة تظليل صورتين تم الحصول عليهما مسبقًا:



أضف ممرًا إلى OutlineFeature


تشبه جميع الإجراءات التمريرات السابقة.

[SerializeField] private Material _outlineMaterial;
private OutlinePass _outlinePass;

public override void Create()
{
    ...
    _outlinePass = new OutlinePass(_outlineMaterial);
    ....
}

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

RenderPassEvent


يبقى الإشارة إلى متى سيتم استدعاء التمريرات التي تم إنشاؤها. للقيام بذلك ، يحتاج كل واحد منهم إلى تحديد المعلمة RovPassEvent.

قائمة الأحداث
Universal RP, .
BeforeRendering
BeforeRenderingShadows
AfterRenderingShadows
BeforeRenderingPrepasses
AfterRenderingPrePasses
BeforeRenderingOpaques
AfterRenderingOpaques
BeforeRenderingSkybox
AfterRenderingSkybox
BeforeRenderingTransparents
AfterRenderingTransparents
BeforeRenderingPostProcessing
AfterRenderingPostProcessing
AfterRendering

قم بإنشاء الحقل المناسب في OutlineFeature.

[SerializeField] private RenderPassEvent _renderPassEvent;

وسنشير إلى جميع المقاطع التي تم إنشاؤها.

public override void Create()
{
    ...
    _renderPass.renderPassEvent = _renderPassEvent;
    _blurPass.renderPassEvent = _renderPassEvent;
    _outlinePass.renderPassEvent = _renderPassEvent;
}

التخصيص


أضف طبقة مخطط تفصيلي وقم بتعيينها للكائنات التي نريد وضع دائرة حولها.

سنقوم بإنشاء وتكوين جميع الأصول اللازمة: UniversalRendererPipelineAsset و ForwardRendererData.



نتيجة


ستكون النتيجة لإطارنا الأصلي كما يلي!



إكمال


الآن سيكون مخطط الكائن مرئيًا دائمًا ، حتى من خلال الكائنات الأخرى. من أجل أن يأخذ تأثيرنا في الاعتبار عمق المشهد ، يجب إجراء العديد من التغييرات.

RenderObjectsPass


عند تحديد الغرض من العرض ، يجب أن نشير أيضًا إلى المخزن المؤقت العمق الحالي. قم بإنشاء الحقل والطريقة المناسبة.

public class MyRenderObjectsPass : ScriptableRenderPass
{
    ...
    private RenderTargetIdentifier _depth;

    public void SetDepthTexture(RenderTargetIdentifier depth)
    { _depth = depth; }
    ...
}

في طريقة Configure () ، حدد العمق في إعداد هدف التجسيد.

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
    cmd.GetTemporaryRT(_destination.id, cameraTextureDescriptor);
    ConfigureTarget(_destination.Identifier(), _depth);
    ConfigureClear(ClearFlag.Color, Color.clear);
}

الميزة الخارجية


في OutlineFeature ، سنقوم بتمرير MyRenderObjectsPass عمق المشهد الحالي.

public class OutlineFeature : ScriptableRendererFeature
{
    ...
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        var depthTexture = renderer.cameraDepth;
        _renderPass.SetDepthTexture(depthTexture);

        renderer.EnqueuePass(_renderPass);
        renderer.EnqueuePass(_blurPass);
        renderer.EnqueuePass(_outlinePass);
    }
    ...
}

UniversalRenderPipelineAsset


في UniversalRenderPipelineAsset المستخدمة ، حدد المربع المجاور لـ DepthTexture.


نتيجة


النتيجة باستثناء العمق:


النتيجة بناءً على العمق:



مجموع


ScriptableRendererFeature هي أداة مناسبة تمامًا لإضافة مقاطعك إلى RP.
في ذلك ، يمكنك بسهولة استبدال RenderObjectsPass واستخدامها في ScriptableRendererFeature أخرى. لست بحاجة إلى التعمق في تنفيذ Universal RP وتغيير رمزه لإضافة شيء ما.

ملاحظة


من أجل جعل الخوارزمية العامة للعمل مع ScriptableRendererFeature و ScriptableRenderPass أكثر وضوحًا ، وحتى لا تنمو المقالة كثيرًا ، حاولت عمداً إنشاء رمز مرور بسيط ، حتى على حساب عالميتها ومثاليتها.

المراجع


- شفرة المصدر تصل إلى gitlab
. أعماق الكوكب لعبة: نماذج والمشهد مأخوذ من البعثات لاندر
وقد اتخذ تنفيذ السكتة الدماغية التالية كأساس لالمثال - يوتيوب رابط
أمثلة تنفيذ RenderFeature الخاصة الوحدة - و تصل إلى جيثب .

سلسلة من الدروس حول إنشاء ScriptableRenderPipeline الخاص بك. بعد قراءة المنطق العام لـ RP و shaders ، يصبح الرابط إلى البرامج التعليمية واضحًا .

All Articles