Membuat Efek Garis Besar di Unity Universal Render Pipeline

Di Universal Render Pipeline, dengan membuat RendererFeature Anda sendiri, Anda dapat dengan mudah memperluas kemampuan rendering. Menambahkan pass baru ke pipeline rendering memungkinkan Anda membuat berbagai efek. Pada artikel ini, menggunakan ScriptableRendererFeature dan ScriptableRenderPass, kita akan membuat efek Garis besar objek dan mempertimbangkan beberapa fitur penerapannya.

Efek garis besar


Pendahuluan atau beberapa kata tentang Render Pipeline


Scriptable Render Pipeline memungkinkan Anda untuk mengontrol rendering gambar melalui skrip dalam C # dan mengontrol urutan pemrosesan objek, lampu, bayangan, dan banyak lagi. Universal Render Pipeline adalah Scriptable Render Pipeline yang dikembangkan oleh Unity dan dirancang untuk menggantikan RP bawaan lama.

Kemampuan Universal RP dapat diperluas dengan membuat dan menambahkan gambar Anda sendiri (ScriptableRendererFeature dan ScriptableRenderPass). Ini akan menjadi artikel saat ini. Ini akan bermanfaat bagi mereka yang akan beralih ke Universal RP dan, mungkin, membantu untuk lebih memahami pekerjaan ScriptableRenderPass'ov yang ada di Universal RP.

Artikel ini ditulis dalam Unity 2019.3 dan Universal RP 7.1.8.

Rencana aksi


Kita akan memahami bagaimana ScriptableRendererFeature dan ScriptableRenderPass bekerja pada contoh menciptakan efek goresan objek buram.

Untuk melakukan ini, buat ScriptableRendererFeature yang melakukan tindakan berikut:

  • menggambar objek yang ditentukan
  • objek yang ditarik kabur
  • memperoleh kontur objek dari gambar yang diperoleh pada lintasan sebelumnya

Sumber bingkai -

Dan urutan hasil yang harus kita capai:


Dalam perjalanan kerja, kita akan membuat shader, di properti global di mana hasil dari lintasan pertama dan kedua akan disimpan. Lulus terakhir akan menampilkan hasil shader itu sendiri di layar.

Properti global
, , Properties. — .

— . .

Buat OutlineFeature


ScriptableRendererFeature digunakan untuk menambahkan bagian render kustom (ScriptableRenderPass) ke Universal RP. Buat kelas OutlineFeature yang mewarisi dari ScriptableRenderFeature dan terapkan metode-metodenya.

using UnityEngine;
using UnityEngine.Rendering.Universal;

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

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

Metode Buat () digunakan untuk membuat dan mengonfigurasi lintasan. Dan metode AddRenderPasses () untuk menyuntikkan pass yang dibuat ke antrian rendering.

argumen AddRenderPasses ()
ScriptableRenderer — Universal RP. Universal RP Forward Rendering.

RenderingData — , , .

Sekarang mari kita mulai membuat pass rendering, dan kita akan kembali ke kelas saat ini setelah mengimplementasikan masing-masing.

Membuat objek lewat


Tugas dari bagian ini adalah untuk menggambar objek dari lapisan tertentu dengan penggantian material dalam properti tekstur global shader. Ini akan menjadi versi yang disederhanakan dari bagian RenderObjectsPass yang tersedia di Universal RP, dengan satu-satunya perbedaan dalam target (RenderTarget) di mana rendering akan dilakukan.

Buat kelas MyRenderObjectsPass yang diwarisi dari ScriptableRenderPass. Kami menerapkan metode Execute (), yang akan berisi semua logika bagian tersebut, serta mendefinisikan kembali metode 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)
        { }
    }
}

Metode Configure () digunakan untuk menentukan tujuan rendering dan membuat tekstur sementara. Secara default, target adalah target kamera saat ini, dan setelah menyelesaikan pass, itu akan ditunjukkan secara default lagi. Metode ini dipanggil sebelum logika dasar berjalan.

Merender penggantian target


Deklarasikan RenderTargetHandle untuk target rendering baru. Dengan menggunakannya, buat tekstur sementara dan indikasikan sebagai target. RenderTargetHandle berisi pengidentifikasi RenderTexture sementara yang digunakan. Ini juga memungkinkan Anda untuk mendapatkan RenderTargetIdentifier, yang digunakan untuk mengidentifikasi target render yang dapat ditetapkan, misalnya, sebagai RenderTexture, objek Tekstur, RenderTexture sementara atau built-in (digunakan oleh kamera saat merender bingkai).

Objek RenderTargetHandle akan dibuat di OutlineFeature dan diteruskan ke pass kami saat dibuat.

private RenderTargetHandle _destination;

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

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

