天天看點

unity3d 基于實體渲染的問題解決

最近1個月做了unity 次世代開發的一些程式方面的支援工作,當然也是基于實體渲染相關的,主要還是skyshop marmoset的使用吧,他算是unity4.x版本 PBR的優秀方案之一了

但在使用以及性能上,還是多少有些坑和不足,這裡也是自己的一些心得吧,希望可以其他對這個方案有興趣的朋友起到一些幫助。

一、遇到了fps降低的BUG

國慶節前的老版本工程和最新的工程版本運作起來沒任何差別,但新版本在真機上的的運作效率有問題,隻有7.5fps

開發和運作環境,

XCode6.1 IOS8.1 

IPad Air 分辨率 2048x1536

Graphic level GLES 3.0

unity3d 基于實體渲染的問題解決
圖1 老版本的運作截圖,為了能做參考,我這裡把新版本的場景檔案拷貝到老工程裡
unity3d 基于實體渲染的問題解決

新版本相同的場景就隻有不到8FPS

然後對兩個版本用Xcode做了分析,舊版本fps analyze

unity3d 基于實體渲染的問題解決
新版本fps analyze,同樣的shader消費的ms是老版的5倍
unity3d 基于實體渲染的問題解決
unity3d 基于實體渲染的問題解決

發現bug後,嘗試定位問題 

1 一開始認為是marmoset版本問題,但用老版本完全覆寫,fps并沒有提升 

2 删除和場景資源相關外的所有資源,重新build後,fps就恢複了,不過這種解決方法應該是無非接受的 目前臨時的解決方法,把老工程的ProjectSettings裡的檔案替換過好了,具體的原因還要繼續排查。

unity3d 基于實體渲染的問題解決
unity3d 基于實體渲染的問題解決

另外有一些版本的SkyShop的Mobile shader沒有gles3.0的支援,需要在給所有場景裡使用的Marmoset的shader裡添加關鍵字

#pragma surface MarmosetSurf MarmosetDirect vertex:MarmosetVert exclude_path:prepass noforwardadd approxview

#pragma only_renderers d3d9 opengl gles d3d11 d3d11_9x gles3

好早marmoset的是UberShader的設計,是以隻要改幾個就好了。

要unity支援es3.0的話,需要在設定Player Settings.. 的圖形等級裡選擇 Automatic或強制gles3.0。  

unity3d 基于實體渲染的問題解決
unity3d 基于實體渲染的問題解決

如果隻用es2.0的話,因為unity會使用texCube或texCubeBias來替換texCubeLod,沒有lod的支援,使用cubemap的mipmap來實作粗糙度的功能就會受到影響

最終渲染畫面裡可能會看不到材質的粗糙度表現。

如果把這個bug解決的話,那麼性能評估應該和10.1前的報告一樣,IPad Air 可以承受的是全屏,100Draw Call的支援IBL材質物體的繪制,另外有IBL的shader的瓶頸

應該是在pixel shader上,如果1,2個IBL材質占滿整個2048x1536螢幕的話,一樣會有潛在的瓶頸問題産生。

二、關于另外一個場景的問題解決 Draw Call可以先在Editor或聯機Porfile裡檢視,一些裝置不支援Unity Editor的GPU Profile,是以還是要用到Xcode

unity3d 基于實體渲染的問題解決
unity3d 基于實體渲染的問題解決

沒做任何優化的前提下 draw call是592, GPU裡兩個占用最高的shader,9.8ms和7.94ms都是Terrain占用的(地形和他和陰影貼圖), 另外關閉陰影後為289 drawcall,關閉地形後289->219(地形 70dc),關閉水面289dc->246dc(水面反射)

首先是Terrain,不論是shader還是dc都有些多,在Xcode的Frame view裡,Terrain的繪制有不合理的地方,從截圖場景來看,這種大小的地形需要70的draw call次數有些誇張了,另外就是shader上,如果是靜态烘培陰影,應該是可以合并到一個shader裡繪制的。建議還是從優化地形開始,降低dc,合并shader,如果u3d 的terrain沒有優化的可能,不如就直接max裡制作網格的地面來代替。

