DrawMeshInstanced在Unity2018上不生效

这是第164篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间10分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ群2:793972859(原群已满员)


本期目录:

  • Unity2018升级DrawMeshInstanced不生效
  • Unity的Shader加载解析重复
  • 使用锁定分辨率的方式进行性能测试问题
  • 做动态图集时遇到报错
  • 同一个图集,同一个Shader无法合并

DrawCall

Q:我们对Shader的打包做法,一般是把项目的所有Shader独立打成一个AssetBundle,这样可以避免Shader的冗余,也使Shader可以热更。在Unity 5.5.4里这么做完全没有问题,所有Shader都能够正常地渲染、用于Instancing和热更。

但是在Unity 2018.3里,如果材质球和它使用的Shader没有打在同一个AssetBundle里,那么正常渲染材质球没问题,但是用这个材质球来进行GPUInstancing会不生效。试了一下Unity 2018.4也是这样。

测试工程在这里,用Unity在PC平台下就可以复现。能确认一下这个是Unity的Bug吗?还是我们对Shader打包和使用的方式有什么不对?

A:在Unity加入了Shader Stripping功能之后,就会出现很多Keywords丢失的问题。

DrawMeshInstanced在Unity2018上不生效

可以看到成功进行GPU Instancing的Shader中有Keywords:INSTANCING_ON,但是分离Shader打包,加载运行的Shader,该Keywords丢失:

DrawMeshInstanced在Unity2018上不生效

所以,解决方案之一,可以在Project Setting中,取消Stripping功能,选择Keep All:

DrawMeshInstanced在Unity2018上不生效

解决方案二,就是选择在使用了该GPU Instancing功能的场景中打包,这样该Keywords便不会被strip掉。当然方案二不太切合实际,建议还是,保留这个Material一起打包。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d077b23739f3b667bc57b95


图集

Q:我们项目中Shader的加载和解析用的是ShaderVariantCollection机制,但是在加载的时候发现这样的问题。

在加载Shader的Bundle时,发现执行Shader的Parse方法,解析了所有的Shader。

DrawMeshInstanced在Unity2018上不生效

然后再执行WarmUp的时候又解析了一遍。

DrawMeshInstanced在Unity2018上不生效

之前了解到Unity5.X后的Shader加载和解析不是分开了吗?很是疑惑,希望大神能解疑一下。(Unity版本:2018.2.19f1)

A:个人理解是这样的:

1、Shader和Shadervariant打在同一个Bundle中,对于在Shadervariant中编辑的Shader,Shadervariant会对其有一份依赖,在游戏启动的时候,加载Shader所在Bundle,然后从中Load Shadervariant,会自动触发对其依赖的Shader的Parse,对应的变体会生成一份变体Shader提交到GPU,但是这时候的变体个数并不是完全的;

2、执行Shadervariant.warmup的时候,会触发剩余的变体的生成,提交到GPU;

3、通过两步操作,第一步Shader.Parse,并生成部分变体Shader;第二步,Warmup会将剩余变体生成,以下我个人测试的截图:

DrawMeshInstanced在Unity2018上不生效

4、对比调用的次数,可见第一次Shader.Parse是并没有完全执行完所有变体的生成的。我测试过直接加载Shader所在Bundle,然后LoadAllAsset,会触发所有Shader的解析,无论是否和Shadervariant关联:

DrawMeshInstanced在Unity2018上不生效

可以看到,即使所有Shader都编译,Warmup还是会执行变体Shader的生成,可见第一步加载应该是没有执行完所有变体Shader的生成过程。

感谢zblade@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5ce5467ad1d3d045c846d769


性能测试

Q:目前项目在做性能测试的时候,会根据机型SoC(System on a Chip)来划分,同时锁定一个固定分辨率(比如:1024*768)。想问一下这种方式测试出来是否准确?

比如,两个手机,配置都是一样的,一个4K屏,一个1080P屏,锁成1024*768的分辨率,在性能上可以认为是一致的吗?

