unity 天空盒_Unity自定义可编程渲染管线(SRP)(二)——编写第一个自定义SRP
一句話描述,我們可以把SRP分解成兩個(gè)部分,分別是SRP Asset,SRP Instance。
SRP Asset
SRP Asset是一個(gè)Unity Asset文件,用來存儲(chǔ)渲染管線的特定配置信息,包含的信息有:游戲物體是否應(yīng)該投射陰影;使用什么樣的著色器質(zhì)量級(jí)別;影子距離;默認(rèn)材質(zhì)配置。
此外還可以保存所有像在配置中保存和控制的信息和unity需要序列化的數(shù)據(jù)。SRP Asset定義了SRP的類型和所有配置數(shù)據(jù)的設(shè)置。
SRP Instance
SRP Instance是實(shí)際執(zhí)行渲染的類,當(dāng)unity發(fā)現(xiàn)工程使用SRP的時(shí)候,就會(huì)尋找當(dāng)前使用的SRP Asset并請(qǐng)求一個(gè)渲染實(shí)例,該實(shí)例必須包含一個(gè)Render函數(shù),
渲染實(shí)例表示管道配置。在渲染調(diào)用中,Unity可以執(zhí)行如下操作:
- 清理framebuffer。
 - 執(zhí)行場景清理。
 - 渲染游戲?qū)ο蠹?/li>
 - 從一個(gè)幀緩沖區(qū)到另一個(gè)幀緩沖區(qū)執(zhí)行位塊傳輸;
 - 渲染陰影。
 - 應(yīng)用后處理效果。
 