水面可以優化反射部分的實作,靜态場景的反射可以預烘培到一張貼圖裡,而可以反射的部分,建議單獨添加到一個layer裡。降低dc數量。 錄影機的可視範圍,角度,以及shader Lod的設定,在Xcode的分析中,一些極遠位置的山體還是被繪制了,而且和近處的角色一樣高品質的shader,這點用unity的内部設定應該就可以解決。另外這個demo錄影機的角度過低,導緻遠處的物體也都被渲染到,如果适當修改錄影機角度,例如傳統的45視角,應該可以裁剪一部分場景物體。起到降低dc和ps填充率的作用。

三、關于Marmoset shader的改進意見 1。如果不使用skyshop的天空盒的動态功能的話,skymanager的update可以關閉 public void LateUpdate() {

            if(firstFrame) {

                if(_GlobalSky) {

                    firstFrame = false;

                    _GlobalSky.Apply(0);

                    _GlobalSky.Apply(1);

                    if(_SkyboxMaterial) {

                        _GlobalSky.Apply(_SkyboxMaterial, 0);

                        _GlobalSky.Apply(_SkyboxMaterial, 1);

                    }

                }

            }

            #if UNITY_EDITOR

            if(!Application.isPlaying) return;

            #endif

直接在 #if UNITY_EDITOR前面傳回return就可以了,這樣可以節省skymanager的Update的cpu消耗和GC。

2 GlossyMap的使用,之前為了解決7FPS的問題時,嘗試的一種解決方案,在Anylaze裡直接修改textureLod的參數 tmpvar_40 = textureLod (_SpecCubeIBL, lookup_38.xyz, lookup_38.w);

例如 tmpvar_40 = textureLod (_SpecCubeIBL, lookup_38.xyz, 1);, 這樣效率可以提高1倍以上 分析可以看下圖

unity3d 基于實體渲染的問題解決

highp float glossLod_36;

  glossLod_36 = tmpvar_27;

  mediump vec4 spec_37;

  mediump vec4 lookup_38;

  highp vec4 tmpvar_39;

  tmpvar_39.xyz = ((v_33.xyz * tmpvar_32.x) + ((v_34.xyz * tmpvar_32.y) + (v_35.xyz * tmpvar_32.z)));

  tmpvar_39.w = glossLod_36;

  lookup_38 = tmpvar_39;

  lowp vec4 tmpvar_40;

  tmpvar_40 = textureLod (_SpecCubeIBL, lookup_38.xyz, lookup_38.w);

上面是還沒有做任何修改的shader,lod,也就是lookup_38.w還是根據glossy map的值,在shader裡計算得出

unity3d 基于實體渲染的問題解決

  tmpvar_39.w = glossLod_36;

  lookup_38 = tmpvar_39;

  lowp vec4 tmpvar_40;

  tmpvar_40 = textureLod (_SpecCubeIBL, lookup_38.xyz, 1.0); 在shader裡直接傳一個const值的方法,熱更新後可以看到shader消費的ms和之前有一定的減少。

unity3d 基于實體渲染的問題解決

不過重新啟動遊戲的話,ms有了40%左右的減少,這是因為IOS做的優化,如果lod在shader運作前已經确定的話,會直接pre fetch制定的texture,就不需要在每個pix shader裡重新執行一次采樣了。 

是以,glossy map建議适量使用,一些不需要細節的材質可以直接用一個恒定的roughness參數替代。

還有就是關于pbr shader算法的優化,marmoset自己内部有MARMO_HQ的關鍵字,通過切換可以實作一定程度的優化,先是兩種品質的對比 MARMO_LQ

unity3d 基于實體渲染的問題解決
MARMO_HQ 差别在shader的精确度上,以及出射光的亮度上
unity3d 基于實體渲染的問題解決

MARMO_HQ的用處,對向量的規格化,起到類似能量守恒的作用,Fresenl函數的算法選擇,使得渲染的出射光總量更符合實體效果

//self-shadowing blinn

#ifdef MARMO_DIFFUSE_DIRECT

    spec *= saturate(10.0*dp);

#else

    spec *= saturate(10.0*dot(N,L));

#endif

#ifdef MARMO_DIFFUSE_DIRECT

    spec *= saturate(10.0*dp);

#else

    spec *= saturate(10.0*dot(N,L));

#endif

#ifdef MARMO_HQ

    localN = normalize(localN);

#endif    

以上是shader代碼裡一些規格化設定的樣本。 shader裡還有其他一些可優化點

unity3d 基于實體渲染的問題解決

  例如Specular Intensity,Sharpenss,fresnel Strength,并不是pbr Material的标準參數,一般隻需要roughness或glossy map裡選擇其一做粗糙度參數就可以 .而其他參數去掉可以減少一部分shader的計算量

  前面提到的glossymap和roughness的切換,需要shader支援,編輯器也要做一定的修改。

fresenl 反射方程,marmoset提供了的 splineFresnel和fastFresnel的兩種方法,但實際的計算量還是比較多,根據GDC2014上的unity5的方案,可以換成簡單的pow 4次方的形式。 确定TextureCubeLod的方向和lod值的算法上也優化的空間。

  UberShader的設計是一個優點,在開發的時候可以減少很大的工作量,實際運作時,建立和編譯shader數量也很少,友善分析和定位shader的問題,和在Xcode裡進行優化調試。

  另外就是marmoset的skymanager部分,還是需要修改的,他本來的設計目的是基于天空盒來生成IBL使用的Cubemap,而真正的IBL光照是基于周圍環境來生成,是以,skyshop這種整個場景統一一張cubemap的方法,在真實性和效果上還是很值得斟酌的,它的IBL的生成和管理接口對做遊戲來說也不是很友善,優點就是它提供了編輯器和cumbemap生成部分的全部代碼,不論是擴充還是修改bug,都是可行的。

  unity4.x的版本裡,在移動端是無法支援延遲渲染方法的,是以對場景裡的光源限制會比較嚴格,一盞方向光就是極限了,其他烘托場景的用的點光源,就隻能使用lightmap了 而lightmap的具體算法,也是要使用者自己實作的,Marmoset在MarmosetDirect.cginc裡實作了directional lightmap lighting的實作,LightingMarmosetDirect_DirLightmap 這個的命名是要按照unity custom shader的規範來命名,就可以在unity渲染管線裡自動被識别,如果想優化,或者要支援Dual lightmap等其他類型的liaghtmap,最好還是自己提供優化的方法。希望我們自己的項目裡,将來能提供TBDR的支援來達到大量光源的支援。

最後考慮還是要和UE4的移動産品做一下競品對比的:

unity3d 基于實體渲染的問題解決
UE4的Sum Temple項目是個很好的參考,gles2.0的圖形規格下,也能獲得很好的效果
unity3d 基于實體渲染的問題解決

UE4 mobile的圖形規格,簡單來說就是一個Directional light+distance shadow來生成光照和陰影,其他的場景明暗和各種顔色燈光的亮度由lightmap來實作, IBL方面,可以為通過設定RefelctCapture,給制定區域内的對象生成IBL,同一場景内可以使用多個cubemap的實作(ppt裡說他在移動端是使用了一個統一的cubemap,這點需要後面直接對它的工程做真機剖析了)。另外也有bloom+AA+light shaft+dof等的後處理效果,但因為圖形規格的限制,ES2.0版本是沒有真實HDR的支援的。

接下來我會準備一篇針對UE4渲染和優化方法的分析。

四,總結   通過這次U3D的PBR的實驗,在IPAD Air和K1這種硬體級别的機器上,制作PBR的遊戲還是沒有問題的,一開始擔心視網膜屏的填充率問題,在實際測試中,還是可行的,但需要整個開發團隊有一定的優化意識,才能在整個上保證一個良好的運作效率,比如支援IBL的配置設定,而且遊戲制作方面,也要考慮什麼樣的遊戲類型,才能發揮PBR渲染的優勢,特别是間接照明對遊戲場景品質的提升(消費最高的IBLshader支援的是間接照明的高光部分)。還有就是多使用unity的batch功能,盡量降低dc和關于shader狀态切換等等,另外可惜的是,因為之前7fps bug的問題,這次沒有時間把unity的post effect部分實作,個人考慮是可以把ue4的這部分實作移植過來, UE4對U3D可以起到很好的競品作用,在今後的PBR效果和效率的測試和優化中,一定的對比分析和借鑒,也是很有幫助的。

繼續閱讀