Metode GetTemporaryRT () membuat RenderTexture sementara dengan parameter yang diberikan dan menetapkannya sebagai properti shader global dengan nama yang ditentukan (nama akan ditetapkan dalam fitur).

Hapus RenderTexture
ReleaseTemporaryRT() RenderTexture. Execute() FrameCleanup.
, RenderTexture, , .

Untuk membuat RenderTexture sementara kami menggunakan deskriptor kamera saat ini yang berisi informasi tentang ukuran, format, dan parameter lain dari target kamera.

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

Tujuan dari target dan pembersihannya hanya boleh terjadi di Configure () menggunakan metode ConfigureTarget () dan ClearTarget ().

Memberikan


Kami tidak akan mempertimbangkan rendering secara detail, karena ini bisa membawa kita jauh dan jauh dari topik utama. Untuk rendering, kita akan menggunakan metode ScriptableRenderContext.DrawRenderers (). Buat pengaturan untuk rendering hanya objek buram hanya dari lapisan yang ditentukan. Layer mask akan diteruskan ke konstruktor.

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

Sangat singkat tentang parameternya
CullingResults — ( RenderingData)
FilteringSettings — .
DrawingSettings — .
RenderStateBlock — , (, ..)

Tentang RenderObjectsPass yang telah selesai di UniversalRP
, . . RenderObjectsPass, Universal RP, . RenderFeature - :)

Penggantian Bahan


Kami mendefinisikan ulang bahan yang digunakan untuk rendering, karena kami hanya membutuhkan kontur objek.

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

Shader untuk rendering


Buat material shader di ShaderGraph yang akan digunakan saat menggambar objek dalam pass saat ini.


Tambahkan bagian ke OutlineFeature


Kembali ke OutlieFeature. Pertama, buat kelas untuk pengaturan bagian kita.

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

Nyatakan bidang untuk pengaturan MyRenderPass dan nama properti tekstur global yang digunakan sebagai target rendering oleh pass kami.

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

Buat pengenal untuk properti tekstur dan turunan dari MyRenderPass.

private RenderTargetHandle _renderTexture;
private MyRenderObjectsPass _renderPass;

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

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

Dalam metode AddRendererPass, kami menambahkan pass kami ke antrian eksekusi.

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

Melihat ke depan
. , .

Hasil pass untuk adegan sumber harus sebagai berikut:


Debugging
Frame Debug (Windows-Analysis-FrameDebugger).

Blur pass


Tujuan dari bagian ini adalah untuk mengaburkan gambar yang diperoleh pada langkah sebelumnya dan mengaturnya ke properti global shader.

Untuk melakukan ini, kami akan menyalin tekstur asli beberapa kali ke yang sementara, menggunakan blur shader di atasnya. Dalam hal ini, gambar asli dapat diperkecil ukurannya (buat salinan yang diperkecil), yang akan mempercepat perhitungan dan tidak akan mempengaruhi kualitas hasil.

Mari kita buat kelas BlurPass yang diwarisi dari ScriptableRenderPass.

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

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

Mari kita dapatkan variabel untuk sumber, target, dan tekstur sementara (dan ID mereka).

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

private RenderTargetIdentifier _tmpBlurRT1;
private RenderTargetIdentifier _tmpBlurRT2;

private RenderTargetIdentifier _source;
private RenderTargetHandle _destination;

Semua ID untuk RenderTexture ditetapkan melalui Shader.PropertyID (). Ini tidak berarti bahwa di suatu tempat sifat shader seperti itu harus ada.

Tambahkan bidang untuk parameter yang tersisa, yang segera kami inisialisasi dalam konstruktor.

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

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

_blurMaterial - material dengan blur shader.
_downSample - koefisien untuk mengurangi ukuran tekstur
_passesCount - jumlah blur yang diterapkan.

Untuk membuat tekstur sementara, buat deskriptor dengan semua informasi yang diperlukan tentang itu - ukuran, format, dan lainnya. Tinggi dan ukuran akan diskalakan relatif terhadap deskriptor kamera.

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);
Kami juga akan membuat pengidentifikasi dan RenderTexture sementara itu sendiri.
    _tmpBlurRT1 = new RenderTargetIdentifier(_tmpBlurRTId1);
    _tmpBlurRT2 = new RenderTargetIdentifier(_tmpBlurRTId2);

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

Kami mengubah target rendering lagi, jadi buat tekstur sementara lainnya dan tentukan sebagai target.

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

Mengaburkan


Beberapa tugas rendering dapat dilakukan menggunakan metode ScriptableRenderContext khusus yang mengkonfigurasi dan menambahkan perintah untuk itu. Untuk menjalankan perintah lain, Anda harus menggunakan CommandBuffer, yang dapat diperoleh dari kumpulan.
Setelah menambahkan perintah dan mengirimkannya ke konteks, buffer harus dikembalikan ke kolam.

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

