99国产精品欲av蜜臀,可以直接免费观看的AV网站,gogogo高清免费完整版,啊灬啊灬啊灬免费毛片

網易首頁 > 網易號 > 正文 申請入駐

基于URP搭建Linear色彩空間下的UI渲染管線

0
分享至


【USparkle專欄】如果你深懷絕技,愛“搞點研究”,樂于分享也博采眾長,我們期待你的加入,讓智慧的火花碰撞交織,讓知識的傳遞生生不息!

這是侑虎科技第1779篇文章,感謝作者七塊君供稿。歡迎轉發分享,未經作者授權請勿轉載。如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群:793972859)

作者主頁:

https://www.zhihu.com/people/Na-Ka-4921

一、前言

自Unity支持Linear色彩空間以來,Unity的3D渲染的光影層次變得更加準確細膩,但是Linear色彩空間下UI的渲染卻因此變得糟糕。絕大多數的UI資產都是在sRGB色彩空間里制作完成的,UI圖片的格式也都是基于sRGB,所以Linear色彩空間下,基于sRGB的UI圖片的Alpha得不到正確的混合,使得UI圖片的不透明度得不到正確的呈現。

為了匹配Linear色彩空間下的Alpha混合,有些團隊限制使用半透明資產;有些是在Ps里盲調,再到Unity里做驗證,直到看起舒服為止;或是在Ps里改變圖片色彩空間。這些做法無疑都是限制了UI制作流程。

現在的URP基于可編程渲染管線,支持自定義管線。要想徹底解決UI渲染問題,可以在Unity管線層面,做出合理的管線設計,維持UI設計師正常的sRGB資產制作流程。

二、管線效果對比


左邊: Photoshop效果 | 中間: 自定義UI管線效果 | 右邊: Unity URP默認效果

三、管線的設計思路


1. 在原有Linear色彩空間的Buffer里渲染3D圖形;

2. 將渲染完成的3D圖像轉移至Gamma色彩空間的UI Buffer中;

3. 在Gamma色彩空間的UI Buffer中繼續渲染UI圖片;

4. 將最終的渲染結果轉回到Linear,并最終輸出。

因為UI圖片的Alpha Blend是在Gamma空間下完成的,所以不存在錯誤的混合結果,兼容了Linear色彩空間的3D渲染和Gamma色彩空間下的UI渲染。

四、管線的具體實現

管線流程

思路有了,那么再結合URP現有的流程,詳細方案如下:


3D使用Base的Main Camera渲染,UI使用Overlay的UI Camera渲染,并把UI Camera塞到Main Camera的Stack當中。


URP在使用Post-Processing(后處理)時,本身在3D渲染完就會有一次Uber Post Process的Pass,以及不管有沒有后處理,在最終畫面渲染完都會有一次Final Blit的Pass(如果開了FXAA,則是Final Post)。只要我們在這兩個Pass里做色彩空間轉換,幾乎不會產生多少額外的性能開銷。只有在不使用Post-Processing時,才需要在3D渲染完成時額外補一個Pass做色彩空間轉換。

另外,Uber Post Process和Final Blit都會用到"Hidden/Universal Render Pipeline/Blit"這個Shader著色, 因此可以在Blit Shader的片元著色器里加入色彩空間轉換的函數和全局的Keyword宏,以方便在管線中利用Command Buffer設置keyword進行色彩空間轉換。

Shader("Hidden/Universal Render Pipeline/Blit"):

half4 Fragment(Varyings input) : SV_Target {        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);        half4 col = SAMPLE_TEXTURE2D_X(_SourceTex, sampler_SourceTex, input.uv);     #ifdef _LINEAR_TO_SRGB_CONVERSION        col = LinearToSRGB(col);     #endif     #ifdef _SRGB_TO_LINEAR_CONVERSION        col = SRGBToLinear(col);     #endif        return col; }

管線部分(Uber Post Process):

var cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, m_ProfilingRenderPostProcessing)) {     cmd.EnableShaderKeyword(ShaderKeywordStrings.LinearToSRGBConversion);       Render(cmd, ref renderingData);                    cmd.DisableShaderKeyword(ShaderKeywordStrings.LinearToSRGBConversion); } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd);

3D Buffer和UI Buffer的格式:

值得注意的是,Unity默認渲染3D圖形的Buffer格式是RGBA111110Float:


如果在這個格式的Buffer里直接利用shader轉換色彩空間(LinearToSRGB)會造成3D圖像嚴重的色深精度丟失。所以需要一個和sRGB色彩信息契合的格式來儲存Shader轉換后色彩空間后的圖像信息,所以我選擇了RGBA32UNorm作為后續UI Buffer的格式,使用不同格式轉換色彩后的色深對比如下:


可以看出來,使用RGBA32UNorm能更好地儲存轉換后的色深精度。

轉換Buffer的方法,我這里未在ForwardRenderer里為UI重新聲明創建RT,以及根據是否是UI相機,讓Final Blit Pass選擇接受不同的Render Target:

RenderTargetHandle m_UguiTaget; ...... m_UguiTaget.Init("_UIColorTexture"); ...... void CreateCameraRenderTarget(ScriptableRenderContext context, ref RenderTextureDescriptor descriptor, bool createColor, bool createDepth) {     ......     {         var uiDescriptor = descriptor;         uiDescriptor.useMipMap = false;         uiDescriptor.autoGenerateMips = false;         uiDescriptor.depthBufferBits = 24;         uiDescriptor.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm;         cmd.GetTemporaryRT(m_UguiTaget.id, uiDescriptor, FilterMode.Bilinear);     }     ...... } ...... public override void Setup(ScriptableRenderContext context, ref RenderingData renderingData) {     ......     if (!cameraTargetResolved)     {          RenderTargetHandle finalTarget = isUICamera ? m_UguiTaget : m_ActiveCameraColorAttachment;         m_FinalBlitPass.Setup(cameraTargetDescriptor, finalTarget);         EnqueuePass(m_FinalBlitPass);     }     ...... }

并在UGUI Pass(DrawObjectsPass)里,依據是否畫UI來重新設置Render Target:

/* Add by: Takeshi, Set UI Render target */ if (m_IsGameViewUI && m_UguiTarget != default) {     cmd.SetRenderTarget(m_UguiTarget.Identifier());     context.ExecuteCommandBuffer(cmd);     cmd.Clear(); } /* End Add */ context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filterSettings, ref m_RenderStateBlock);

注:UGUI Pass后面會講到。

UI的分辨率

因為在3D物體渲染完畢時切換了Buffer,在這里有一次全面重置Buffer尺寸的機會,我們可以修改接下來UI Buffer的分辨率,以達到即使降低3D的渲染質量,也依然能保證UI以滿屏幕分辨率渲染。

在前面ForwardRenderer的CreateCameraRenderTarget()方法里創建UI RT時指定新的寬高尺寸:

var uiDescriptor = descriptor; uiDescriptor.useMipMap = false; uiDescriptor.autoGenerateMips = false; uiDescriptor.depthBufferBits = 24; uiDescriptor.height = Screen.height; /* 設置 UI Render Target 的高度 */ uiDescriptor.width = Screen.width;   /* 設置 UI Render Target 的寬度 */ uiDescriptor.graphicsFormat = GraphicsFormat.R8G8B8A8_UNorm; cmd.GetTemporaryRT(m_UguiTaget.id, uiDescriptor, FilterMode.Bilinear);


UGUI Pass

Unity默認情況是UI在DrawTransparentObjects Pass里繪制,Game視圖因為有獨立的UI相機,所以問題不大,但是Scene視圖里只有一個相機,借助Render Doc可以看出UI和一般的半透明物體是混在一起的,想在UI和半透明物體之間插入自定義Pass是不可能的。理想狀態是:讓UI擁有屬于自己的Pass,方便后期維護管理。

在Forward Renderer中單獨聲明了一個DrawOjectsPass類型的UGUI Pass,構造如下:

m_UguiPass = new DrawObjectsPass("UGUI", false,
RenderPassEvent.BeforeRenderingTransparents +1,
RenderQueueRange.transparent,
LayerMask.GetMask("UI"), m_DefaultStencilState,
stencilData.stencilReference);

用指定的Layer Mask ("UI")來作為這個Pass的渲染條件。使用"UI" layer的Transparent序列物體都會進入這個Pass。


注:不能忘了重新配置Forward Renderer Data, 要把"UI" Layer Mask在Transparent Layer Mask中去掉,否則UI會被DrawTransparentObjects和UGUI這兩個Pass重復繪制。


UI和半透明物體分離后,Scene視圖也可以方便的校色了。


UI圖片的色彩空間

在管線修復后,理論上UI圖片就不用勾選sRGB了,但是,我在這里做法是:UI圖片維持勾選sRGB,并在UI的Shader里反向矯正回打勾前的狀態。


UI Shader的Fragment:

float4 pixel(v2f IN) : SV_Target {     ......     half4 color;     ......     color.rgb = lerp(color.rgb,LinearToSRGB(color.rgb),_IsInUICamera);     // "One OneMinusSrcAlpha".     color.rgb *= color.a;     return color; }

將Linear的Color和sRGB的Color用一個全局變量"_IsInUICamera"為mask進行Lerp插值,全局變量"_IsInUICamera"在DrawObjectPass中實時全局賦值:

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) {     // NOTE: Do NOT mix ProfilingScope with named CommandBuffers i.e. CommandBufferPool.Get("name").     // Currently there's an issue which results in mismatched markers.     CommandBuffer cmd = CommandBufferPool.Get();     using (new ProfilingScope(cmd, m_ProfilingSampler))     {         Camera camera = renderingData.cameraData.camera;         if (camera.CompareTag("UICamera"))             cmd.SetGlobalFloat(ShaderPropertyId.isInUICamera,1); #if UNITY_EDITOR         else if(m_FilteringSettings.layerMask == LayerMask.GetMask("UI") && renderingData.cameraData.isSceneViewCamera)             cmd.SetGlobalFloat(ShaderPropertyId.isInUICamera,1); #endif         else cmd.SetGlobalFloat(ShaderPropertyId.isInUICamera,0);         ......     }     ......  }

這樣確保只在UI相機渲染階段走sRGB的渲染流程,非UI相機一切照舊,規避掉因為UI校色而導致非UI相機渲染的UI圖片(*例如:世界空間下的UI)顏色不正確。

注:即UI相機中UI的顏色和不透明度都是正確的,非UI相機中的UI顏色正確但不透明度未被矯正。所以暫時不支持非UI相機的不透明度矯正,但也不影響正常使用。

重置UI組件默認Shader

UI組件,比如Image,在不使用自定義材質時,會默認使用Shader "UI/Defaut",而這個Shader是內置不可編輯的,對于我們使用了自定的UI Shader和后期對Shader框架進行擴展就很不方便,我們需要UI組件默認使用我們自己寫的Shader。


UI 組件 默認著色器

好在UI組件的源碼是可以編輯的,順著Image組件的源碼,可以看到Image類繼承了MaskableGraphic類,MaskableGraphic類又繼承了Graphic類,這個就是UI組件的根源了。可以看到Graphic類里有一段設置默認UI Shader的代碼。


修改一下:

static public Material defaultGraphicMaterial {     get     {         // Find Custom UI Shader         Shader uiShader = Shader.Find("UI/URP_Linear_Space_Default");         Material uiMaterial = new Material(uiShader);         if (s_DefaultUI == null)             //s_DefaultUI = Canvas.GetDefaultCanvasMaterial();             s_DefaultUI = uiMaterial;         return s_DefaultUI;     } }

這樣默認UI Shader就替換成我們自己的了,后面就可以愉快地搭建UI Shader框架了。


修改后 的默認UI Shader變成了我們的自定義著色器

五、尾聲

最后的最后,是我項目的GitHub地址:

https://github.com/TakeshiCho/UI_RenderPipelineInLinearSpace

文末,再次感謝 七塊君 的分享, 作者主頁: https://www.zhihu.com/people/Na-Ka-4921, 如果您有任何獨到的見解或者發現也歡迎聯系我們,一起探討。(QQ群: 793972859 )。

近期精彩回顧

特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關推薦
熱點推薦
我在非洲干工地,為方便在院里建了廁所,結果隔天全村姑娘都來了

我在非洲干工地,為方便在院里建了廁所,結果隔天全村姑娘都來了

凱裕說故事
2025-06-17 15:20:47
56歲高曉松與高中女友相約聚會,曬二人戀愛時合影,被嘲像兩代人

56歲高曉松與高中女友相約聚會,曬二人戀愛時合影,被嘲像兩代人

深析古今
2025-06-17 20:23:49
曾春蕾現身云南支教,戴眼鏡有模有樣,退役后太低調,已生二胎

曾春蕾現身云南支教,戴眼鏡有模有樣,退役后太低調,已生二胎

跑者排球視角
2025-06-17 23:24:45
字節某員工:前+1領導貪污被判了兩年半。他年薪過百萬,可惜了

字節某員工:前+1領導貪污被判了兩年半。他年薪過百萬,可惜了

螞蟻大喇叭
2025-06-18 17:59:09
中國男籃國家隊即將迎來多名黑面孔,混血+歸化是大勢所趨!

中國男籃國家隊即將迎來多名黑面孔,混血+歸化是大勢所趨!

趙仔說
2025-06-18 08:31:36
金正恩手一揮,再給俄6000兵,接下來普京的操作,整個歐洲要看懵

金正恩手一揮,再給俄6000兵,接下來普京的操作,整個歐洲要看懵

梁訊
2025-06-18 09:19:18
西班牙生物老師親自穿立體“人體器官服”講課,家長質疑尺度大

西班牙生物老師親自穿立體“人體器官服”講課,家長質疑尺度大

等風來育兒聯盟
2025-06-17 09:24:58
王楚欽陪領導打球不加轉!成功放水后憨笑,在大佬旁側坐很乖巧

王楚欽陪領導打球不加轉!成功放水后憨笑,在大佬旁側坐很乖巧

三十年萊斯特城球迷
2025-06-17 17:52:49
外資繼續加倉!這些A股受關注

外資繼續加倉!這些A股受關注

數據寶
2025-06-18 07:37:01
外賣備注到底能有多辣眼睛?一看一個臉紅心跳不吱聲的

外賣備注到底能有多辣眼睛?一看一個臉紅心跳不吱聲的

有趣的火烈鳥
2025-06-18 18:36:07
王菲在福建寺廟祈福被偶遇,棉麻素衣加持,美成“人間仙子”

王菲在福建寺廟祈福被偶遇,棉麻素衣加持,美成“人間仙子”

喜歡歷史的阿繁
2025-06-16 13:20:05
女人過了40歲,最容易和哪種男人發生關系?已婚女人實話實說了

女人過了40歲,最容易和哪種男人發生關系?已婚女人實話實說了

特約前排觀眾
2025-06-05 00:05:08
李玟墓地現狀:臺階上堆滿鮮花蠟燭,隔壁姚貝娜墓地卻冷冷清清

李玟墓地現狀:臺階上堆滿鮮花蠟燭,隔壁姚貝娜墓地卻冷冷清清

不八卦掌門人
2025-06-16 21:15:02
24GB+1TB!小米新機公布:6月20日,正式發布!

24GB+1TB!小米新機公布:6月20日,正式發布!

科技堡壘
2025-06-16 11:38:51
父親節,一個連資本都不愿意炒作的節日

父親節,一個連資本都不愿意炒作的節日

今夜無局
2025-06-15 12:32:18
伊朗和以色列這次生死之戰,必將把中國送上世界頭把交椅

伊朗和以色列這次生死之戰,必將把中國送上世界頭把交椅

智慧生活筆記
2025-06-17 21:31:49
飛天茅臺電商促銷價跌破1850元:經銷商稱線下影響有限,高端白酒如何破局?

飛天茅臺電商促銷價跌破1850元:經銷商稱線下影響有限,高端白酒如何破局?

澎湃新聞
2025-06-18 07:42:28
難以置信!欠薪18000元,官方介入解決不了,欠薪者拒不配合調解

難以置信!欠薪18000元,官方介入解決不了,欠薪者拒不配合調解

火山詩話
2025-06-17 10:10:02
“消失五天”的哈梅內伊交代后事:革命衛隊將接管伊朗最高權力

“消失五天”的哈梅內伊交代后事:革命衛隊將接管伊朗最高權力

侃侃娛季
2025-06-18 16:01:29
三人以上傳不得聚餐!官媒權威解讀史上最嚴“規定”:三人以下普通聚餐,一般沒問題

三人以上傳不得聚餐!官媒權威解讀史上最嚴“規定”:三人以下普通聚餐,一般沒問題

霹靂炮
2025-06-17 22:55:05
2025-06-18 19:23:00
侑虎科技UWA incentive-icons
侑虎科技UWA
游戲/VR性能優化平臺
1455文章數 984關注度
往期回顧 全部

科技要聞

別叫我互聯網公司,京東的野心藏不住了

頭條要聞

俄方稱朝鮮決定向俄羅斯追加派兵6000人 中方回應

頭條要聞

俄方稱朝鮮決定向俄羅斯追加派兵6000人 中方回應

體育要聞

高僧下山了!文班結束少林寺10日修行

娛樂要聞

前老板舉報李雪琴欠190萬轉移公司財產

財經要聞

潘功勝李云澤吳清發聲 資本市場關鍵信號

汽車要聞

燈光技術升級還有插混版本 全新奧迪Q3預計明年國產

態度原創

藝術
游戲
教育
房產
公開課

藝術要聞

故宮珍藏的墨跡《十七帖》,比拓本更精良,這才是地道的魏晉寫法

原來封面圖是真的!玩家才發現Switch手柄座可立

教育要聞

五年級期末考試附加題,難,除了尖子生,都放棄了

房產要聞

創紀錄了!海南單日賣地44億!保利、方大瘋狂出手!

公開課

李玫瑾:為什么性格比能力更重要?

無障礙瀏覽 進入關懷版 主站蜘蛛池模板: 宜君县| 嵊泗县| 承德县| 新源县| 师宗县| 霸州市| 山阳县| 黎平县| 双江| 准格尔旗| 四会市| 仪征市| 乃东县| 湘乡市| 响水县| 铜山县| 都匀市| 铜梁县| 阿尔山市| 山东省| 昌邑市| 红安县| 涪陵区| 信阳市| 横峰县| 尚志市| 太仆寺旗| 临洮县| 仁化县| 尤溪县| 霍林郭勒市| 农安县| 明星| 凤庆县| 神农架林区| 舟曲县| 黄平县| 肇东市| 和政县| 徐汇区| 建始县|