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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

unity 如何获取到屏幕中间_Unity通用渲染管线Shader日志输出工具

發(fā)布時間:2023/12/15 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 unity 如何获取到屏幕中间_Unity通用渲染管线Shader日志输出工具 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這是侑虎科技第700篇文章,感謝作者鄒春毅供稿。歡迎轉(zhuǎn)發(fā)分享,未經(jīng)作者授權(quán)請勿轉(zhuǎn)載。如果您有任何獨到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)

作者主頁:https://www.zhihu.com/people/zou-chun-yi-45,作者也是U Sparkle活動參與者,UWA歡迎更多開發(fā)朋友加入U Sparkle開發(fā)者計劃,這個舞臺有你更精彩!


在Unity開發(fā)過程中,如果需要輸出調(diào)試日志只需要在C#中調(diào)用Debug.Log即可,但是Shader由于硬件結(jié)構(gòu)上的問題無法像C#一樣輕松地輸出調(diào)試日志。因此在Shader編碼過程中調(diào)試就成了一個很困難的事情,比如想知道VS中某個中間變量結(jié)果是否正確等等。我寫的這個工具就是希望能把Shader中的變量能像C#一樣輸出,解決調(diào)試中遇到的困難。當(dāng)然原理與C#中的日志輸出是完全不同的,針對不同的Shader解決方法也是不同的。一、開發(fā)環(huán)境Unity 2019.3+URP支持的調(diào)試Shader類型:VertexShader、FragmentShader、ComputeShader。二、VertexShader中的日志輸出頂點著色器與像素著色器是兩個必須的著色器,但是不要忘記,這兩者還有一個可選的著色器:幾何著色器(Geometry Shader)。關(guān)于幾何著色器就不詳細(xì)闡述了,大家可以自行查閱相關(guān)資料。由于幾何著色器可以為模型添加新的頂點,并且還沒有經(jīng)過光柵化,因此我們可以將頂點著色器中需要輸出的變量存儲到紋理通道中,然后在幾何著色階段利用新增的頂點將這個變量的內(nèi)容畫到屏幕上。1. ?下面直接介紹使用方法:以調(diào)試Lit.shader為例(工程中參見LitDebugVertex.shader)。先看下效果:

對紅圈內(nèi)的模型Shader進行日志輸出

調(diào)試過程中的模型會以Wireframe的模式渲染,點擊某一個頂點會輸出調(diào)試的日志2. ?對需要日志輸出的Shader進行簡單改造1)在原先Fragment聲明的地方插入如下代碼,然后注釋掉原先的聲明。

#pragma vertex LitPassVertex

//#pragma fragment LitPassFragment

//1、VertexDebug: 在#pragma fragment xxx后前添加,同時注釋掉此行

#pragma geometry geom //關(guān)閉調(diào)試注釋此行

#pragma fragment debugFrag //關(guān)閉調(diào)試注釋此行

#define VERTEX_DEBUG_ENABLE //關(guān)閉調(diào)試注釋此行

#define VERTEX_DEBUG_INDEX 0 //選取的頂點所在三角形index(0,1,2,3-表示全部檢測)

#include "Packages/com.seasun.graphics/Shaders/Debug/VertexDebug.hlsl"

如果想取消調(diào)試,恢復(fù)到正常的渲染模式,可以注釋掉上述標(biāo)記的3行代碼,并恢復(fù)原先的Fragment函數(shù)聲明。2)因為替換了Fragment函數(shù),所以需要修改原先Vertex函數(shù)的名稱。

//2、VertexDebug: 修改Vert函數(shù)分布傳入4個參數(shù):返回類型,函數(shù)名,數(shù)據(jù)結(jié)構(gòu)體名稱,結(jié)構(gòu)體實例

VERTEX_DEBUG_FUN(Varyings, LitPassVertex, Attributes, input)

//Varyings LitPassVertex(Attributes input)

