关于_CameraDepthTexture的疑惑

关于_CameraDepthTexture的疑惑

1)关于_CameraDepthTexture的疑惑
​2)贴图Alpha通道对图片大小的影响
3)URP要怎么实现GrabPass的效果
4)如何获取AssetDatabase加载失败的Asset的Instance ID
5)如何判断Bundle文件加载进内存的时机


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

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

Rendering

Q:一个关于_CameraDepthTexture的疑问。

如果开启_CameraDepthTexture,Camera就需要渲染一遍场景内所有带有ShadowCaster的可见物体的Pass来实现深度图。

但是场景中的物体在开启ZWrite的时候就把深度写进了Depth Buffer中了,直接获得这个Depth Buffer是不是比近乎DrawCall翻倍的方式更有效率呢?还是Unity在这方面有什么考虑?

另外,问一个更实际的问题:
我们的项目需要渲染场景的中湖水的深度效果,所有不透明的场景物体的材质都是关联同样一个Shader,这个Shader是带有ShadowCaster的。但是只有个别插入水中的物体需要去渲染ShadowCaster的Pass,有没有方法在不增加Shader的情况下,让没有插入水里的物体不渲染Shadow Caster Pass呢?我们用的是Built-in的渲染管线。

A:第一个问题,可以参考这个问题中Unity官方人员的回复。
里面讲了两个原因,第一是对于非全屏渲染的情况,本来是想拿对应相机渲染的深度,但是Depth Buffer是全屏的。第二个原因是因为很多平台不支持直接拿Depth Buffer的数据。

参考网页:
https://forum.unity.com/threads/poor-performance-of-updatedepthtexture-why-is-it-even-needed.197455/

另外查FrameBufferFetch相关问题的时候看到Unity论坛上另外一个贴子里面的回答。里面说到Unity支持了FrameBufferFetch,但是不支持DepthBuffer的获取。

参考网页:
https://forum.unity.com/threads/pixel-local-storage-and-frame-buffer-fetch-on-mobile-devices.604186/

第二个问题,如果不增加Shader,目前没想到其他好的方法。
如果可以增加Shader,可以将原来的Shader复制一份,只在ShadowCaster的部分加一个“NeedDepth”这样的Tag,将水下的物体的材质球换成这个Shader,另外做一个只有ShadowCaster并带有“NeedDepth”这个Tag的Shader,这个Shader用来做Replace操作。

额外增加一个Camera,这个Camera跟随主相机,或者作为主相机的子节点,创建一个RT,让这个Camera渲染到这个RT,在Update里面使用ReplaceShader去画一下,那么只有有那个Tag的ShadowCaster会进行深度渲染,后续可以对这个RT进行编码等操作,这个RT记录的就是水下物体的深度。整个过程看上去没有特别多的额外工作,觉得可以一试(我没有做过测试,但理论上是可行的)。

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


Texture

Q:在UWA的《纹理优化:不仅仅是一张图片那么简单》这篇文章中,描述了图片含有Alpha通道会对内存有影响。

通过以下的测试资源配置:

  • Tga_Alpha - 含有Alpha通道
  • Tga_NoAlpha - 不含有Alpha通道
  • Png_Trans - 含有透明的图片
  • 进入到Unity中的Format,全部代码设置为TextureImporterFormat.ASTC_6x6

测试结果:

  • 三张图片Unity全部Format为下图格式
  • 三张图片显示的内存大小全部一样
  • Texture Importer的Alpha Source设置为None,对测试结果无影响

    问题:图片是否含有Alpha通道,对于同一个Format格式,内存大小都是一样的吗?
    Tex.7z

A:原文中的优化建议是去除无意义的Alpha通道(原文中的定义为Alpha值全部为1的贴图),这个确实是对内存优化有帮助的。

题主的测试用例中,无论是png格式还是tga格式,进入引擎后,都会被引擎转为内部的格式(RGBA、ETC、ASTC等)。设想一下,以ETC2为例,如果没有Alpha通道,在压缩质量可以接受的情况下,就可以选用RGB_Compressed_ETC2_4bits,而如果添加了这个无意义的Alpha通道,那么我们在批量导入设置时,都会自动选择RGBA_Compressed_ETC2_8bits。这样内存就相差了一倍。

