日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity SRP自定义渲染管线 -- 2.Custom Shaders

發布時間:2023/12/13 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity SRP自定义渲染管线 -- 2.Custom Shaders 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本章將接著上一篇文章,在初步實現一個渲染管線后來創建自定義的shader。上一篇文章的鏈接

?https://blog.csdn.net/yinfourever/article/details/90516602。在本章中,將完成以下內容:

  • 寫一個HLSL Shader
  • 定義constant buffer(常量緩沖區)
  • 使用?Render Pipeline Core Library
  • 支持動態合批和GPU instancing

本章最后實現的效果如下圖,多個不同顏色球體,只需要一個draw call

256個球體,只需要一個draw call

1.Custom Unlit Shader

1.1Creating a Shader

創建一個Shader,刪掉所有自帶的默代碼,寫入以下代碼。

將上一章創建的Unlit Opaque material指定為使用我們創建的這個新shader。

1.2 HLSL

Unity 新的SRP渲染管線使用HLSL,所以我們自定義的渲染管線也使用HLSL,我們使用HLSLPROGRAM?and?ENDHLSL

?一個Shader至少應該包含vertex函數(頂點shader部分)和fragment函數(片元shader部分)。我們命名UnlitPassVertex?for the vertex function and?UnlitPassFragment?for the other。但具體代碼我們不在這個文件中實現,而是分離到一個單獨的hlsl文件中,在這里include進來。

?在生成的Unlit.hlsl文件中,我們使用#ifndef來避免多次引用。之后,我們聲明Vertex函數的輸入參數結構體和輸出參數結構體

在vertex shader中,講輸入參數傳遞給輸出參數,在fragment shader中,返回1,這樣就完成了一個最簡單的shader架構,雖然參數還是有錯誤的(position參數沒有進行坐標變換處理直接從vertex shader傳入到了fragment shader)?

1.3?Transformation Matrices

從模型空間到裁剪空間需要兩步轉換,我們先用unity_ObjectToWorld矩陣轉換到世界坐標空間,再用unity_MatrixVP矩陣轉換到裁剪空間。

?我們可以通過一個小技巧來提高運算的效率,將input的position信息,從三維向量補齊成四維,可以大大加快運算效率。

1.4 Constant Buffers

Unity沒有直接提供MVP矩陣二是拆開成提供兩個矩陣M和VP是因為VP矩陣在一幀中不會改變,可以重復利用。Unity將M矩陣和VP矩陣存入Constant Buffer中以提高運算效率,M矩陣存入的buffer為UnityPerDraw buffer, 也就是針對每個物體的繪制不會改變。VP矩陣則存入的是UnityPerFrame buffer,即每一幀VP矩陣并不會改變。Constant Buffer并不是所有平臺都支持,目前OpenGL就不支持。

使用cbuffer keyworld來引入Constant buffer,constant buffer中還有很多其他的數據,暫時我們用不到,只使用這兩個矩陣

1.5 Core Library

? 因為constant buffer并不是支持所有平臺,所以我們使用宏來代替直接cbuffer keyword,使用CBUFFER_START 和CBUFFER_END?這兩個宏需要使用Core Library,通過package manager可以安裝。? 安裝成功后,在hlsl代碼中引入common.hlsl就可以使用這兩個宏了。

1.6 Compilation Target Level

我們使用#pragma target?指定shader level為3.5 代替默認的2.5,我們不支持OpenGL ES2那些老設備。

?

1.7 Folder Structure

我們調整下文件目錄結構,使引用的文件都放入ShaderLibrary文件夾

2?Dynamic Batching

?現在使用我們新創建的這個shader去渲染大量球體時,可以看到每個球體各自占用一個draw call。在fram debugger中我們可以看到提示沒有合批的原因是我們沒有開啟動態合批。

?

我們根據提示,即使打開了player setting中的Dynamic Batching option選項,依然不會有效果,這是因為player setting中設置的是unity默認的渲染管線,而我們現在使用的是自定義的渲染管線,所以需要代碼手動控制我們自己的這個管線開啟合批功能。

開啟后,我們發現合批依然沒有成功,根據提示,是因為物體的定點數太多,超過了動態合批的限制300。?

把球體換成頂點數很少的方體,動態合批就成功了,可以看到只有一個draw call?

2.2 Colors

當使用不同的material時,是不能動態合批的,為了證明這一點,我們加入color屬性。

?將color屬性存入constant buffer中