{

Varyings output = (Varyings)0;

float4 mrtValue = 0;

UNITY_SETUP_INSTANCE_ID(input);

UNITY_TRANSFER_INSTANCE_ID(input, output);

UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

3)初始化

UNITY_SETUP_INSTANCE_ID(input);

UNITY_TRANSFER_INSTANCE_ID(input, output);

UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);

//3、VertexDebug: 初始化,傳遞投影后的坐標(biāo)值

VERTEX_DEBUG_INIT(vertexInput.positionCS)

4)添加想要輸出的變量

#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF)

output.shadowCoord = GetShadowCoord(vertexInput);

#endif

output.positionCS = vertexInput.positionCS;

//4、VertexDebug: 根據(jù)屏幕采點,自動選擇頂點(可選,也可以自己填寫)

if (VERTEX_DEBUG_AUTO_JUDGE)

{

//5、VertexDebug: 輸入想要調(diào)試輸出的變量,支持xy2個參數(shù)

VERTEX_DEBUG_VALUE(xy, input.lightmapUV.xy)

}

由于Shader是并行執(zhí)行,在調(diào)試期間會有多個頂點執(zhí)行同樣的一段代碼,因此這里有兩種方法來指定某一個頂點輸入。一種是像示例中的一樣使用這個宏,然后在場景的運行的時候按住Alt,用鼠標(biāo)點擊模型的頂點,然后就會輸出選中頂點的日志(如果游戲頂點比較密集,會輸出多個頂點的日志)。另一種方式是自己設(shè)置約束,在Shader中指定某一個頂點輸出日志。5)改寫返回

//6、VertexDebug: 將原始輸出結(jié)構(gòu)放入宏中

VERTEX_DEBUG_OUTPUT(output)

//return output;

3. ?開始調(diào)試在調(diào)試場景中,找個任意一個GameObject,掛載VertexDebug.cs腳本,然后啟動游戲。按住Alt,用鼠標(biāo)點擊待調(diào)試模型的頂點。調(diào)節(jié)攝像機的視角,使待調(diào)試的頂點進行放大,避免其他頂點的干擾。三、FragmentShader中的日志輸出像素著色器不像頂點著色器那樣,中間有幾何著色器輔助輸出,因此像素著色器中的調(diào)試信息只能存儲到顏色緩沖區(qū)中。但是存儲到顏色緩沖區(qū)中的內(nèi)容不僅會影響最終的渲染結(jié)果,也會受到后期等因素的影響。假如我們使用MRT,就可以解決上述問題。Unity中的MRT可參見延遲渲染:https://docs.unity3d.com/Manual/RenderTech-DeferredShading.html1. ?對URP進行改造URP由于使用正向渲染,因此并沒有啟用MRT,所以需要稍微改造,已到達(dá)支持的目的。具體內(nèi)容這里就不闡述了,可以在工程中搜索宏FRAGMENG_DEBUG查看改造的內(nèi)容。2. ?下面直接介紹使用方法:以調(diào)試Lit.shader為例(工程中參見LitDebugFragment.shader)。先看下效果:

木材Shader為需要調(diào)試的,插入代碼后,渲染結(jié)果不會受到任何影響

按住Ctrl,點擊需要顯示輸出內(nèi)容的像素點,同時會在屏幕和Console中輸出內(nèi)容3. ?對需要日志輸出的Shader進行簡單改造1)在HLSLPROGRAM前添加

//1、FragmentDebug:添加混合模式

Blend 1 One Zero

指定SV_Target1的混合方式2)在Fragment函數(shù)前添加

//--------------------------------------

// GPU Instancing

#pragma multi_compile_instancing

//2、FragmentDebug: 在Fragment函數(shù)前添加

#pragma multi_compile __ FRAGMENT_DEBUG_ENABLE

#include "Packages/com.seasun.graphics/Shaders/Debug/FragmentDebug.hlsl"