而问题中关于ASTC的情况,在Unity编辑器源码中的Texture导入格式的定义有这样一句注释:// ASTC uses 128bit block of varying sizes (we use only square blocks). It does not distinguish RGB/RGBA,即与是否包含Alpha通道无关。关于ASTC格式的介绍,这里推荐你阅读一下Github上的ASTC Format Overview

而关于你楼上回复中提到的Unity新版本的问题,可以看下Unity论坛上的这个问题

可能有人觉得对于项目的贴图格式都是ASTC来说,去除Alpha的意义不是很大,其实不能一概而论,虽然大小相同,但根据(https://zhuanlan.zhihu.com/p/158740249)中的测试,是否有Alpha通道会一定程度上影响压缩质量。所以还是要在项目中合理使用。

感谢范君@UWA问答社区提供了回答

A2:游戏运行时Texture的Alpha通道要看导入后的情况,不能看源文件的情况。UWA本地资源检测对于Texture的Alpha通道检测的就是导入后的结果。

图片源文件的格式,图形硬件是不支持的,Unity也不直接接管。导入图片后,会按照Import Settings中的设置对图片进行处理,将图片导入成硬件支持的格式(在引擎中的格式),而在运行中使用的资源也是导入后的。

题主将Alpha Source设置为None,那么导入时就不对源文件的Alpha通道进行导入,而压缩格式为ASTC_6x6,这个格式是包含Alpha通道的。这样导入后三个资源都会默认生成一个全为1的Alpha通道。占用内存大小自然一样。

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


Rendering

Q:URP如何实现GrabPass的效果?URP管线已经去掉了原先GrabPass的功能,现在有一个扭曲特效的功能,类似热扰动那种。虽然URP能够直接获取到实体图做扭曲效果,但是像是半透明物体(比如:水、其他特效等)也需要被扭曲就做不到。

A:题主想要完全实现GrabPass估计不行,但是可以有替代方案:

GrabPass的意思就是先绘制a物件,然后绘制b物件的时候影响a,绘制c物件的时候影响ab。注意,这最重要的是b物件的扰动影响不了c物件,因为b物件是比c物件先绘制的。

但是如果你能够接受b物件和c物件的扰动同时影响abc,那么就简单了,先用一个RT将扭曲的信息存下来(其实就是UV偏移),然后在Uber Shader中将偏移应用在画面上。这样扭曲信息就扰动了所有物件(不管是不透明还是半透明)。

虽然不知道URP怎么实现的,但是我们自己改的SRP,就是这么实现的。

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


Editor

Q:现在有一个继承于ScriptableObject的Asset,无论出于什么原因,引用脚本的GUID错了。那么通过一定的编辑器脚本能找到这个Asset的Path,但是如何在ProjectView内选中它?

经测试,使用Selection.instanceID是可以选中的,而Instance ID一般需要通过Object来获取,但是因为脚本引用错误了,所以AssetDatabase是无法载入这个Object的。有什么办法或者API能获取到这个Instance ID呢?

A:通过查看公开源码,找到了一个可用的方法:

//assetPath : 某个找不到对应脚本的Asset实例路径
HierarchyProperty property = new HierarchyProperty(assetPath);
Selection.activeInstanceID = property.GetInstanceIDIfImported();

这样可以在ProjectView内正确选中了。

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


Addressable

Q:当下载好所有的资源后,在一个测试脚本中调用LoadAssetAsync函数,如下图:


在AssetBundleProvider这里是第一个疑惑:
既然Addressables全部采用缓存机制来存放AssetBundle包,那此处的File.Exists不是总会为False吗?

第二个疑惑在于:
Addressables在WebRequest完成下载后,如何把握把Bundle加载进内存的时机?也可能是我的思路有问题,但是在后面的堆栈追踪里面没有发现有类似于LoadFromFile这样的调用。

A:这儿的File.Exists并不是检查缓存,而是检查文件在不在StreamingAssets里面。而所有下载的资源则是通过缓存来获取的,若缓存里没有则下载。而Load这部分已经被封装在了UnityWebRequestAssetBundle内了。

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

封面图来源于网络


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

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