復制一份之前的material,將復制的material中的color屬性設置為其他顏色,我們可以看到合批結果為4個draw call。?這是因為對于每個material至少會產生一個draw call,unity中為了避免overdraw,會根絕空間位置信息分組渲染,對于每個material,往往會多于一個draw call。

debugger中可以看到提示不能合批的信息為使用了不同的material。?

2.3 Optional Batching

動態合批是一個提升渲染效率的好方法,但是并不是所有時候都有效,甚至會拖慢渲染效率。當場景中并不存在大量使用相同material的小mesh的時候,動態合批就沒什么用了,反而每幀關于動態合批的運算會降低效率。我們在自定義的渲染管線中加入一個bool值,來作為是否開啟動態合批的開關。

?在MyPipeline的構造函數中,傳入是否開啟動態合批的bool值

?在render函數中根據drawFlags設置動態合批是否開啟

?3 GPU Instancing

除了動態合批外,GPU Instancing也可以用于減少draw call。通過GPU Instancing,CPU告訴GPU在一個draw call中,渲染特定的mesh和material的組合多次。這使得使用相同mesh和material的物體渲染時不再像動態合批需要重新組成一個新的后批后的大mesh,這也就移除了對mesh大小的限制。

3.1?Optional Instancing

和之前的動態合批一樣,我們也引入一個bool值控制是否開啟GPU Instancing

?

?3.2?Material Support

渲染管線開啟了GPU Instancing還不夠,還需要使得material支持GPU Instancing,通過添加#pragma multi_compile_instancing來產生shader 變體,一個支持GPU Instancing一個不支持。在Editor中material的設置中可以看到是否開啟GPU Instancing選項。

3.3?Shader Support

當GPU Instancing開啟時,GPU會使用相同的constant data渲染同一個mesh多次。但是因為每個物體的位置不同,所以M矩陣就不同。為了解決這個問題,會在constant buffer中存入一個數組,用于存儲待渲染的物體的M矩陣。每一個instance根據自身的index,從數組中取用數據。

我們使用unity提供的UNITY_MATRIX_M這個宏,在core library中的這個宏可以支持instancing,在使用矩陣數組的時候可以取出對應的矩陣

?使用該宏需要引用UnityInstancing.hlsl這個文件。

?當時用Instancing時,物體的index或被gpu傳入頂點數據中,UNITY_MATRIX_M這個宏需要使用這個index數據,我們將Index數據加入到Vertex shader函數的輸入結構體中,在Vertex Shader的處理函數中使用UNITY_SETUP_INSTANCE_ID?這個宏來使其生效。

?

?除了?object-to-world matrices, 默認?world-to-object矩陣也存在了constant buffer中。但是目前我們沒有需求使用他們,所以可以通過#pragma instancing_options assumeuniformscaling去掉他們提高性能?

3.4 Many Colors

之前我們想實現一個場景中多個顏色的物體只能使用多個material,但是如果使用類似存儲M矩陣的方式操作color屬性,就可以實現用一個matrial渲染多種顏色物體。

首先創建一個腳本,包含要使用的color數據。

?其次通過MaterialPropertyBlock函數創建一個MaterialPropertyBlock實體,通過它來設置material中的顏色。這些操作寫入了OnValidate函數中,使得在editor中可以看到顏色變化效果。

?通過去掉局部變量,可以優化效率。

這時就可以用一個material渲染多種顏色了,但是到目前為止,每個物體都會產生draw call?

?3.5?Per-Instance Colors

像M矩陣處理的方式一樣,我們也將color屬性以數組形式存入constant buffer中,在使用時通過index從數組中取出。

不同于M矩陣Unity已經幫我們處理好了,color屬性需要我們自己手動創建constant buffer并存入其中

在vertex shader函數的輸出中,也要把index數據傳遞到fragment shader函數中。在fragment shdare的處理函數中,根據index取用color數據

這時,我們只需使用一個material就能實現多顏色物體的渲染了,并且可以實現合并draw call。但是要注意的是constant buffer能存儲多少數據是有限制的,最大數量的Instance取決于每個instance需要多少數據,除此之外,不同平臺最大限制也不同。同時instance draw call的合并依然也要求需要是相同的mesh和material,比如下圖中的方形和圓形雖然使用相同的material,但因為mesh不同所以依然需要不同的draw call進行渲染。

?

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Unity SRP自定义渲染管线 -- 2.Custom Shaders的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。