A:这种缩屏的方法在很多项目中都有应用。在渲染内容一致的情况下,无论是4K屏还是1K屏,其GPU的计算压力是一致的,唯一的区别是最后延展成的RT尺寸不一致,这块的开销是很低的。但是,因为设备GPU能力的不同(一般能有4K屏的设备,其GPU性能也是很强悍的),其最终GPU芯片上的耗时肯定是不一样的。

对于Overdraw,则同样因屏幕分辨率的不同而不同,在UWA性能报告中,你会看到真正的Overdraw仅是屏幕中的一块而已。

该回答由UWA提供,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d0319bff8404a26fbe435d1


Unreal

Q:做动态图集的时候遇到报错:Unsupported texture format - needs to be ARGB32, RGBA32, RGB24, Alpha8 or one of float formats.

本来想利用动态图集来优化一下DrawCall和内存,发现好像只能创建上面格式的Texture2D,如果用其他格式在texture.SetPixels的时候会报上面那个错误。但是上面提到的格式内存占用太大了,有办法创建其他格式的纹理吗?

代码:

Texture2D texture = new Texture2D(textureSize, textureSize, TextureFormat.DXT5, false);
Color[] fillColor = texture.GetPixels();
for (int i = 0; i < fillColor.Length; ++i)
fillColor[i] = Color.clear;
texture.SetPixels(fillColor);

A:首先要区分一个问题,这是离线生成还是Runtime生成的?离线的话有太多方法来生成,这里假设题主是Runtime生成的。对于SetPixels,Unity文档里明确了“This function works only on RGBA32, ARGB32, RGB24 and Alpha8 texture formats. For other formats SetPixels is ignored. The texture also has to have Is Readable flag set in the import settings.”,另外题主New Texture2D用的是DXT5的格式,这个格式一般只用于PC。

一种方式是用RGBA32来生成,然后压缩后再导入。不过据我所知Unity原生并不支持运行时压缩图片。所以个人建议采用另一种方式,既使用RenderTexture来复制像素,这种方式相比CPU的SetPixels要快很多,而格式方面,RenderTexture有多种格式可选,包括RGB565,ARGB4444等,在内存上比RGBA32要小。

感谢王啸予@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d0314cf18013226f621cca0


Mesh

Q:我在处理地图上节点的DrawCall的时候发现两个相同图集,相同Shader的东西竟然无法合批。提示Objects have different materials.

然后通过内存查看的发现,这个的引用竟然有很多,每个里面才是具体引用的资源。

DrawMeshInstanced在Unity2018上不生效

 

A1:目前这个找到原因了,是因为在不同的预制体使用了内置材质球,导致在不同的里面都会有一份材质球信息。所以导致了不同的Materials。要解决的话,估计要让这些预制体都引用同一个资源。UWA有个解决方案《Unity 5.x AssetBundle零冗余解决方案》。

不过有个问题。因为资源是引用了内置的Shader和Texture。那是要把内置的导成文件,然后重新设置引用吗?然后把导出的文件打成AssetBundle包吗?那为什么要放在Editor目录下,不是需要打成AssetBundle包吗?最后引用都设置好了。那为什么最后还要还原呢?
感谢题主halm@UWA问答社区提供了回答

A2:还原的做法是最初版本的策略,已经废弃,现在推荐是直接放在项目里,新创建的物体就会直接使用提取的Shader和材质了。保持提取资源名字和内置一样,新建的资源会优先使用Assets下面的。

感谢张迪@UWA问答社区提供了回答,欢迎大家转至社区交流:
https://answer.uwa4d.com/question/5d0338c318013226f621cca5


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之“石”,也能攻你之“玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859(原群已满员)

封面图:Unity Shader Repository
Unity Shader效果。

上一篇:C# 一些代码小结--UI操作


下一篇:C#反射调用类的私有方法