#include "ShaderPass/LitInput.hlsl"

3)改造Fragment函數(shù)名和初始化

// Used in Standard (Physically Based) shader

//half4 LitPassFragment(Varyings input) : SV_Target

//3、FragmentDebug: 修改Frag函數(shù)分別傳入3個參數(shù):函數(shù)名、v2f結(jié)構(gòu)體名稱、結(jié)構(gòu)體實例

FRAGMENT_DEBUG_FUN(LitPassFragment, Varyings, input)

{

//4、FragmentDebug: 初始化

FRAGMENT_DEBUG_INIT

4)增添想輸出的變量和改造返回

half4 color = UniversalFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha);

color.rgb = MixFog(color.rgb, inputData.fogCoord);

//5、FragmentDebug: 輸入想要調(diào)試輸出的變量,支持xyz3個參數(shù)

FRAGMENT_DEBUG_VALUE(xyz, surfaceData.albedo)

//6、FragmentDebug: 將原始結(jié)果放入宏中

FRAGMENT_DEBUG_OUTPUT(color)

//return color;

4. ?開始調(diào)試在PlayerSetting中增添宏FRAGMENG_DEBUG,刪除此宏會自動關(guān)掉全部功能,包括對URP的改造。在調(diào)試場景中,找個任意一個GameObject,掛載FragmentDebug.cs腳本,然后啟動游戲。按住Ctrl,用鼠標(biāo)點擊待調(diào)試模型的像素點,會在Console和屏幕中輸出日志內(nèi)容。Ctrl+D可以顯示和隱藏屏幕中的調(diào)試窗口。四、ComputeShader中的日志輸出ComputeShader與上面的VS與PS不同,是完全兩套流水線,基于GPGPU設(shè)計,天然就支持?jǐn)?shù)據(jù)從GPU回傳數(shù)據(jù)到CPU。這個工具為了更方便地調(diào)試輸出,只是對原本的方法進行了一些封裝。1. ?下面直接介紹使用方法:使用示例參見倉庫中的CSTest.cs和CSDebug.compute。2. ?對執(zhí)行腳本進行改造由于ComputeShader的執(zhí)行通常有兩種,一種是直接執(zhí)行,另一種是在CommandBuffer中執(zhí)行。針對這兩種方法使用上略有差別:1)直接執(zhí)行

private void ExcuteCSManual()

{

CSDebug.ComputeShaderDebugSet("Debug1", m_ComputeShader, kernel);

CSDebug.ComputeShaderDebugSet("Debug2", m_ComputeShader, kernel);

m_ComputeShader.SetTexture(kernel, "Result", m_RenderTexture);

m_ComputeShader.SetTexture(kernel, "Source", m_SrcTexture);

m_ComputeShader.Dispatch(kernel, m_RenderTexture.width, m_RenderTexture.height, 1);

Debug.Log("CS1 : " + CSDebug.ComputeShaderDebugGet("Debug1"));

Debug.Log("CS2 : " + CSDebug.ComputeShaderDebugGet("Debug2"));

CSDebug.ComputeShaderDebugRelease();

}

在Dispatch之前設(shè)置變量名,可以根據(jù)實際情況設(shè)置多個,其中Debug1和Debug2為變量名。在執(zhí)行完Dispatch之后調(diào)用CSDebug.ComputeShaderDebugGet來獲取ComputeShader中輸出的數(shù)值。最后執(zhí)行CSDebug.ComputeShaderDebugRelease()來釋放ComputeBuffer。2)在CommandBuffer中執(zhí)行

private void ExcuteCSCommand(ScriptableRenderContext context, Camera camera)