Implementasi akhir metode Execute () adalah sebagai berikut.

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
Blit() .

Shader


Untuk mengaburkan, buat shader sederhana yang akan menghitung warna piksel dengan mempertimbangkan tetangga terdekatnya (nilai warna rata-rata lima piksel).

Blur shader
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
}
}
}

Kenapa tidak ShaderGraph?
ShaderGraph , 13 :)

Tambahkan bagian ke OutlineFeature


Prosedurnya akan mirip dengan menambahkan pass pertama kami. Pertama, buat pengaturan.

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

Lalu ladang.

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

Dan tambahkan ke antrian untuk eksekusi.

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

Lulus hasil:


Garis batas lulus


Gambar akhir dengan goresan objek akan diperoleh menggunakan shader. Dan hasil karyanya akan ditampilkan di atas gambar saat ini di layar.

Di bawah ini adalah seluruh kode sandi sekaligus, sebagai semua logika ada dalam dua baris.

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 mengembalikan mesh 1 per 1.

Shader


Buat shader untuk mendapatkan garis besar. Itu harus mengandung dua sifat tekstur global. _OutlineRenderTexture dan _OutlineBluredTexture untuk gambar objek yang ditentukan dan versi buramnya.

kode shader
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..

Hasil shader untuk dua gambar yang diperoleh sebelumnya:



Tambahkan bagian ke OutlineFeature


Semua aksi mirip dengan operan sebelumnya.

[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


Masih menunjukkan kapan pass yang dibuat akan dipanggil. Untuk melakukan ini, masing-masing dari mereka perlu menentukan parameter renderPassEvent.

Daftar acara
Universal RP, .
BeforeRendering
BeforeRenderingShadows
AfterRenderingShadows
BeforeRenderingPrepasses
AfterRenderingPrePasses
BeforeRenderingOpaques
AfterRenderingOpaques
BeforeRenderingSkybox
AfterRenderingSkybox
BeforeRenderingTransparents
AfterRenderingTransparents
BeforeRenderingPostProcessing
AfterRenderingPostProcessing
AfterRendering

Buat bidang yang sesuai di OutlineFeature.

[SerializeField] private RenderPassEvent _renderPassEvent;

Dan kami akan menunjukkannya ke semua bagian yang dibuat.

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

Kustomisasi


Tambahkan layer Outline dan atur untuk objek yang ingin kita lingkari.

Kami akan membuat dan mengonfigurasi semua aset yang diperlukan: UniversalRendererPipelineAsset dan ForwardRendererData.



Hasil


Hasil untuk bingkai asli kami adalah sebagai berikut!



Penyelesaian


Sekarang garis besar objek akan selalu terlihat, bahkan melalui objek lain. Agar efek kami memperhitungkan kedalaman adegan, beberapa perubahan harus dilakukan.

RenderObjectsPass


Saat menentukan tujuan render kami, kami juga harus menunjukkan buffer kedalaman saat ini. Buat bidang dan metode yang sesuai.

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

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

Dalam metode Configure (), tentukan kedalaman dalam menetapkan target render.

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

Fitur garis besar


Di OutlineFeature, kami akan melewati MyRenderObjectsPass kedalaman adegan saat ini.

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


Di UniversalRenderPipelineAsset yang digunakan, centang kotak di sebelah DepthTexture.


Hasil


Hasil tidak termasuk kedalaman:


Hasil berdasarkan kedalaman:



Total


ScriptableRendererFeature adalah alat yang cukup nyaman untuk menambahkan bagian Anda ke RP.
Di dalamnya, Anda dapat dengan mudah mengganti RenderObjectsPass's dan menggunakannya di ScriptableRendererFeature lainnya. Anda tidak perlu mempelajari lebih jauh tentang penerapan RP Universal dan mengubah kodenya untuk menambahkan sesuatu.

PS


Untuk membuat algoritma umum bekerja dengan ScriptableRendererFeature dan ScriptableRenderPass lebih jelas, dan agar artikel tidak tumbuh terlalu banyak, saya sengaja mencoba membuat kode sandi sederhana, bahkan dengan merusak universalitas dan optimalitasnya.

Referensi


Kode sumber adalah tautan ke gitlab.
Model dan adegan diambil dari Lander Missions: planet depths game.
Implementasi pukulan berikut diambil sebagai dasar dari contoh - tautan youtube
contoh implementasi RenderFeature milik Unity sendiri - tautan ke github .

Serangkaian pelajaran tentang cara membuat ScriptableRenderPipeline Anda sendiri. Setelah membaca logika umum RP dan shader, tautan ke tutorial menjadi jelas .

All Articles