问答 关于_CameraDepthTexture 的疑惑

侑虎科技 · 2020年11月09日 · 1768 次阅读

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 问答社区提供了回答

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 问答社区提供了回答

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 问答社区提供了回答

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 问答社区提供了回答

Addressable

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

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

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

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

感谢 黄程 在 UWA 问答社区提供了回答

封面图来源于网络


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

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

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册