第一個(gè)SRP Asset案例
SRP Asset實(shí)際是一個(gè)繼承RenderPipelineAsset接口的類,需要實(shí)現(xiàn)CreatePipeline接口。當(dāng)unity首次執(zhí)行渲染命令的時(shí)候,則會(huì)調(diào)用這個(gè)接口并返回一個(gè)可用的渲染實(shí)例。
下面所展示的就是一個(gè)簡單的SRP Asset類。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering;[CreateAssetMenu(menuName = "Rendering/Custom Render Pipeline")] public class CustomRenderPipelineAsset : RenderPipelineAsset {protected override RenderPipeline CreatePipeline(){return new CustomRenderPipeline();} }SRP Instance
在上面的敘述中,CustomRenderPipelineAsset類重寫了CreatePipeline方法,并返回了一個(gè)CustomRenderPipeline實(shí)例對(duì)象,該對(duì)象則是unity SRP渲染的入口。CustomRenderPipeline是一個(gè)繼承RenderPipeline的類,而且必須實(shí)現(xiàn)虛函數(shù)Render,該函數(shù)包含了兩個(gè)參數(shù):
ScriptableRenderContext context:是一個(gè)command buffer對(duì)象,可以向其輸入您想執(zhí)行的渲染指令。
Camera[] cameras:一系列用于渲染的相機(jī)。
先介紹一個(gè)簡單的例子:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering;public class CustomRenderPipeline : RenderPipeline {public CameraRender cameraRender = new CameraRender();public CustomRenderPipeline(){}protected override void Render(ScriptableRenderContext context, Camera[] cameras){foreach(var camera in cameras){cameraRender.Render(context, camera);}} }如上所示,我們把渲染的處理邏輯封裝到CameraRender類里,對(duì)每一個(gè)場景中的活動(dòng)相機(jī)進(jìn)行單獨(dú)處理。
下一步先定義CameraRender類:
using UnityEngine; using UnityEngine.Rendering;public class CameraRenderer {ScriptableRenderContext context;Camera camera;public void Render (ScriptableRenderContext context, Camera camera) {this.context = context;this.camera = camera;} }然后正式定義Render函數(shù),實(shí)現(xiàn)我們的自定義渲染管線。
在Render函數(shù)中是要繪制所有Camera可見的幾何體,我們聲明一個(gè)函數(shù)DrawVisibleGeometry用于處理一些特殊的工作,繪制天空盒也是在這個(gè)方法中處理,不過我們還另外聲明了一個(gè)方法來完成這個(gè)工作。代碼如下:
public void Render (ScriptableRenderContext context, Camera camera) {this.context = context;this.camera = camera;DrawVisibleGeometry();}void DrawVisibleGeometry () {context.DrawSkybox(camera);}然而這樣仍不能顯示天空盒,這是因?yàn)槲覀冋{(diào)用DrawSkybox只是把命令添加到context的緩存隊(duì)列里,還需要調(diào)用context.Submit()方法才會(huì)正式執(zhí)行緩存隊(duì)列里面的命令。
public void Render (ScriptableRenderContext context, Camera camera) {this.context = context;this.camera = camera;DrawVisibleGeometry();Submit();}void Submit () {context.Submit();}最后我們可以看到下面的效果。
但是,這個(gè)渲染結(jié)果還是有問題,當(dāng)我們調(diào)整相機(jī)的角度或位置時(shí),渲染結(jié)果并沒有發(fā)生變化,這是因?yàn)槲覀儾]有將視角投影矩陣傳遞給Command Buffer。這個(gè)變換矩陣在Unity Shader中是unity_MatrixVP。當(dāng)我們打開frame debugger面板,選擇一個(gè)draw call,這個(gè)變量就會(huì)顯示在右側(cè)的監(jiān)視板上。當(dāng)前,不管我們?cè)趺凑{(diào)整相機(jī)的姿態(tài),這個(gè)變量都會(huì)保持不變,通過調(diào)用SetupCameraProperties方法可以構(gòu)建這個(gè)矩陣。如下所示
但是,這個(gè)渲染結(jié)果還是有問題,當(dāng)我們調(diào)整相機(jī)的角度或位置時(shí),渲染結(jié)果并沒有發(fā)生變化,這是因?yàn)槲覀儾]有將視角投影矩陣傳遞給Command Buffer。這個(gè)變換矩陣在Unity Shader中是unity_MatrixVP。當(dāng)我們打開frame debugger面板,選擇一個(gè)draw call,這個(gè)變量就會(huì)顯示在右側(cè)的監(jiān)視板上。當(dāng)前,不管我們?cè)趺凑{(diào)整相機(jī)的姿態(tài),這個(gè)變量都會(huì)保持不變,通過調(diào)用SetupCameraProperties方法可以構(gòu)建這個(gè)矩陣。如下所示
public void Render (ScriptableRenderContext context, Camera camera) {this.context = context;this.camera = camera;Setup();DrawVisibleGeometry();Submit(); }void Setup () {context.SetupCameraProperties(camera); }2. Command buffer
前面已經(jīng)提到,context只有在調(diào)用Submit方法時(shí)才會(huì)執(zhí)行渲染指令,在這之前都是將指令添加到渲染隊(duì)列中。像天空盒可以通過專業(yè)的方法添加指令,但是像其他任務(wù)則不能通過這樣添加,需要通過一個(gè)單獨(dú)的command buffer間接添加。因此我們需要另建一個(gè)buffer用來繪制其他的幾何對(duì)象。
const string bufferName = "Render Camera";CommandBuffer buffer = new CommandBuffer {name = bufferName };在項(xiàng)目開發(fā)中,profiler是一個(gè)非常強(qiáng)大和有用的工具,這里我們可以把我們的Command Buffer加入到profiler樣例中,這個(gè)樣例可以同時(shí)顯示在profiler和frame debugger面板,方法是在適當(dāng)?shù)奈恢谜{(diào)用BeginSample和EndSample方法,在我們的案例中將會(huì)分別放在Setup()方法和Submit()方法的開頭位置。BeginSample和EndSample方法必須使用相同的字符串參數(shù)作為樣例的名字,這里使用的是buffer的名字。
void Setup () {buffer.BeginSample(bufferName);context.SetupCameraProperties(camera); }void Submit () {buffer.EndSample(bufferName);context.Submit(); }執(zhí)行Command Buffer中的命令只需要調(diào)用context的ExecuteCommandBuffer方法,并把buffer作為參數(shù)傳遞進(jìn)去。
void Setup () {buffer.BeginSample(bufferName);ExecuteBuffer();context.SetupCameraProperties(camera); }void Submit () {buffer.EndSample(bufferName);ExecuteBuffer();context.Submit(); }void ExecuteBuffer () {context.ExecuteCommandBuffer(buffer);buffer.Clear(); }這時(shí)候打開frame debugger我們就可以看到渲染的案例如下:
3. 清除渲染目標(biāo)
不管我們想要繪制什么東西,最終都會(huì)渲染到相機(jī)的渲染目標(biāo)中。相機(jī)的渲染目標(biāo)一般是幀緩存區(qū),也可以是渲染紋理。渲染目標(biāo)一般不會(huì)自動(dòng)清除,也就是說之前渲染的結(jié)果會(huì)一直保存在渲染目標(biāo)中,這樣會(huì)干擾我們渲染新的圖像。為了保證正確的渲染,我們必須清除渲染目標(biāo),以擺脫其舊的內(nèi)容。通過調(diào)用ClearRenderTarget方法可以實(shí)現(xiàn)這個(gè)目的。
ClearRenderTarget函數(shù)需要至少三個(gè)參數(shù),前兩個(gè)參數(shù)指定是否清理顏色緩存和深度緩存,一般都設(shè)為true,第三個(gè)參數(shù)指定清理緩存的顏色,這里使用Color.clear。
void Setup () {buffer.BeginSample(bufferName);buffer.ClearRenderTarget(true, true, Color.clear);ExecuteBuffer();context.SetupCameraProperties(camera); }打開frame debugger,可以看到清理渲染目標(biāo)活動(dòng)對(duì)應(yīng)了一個(gè)叫DrawGL的樣例。而且這個(gè)案例被鑲嵌在另一個(gè)Render Camera樣例中,這是因?yàn)?ClearRenderTarget將清除任務(wù)包裝在了一個(gè)使用Command buffer的名字命名的樣例中。為了避免這種情況,可以調(diào)整一下清除目標(biāo)的代碼的位置。
void Setup () {context.SetupCameraProperties(camera);buffer.ClearRenderTarget(true, true, Color.clear);buffer.BeginSample(bufferName);ExecuteBuffer();//context.SetupCameraProperties(camera); }現(xiàn)在我們可以看到Clear(color+Z+stencil),這表明顏色跟深度緩沖都沒清除了,stencil數(shù)據(jù)是同一緩存區(qū)的一部分。
總結(jié)
以上是生活随笔為你收集整理的unity 天空盒_Unity自定义可编程渲染管线(SRP)(二)——编写第一个自定义SRP的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: LTE调制方式和编码速率
 - 下一篇: zabbix3监控ESXI主机