unity3d 基於物理渲染的問題解決

  最近1個月作了unity 次世代開發的一些程序方面的支持工做,固然也是基於物理渲染相關的,主要仍是skyshop marmoset的使用吧,他算是unity4.x版本 PBR的優秀方案之一了
但在使用以及性能上,仍是多少有些坑和不足,這裏也是本身的一些心得吧,但願能夠其餘對這個方案有興趣的朋友起到一些幫助。
web

 

1、遇到了fps下降的BUG算法

國慶節前的老版本工程和最新的工程版本運行起來沒任何區別,但新版本在真機上的的運行效率有問題,只有7.5fps
開發和運行環境,
XCode6.1 IOS8.1
IPad Air 分辨率 2048x1536
Graphic level GLES 3.0
app



圖1 老版本的運行截圖,爲了能作參考,我這裏把新版本的場景文件拷貝到老工程裏
編輯器


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

而後對兩個版本用Xcode作了分析,舊版本fps analyze
函數


新版本fps analyze,一樣的shader消費的ms是老版的5倍

post

發現bug後,嘗試定位問題
1 一開始認爲是marmoset版本問題,但用老版本徹底覆蓋,fps並無提高
2 刪除和場景資源相關外的全部資源,從新build後,fps就恢復了,不過這種解決方法應該是無非接受的
性能

目前臨時的解決方法,把老工程的ProjectSettings裏的文件替換過好了,具體的緣由還要繼續排查。
測試

另外有一些版本的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的設計,因此只要改幾個就行了。
fetch


要unity支持es3.0的話,須要在設置Player Settings.. 的圖形等級裏選擇 Automatic或強制gles3.0。

 
優化

若是隻用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屏幕的話,同樣會有潛在的瓶頸問題產生。

2、關於另一個場景的問題解決

Draw Call能夠先在Editor或聯機Porfile裏查看,一些設備不支持Unity Editor的GPU Profile,因此仍是要用到Xcode

沒作任何優化的前提下 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填充率的做用。

3、關於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就能夠了,這樣能夠節省skymanagerUpdatecpu消耗和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倍以上

分析能夠看下圖



  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);

上面是尚未作任何修改的shaderlod,也就是lookup_38.w仍是根據glossy map的值,在shader裏計算得出

 



  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和以前有必定的減小。

 

不太重新啓動遊戲的話,ms有了40%左右的減小,這是由於IOS作的優化,若是lod在shader運行前已經肯定的話,會直接pre fetch制定的texture,就不須要在每一個pix shader裏從新執行一次採樣了。
因此,glossy map建議適量使用,一些不須要細節的材質能夠直接用一個恆定的roughness參數替代。


還有就是關於pbr shader算法的優化,marmoset本身內部有MARMO_HQ的關鍵字,經過切換能夠實現必定程度的優化,先是兩種質量的對比

MARMO_LQ


MARMO_HQ 差異在shader的精確度上,以及出射光的亮度上

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裏還有其餘一些可優化點


  例如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的移動產品作一下競品對比的:

UE4的Sum Temple項目是個很好的參考,gles2.0的圖形規格下,也能得到很好的效果

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效果和效率的測試和優化中,必定的對比分析和借鑑,也是頗有幫助的。

相關文章
相關標籤/搜索