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效果和效率的测试和优化中,必定的对比分析和借鉴,也是颇有帮助的。

相关文章
相关标签/搜索