{

if (camera == Camera.main)

{

if (m_ExcuteCommand)

{

m_ExcuteCommand = false;

}

else

{

return;

}

Debug.Log("CS1 : " + CSDebug.ComputeShaderDebugGet("Debug1"));

Debug.Log("CS2 : " + CSDebug.ComputeShaderDebugGet("Debug2"));

CSDebug.ComputeShaderDebugRelease();

CommandBuffer command = CommandBufferPool.Get("ExcuteCSCommand");

CSDebug.ComputeShaderDebugSet("Debug1", m_ComputeShader, kernel);

CSDebug.ComputeShaderDebugSet("Debug2", m_ComputeShader, kernel);

command.SetComputeTextureParam(m_ComputeShader, kernel, "Result", m_RenderTexture);

command.SetComputeTextureParam(m_ComputeShader, kernel, "Source", m_SrcTexture);

command.DispatchCompute(m_ComputeShader, kernel, m_RenderTexture.width, m_RenderTexture.height, 1);

context.ExecuteCommandBuffer(command);

CommandBufferPool.Release(command);

}

}

與執(zhí)行直接調(diào)用的三個函數(shù)一樣,但是由于CommandBuffer不是立即執(zhí)行,而是延遲執(zhí)行的,因此DispatchCompute之后ComputeBuffer并沒有真正執(zhí)行,也就無法獲取調(diào)試的內(nèi)容。CSDebug.ComputeShaderDebugSet使用的位置同直接執(zhí)行,但是Get和Release兩個方法需要放到Set之前。也就是說,每次Get出來的是上一次執(zhí)行的結(jié)果,第一次執(zhí)行輸出的內(nèi)容為0。3. ?對ComputeShader進行改造

#pragma kernel CSMain

//1) 在定義前添加

#include "Packages/com.seasun.graphics/Shaders/Debug/CSDebug.hlsl"

RWTexture2D<float4> Result;

Texture2D Source;

//2)定義變量,其中變量名同C#中的定義

DEBUG_DEF(Debug1)

DEBUG_DEF(Debug2)

[numthreads(1, 1, 1)]

void CSMain(uint3 id : SV_DispatchThreadID)

{

int i = id.x;

int j = id.y;

float c = Source[float2(i, j)].x * 0.3 + Source[float2(i, j)].y * 0.2 + Source[float2(i, j)].z * 0.5;

Result[float2(i, j)] = float4(c, c, c, Source[float2(i, j)].w);

if (i == 100 && j == 100)

{

//3)增添想要輸出的變量

DEBUG_VALUE(Debug1, Source[float2(i, j)].x)

DEBUG_VALUE(Debug2, Source[float2(i, j)].y)

}

}

一共3個步驟,這里就不再細(xì)說了。4. ?開始調(diào)試在PlayerSetting中增添CS_DEBUG宏,然后運行場景。由于ComputeShader不像普通的Shader一樣支持宏編譯和變體,因此ComputeShader中宏的實現(xiàn)采用文件替換的方式間接實現(xiàn)。每次修改完宏之后需要在編輯器模式下執(zhí)行一次CSDebug中的任意方法才能真正生效(也可以在編輯器模式下調(diào)試一次即可)。

點擊右上角的兩個按鈕進行測試,結(jié)果在Console中輸出五、倉庫地址歡迎大家Clone使用,提出改進意見。https://github.com/zouchunyi/ShaderDebug

文末,再次感謝鄒春毅的分享,如果您有任何獨到的見解或者發(fā)現(xiàn)也歡迎聯(lián)系我們,一起探討。(QQ群:793972859)

也歡迎大家來積極參與U Sparkle開發(fā)者計劃,簡稱“US”,代表你和我,代表UWA和開發(fā)者在一起!

UWA GPM正式上線!

近期精彩回顧

【厚積薄發(fā)】GPU Skinning不生效問題

【萬象更新】GOT Online已支持Unreal最新版本

【學(xué)堂上新】DOTS深度研究之原理分析篇

【充電一刻】一分鐘,讀懂UWA性能報告

總結(jié)

以上是生活随笔為你收集整理的unity 如何获取到屏幕中间_Unity通用渲染管线Shader日志输出工具的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。