UWA问答 | 博客 | 游戏及VR应用性能优化记录分享 | 侑虎科技 - mesh
type: channel
link: https://blog.uwa4d.com/tag/mesh/
items: URP Shader FrameBuffer Fetch Mali Crash
items: Addressable卸载AssetBundle失效的疑惑
items: Vulkan API的性能及兼容性
items: Timeline技能编辑器如何提取关键帧信息
items: Lua代码内存泄漏的疑惑
items: Unity内置资源如何打包避免冗余
items: 下载AssetBundle的Mono内存问题
items: 关于Camera.activeTexture和Camera.targetTexture的疑问
items: Unity动态网格简化算法
items: 警惕GfxDriver内存泄漏！

URP Shader FrameBuffer Fetch Mali Crash
type: item
date: 2023-05-30T04:43:00+03:00
description: 1）URP Shader FrameBuffer Fetch Mali Crash ​2）Unity模型Lightmap UV相关的疑问 3）动画上下半身融合问题 4）AnimatorControllerPlayable.PrepareFrame函数在什么情况下调用 这是第338篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：465082844 Shader Q：使用FrameBuffer Fetch华为Mali设备编译Shader直接闪退，但是如果把纹理采样去掉就正常了，有遇到过这种问题的嘛? Unity 2021.3.23 Custom SRP Device : HUAWEI P40 --- Mali-G76 设备本身支持GL_EXT_shader_framebuffer_fetch。 Shader "unlit/test" { Properties { _Color ("Main Color", Color) = (1,1,1,1) [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} } SubShader { Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" "CanUseSpriteAtlas"="True" } Pass { Name "ForwardLit" Tags {"LightMode" = "UniversalForward"} HLSLPROGRAM #define ENABLE_FRAMEBUFFER_FETCH 1 #pragma vertex Vertex #pragma fragment Fragment #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" struct Attributes { float4 positionOS : POSITION; float4 color : COLOR; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float4 positionCS : SV_POSITION; float4 texcoord : TEXCOORD0; half4 color : TEXCOORD2; UNITY_VERTEX_OUTPUT_STEREO }; TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); CBUFFER_START(UnityPerMaterial) half4 _Color; CBUFFER_END Varyings Vertex(Attributes input) { Varyings output; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.texcoord = input.texcoord.xyxy; output.color = input.color; return output; } half4 FragmentInner(Varyings input) { half4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_LinearClamp, input.texcoord.xy).rgba; return color * input.color * _Color; } void Fragment(Varyings input, inout half4 output : CoLoR0) { half4 col = FragmentInner(input); output.rgb = lerp(output.rgb, col.rgb, col.a); output.a…

Addressable卸载AssetBundle失效的疑惑
type: item
date: 2023-04-04T04:55:00+03:00
description: 1）Addressable卸载AssetBundle失效的疑惑 ​2）模型Meta中的hasExtraRoot参数的作用及其历史原因 3）TMP为什么有多次Delegate.Combine()的GC 4）准备在海外发行游戏，比较常用的身份认证类SDK 这是第331篇UWA技术知识分享的推送，精选了UWA社区的热门话题，涵盖了UWA问答、社区帖子等技术知识点，助力大家更全面地掌握和学习。 UWA社区主页：community.uwa4d.com UWA QQ群：465082844 Addressable Q：项目开发的版本是UnityWebGL，我有一个初包场景A，一个过渡场景Loading，两个用Addressables打的Bundle场景B与C，都是Remote的。 我在A场景点击按钮，使用SceneManager.LoadScene到Loading，然后用Addressables.LoadSceneAsync加载Bundle场景B，并保存了B场景的句柄Handle。 进入到B场景后，点击按钮跳转到Loading场景，然后拿到保存的B场景句柄Handle，使用Addressables.UnloadSceneAsync与Resources.UnloadUnusedAssets，然后Addressables.LoadSceneAsync加载Bundle场景C，并把原B场景的句柄Handle赋值C场景的句柄。 进入到C场景后，又切换B场景，在Google浏览器F12模式下，第二次加载B场景，网络模块下没显示场景B的Bundle。 给我的感觉是B场景的Bundle在跳转C场景的时候没有被卸载，希望能帮助解答一下这是什么原因。 我查看了源码，Addressables.UnloadSceneAsync的底层确实是调用了AssetBundle.Unload(true);的。 A：Addressable加载过一次的AssetBundle，会下载到本地硬盘缓存，Addressable.UnloadSceneAsync和Resources.UnloadUnusedAssets这两个操作只是会让相关资源从Runtime内存中卸载，不会删除本地硬盘的内容。 第二次加载是不用从远程服务器加载的，而是通过本地硬盘加载，所以不存在网络下载了。 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/642406386778221ae3095c5e Mesh Q：模型Meta中的hasExtraRoot参数的作用是什么？有什么历史原因么？ 模型Meta中有个奇怪的参数hasExtraRoot，看起来是humanDescription旗下的，但实际会对任何类型的模型都造成影响。 这个参数无论是在API还是编辑器界面，都找不到调整的地方。当前项目中一部分是0，一部分是1。观察得出，这个在为1的情况下，会保留外层无Mesh关联的Transform；为0的情况下会移除顶层Child不超过1，并且无Mesh的Transform。 不知道这个是怎么生成的，是不是为了适配某些历史版本呢？ 针对以上问题，有经验的朋友欢迎转至社区交流分享： https://answer.uwa4d.com/question/64252d9f6778221ae30a0fd9 TextMeshPro Q：TMP为什么有多次Delegate.Combine()的GC？ 只有一个界面对一个TMP的OnPreRenderText进行了一次+=的操作，为什么在其他界面也发现有Delegate.Combine()的GC，且每次大小不同？ 下图是唯一操作过的界面： 下图是其他界面，有2MB的，还有些几十KB的： 针对以上问题，有经验的朋友欢迎转至社区交流分享： https://answer.uwa4d.com/question/6423ff146778221ae30955ca Platform Q：准备在海外发行游戏，请问身份认证类SDK有哪些比较常用？最好是能直接支持Unity接入的，谢谢。 A：Google、Facebook或Game Center应该都可以。 感谢WTF-082699@UWA问答社区提供了回答，有经验的朋友欢迎转至社区交流分享： https://answer.uwa4d.com/question/6423accf6778221ae3091670 封面图来源于网络 今天的分享就到这里。当然，生有涯而知无涯。在漫漫的开发周期中，您看到的这些问题也许都只是冰山一角，我们早已在UWA问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入，也许你的方法恰能解别人的燃眉之急；而他山之“石”，也能攻你之“玉…

Vulkan API的性能及兼容性
type: item
date: 2022-11-22T04:05:00+02:00
description: 1）Vulkan API的性能及兼容性 ​2）FrameTiming.gpuFrameTime获取GPU耗时有什么条件 3）MMO里面的寻路网格如何制作 4）万国这种联盟边界的实现思路 这是第314篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Rendering Q：请问一下目前Android设备用Vulkan API的项目多吗，性能、兼容性及稳定性如何？ A：Vulkan用的比较好的应该是《天涯明月刀》手游，《王者荣耀》在三星平台上也开发过一段时间的Vulkan的版本，但是之后好像就更新打回ES版本了。 感谢萧小俊@UWA问答社区提供了回答 有没有更多的开发者能提供一些Vulkan稳定性相关的经验分享呢？欢迎大家转至社区交流： https://answer.uwa4d.com/question/6114de488f8c834241698b95 Rendering Q：手机为什么上获取不到FrameTiming.gpuFrameTime的时间？ 版本Unity 2020.3，手机华为 Mate 30P，CPU时间可以显示但GPU时间获取不到，测试代码如下： using System; using UnityEngine; using Unity.Profiling; public class FrameTimingsHUDDisplay : MonoBehaviour { GUIStyle m_Style; // Profiling state. private int frameCount = 0; private float accumulatedFrameTimeCPU = 0.0f; private float accumulatedFrameTimeGPU = 0.0f; private float frameSampleRateMS = 0.0f; private FrameTiming[] m_FrameTimings = new FrameTiming[1]; void Awake() { m_Style = new GUIStyle(); m_Style.fontSize = 15; m_Style.normal.textColor = Color.white; } void OnGUI() { CaptureTimings(); var reportMsg = $"\nCPU: {m_FrameTimings[0].cpuFrameTime:00.00}" + $"\nMain Thread: {m_FrameTimings[0].cpuFrameTime:00.00}" + $"\ncpuTimeFrameComplete: {m_FrameTimings[0].cpuTimeFrameComplete:00.00}" + $"\ncpuTimePresentCalled: {m_FrameTimings[0].cpuTimePresentCalled:00.00}" + $"\nGPU: {m_FrameTimings[0].gpuFrameTime:00.00}" + $"\nCPUTotal: {accumulatedFrameTimeCPU:00.00}" + $"\nCPUAverage: {(accumulatedFrameTimeCPU / frameCount):00.00}" + $"\nGPUTotal: {accumulatedFrameTimeGPU:00.00}" + $"\nGPUAverage: {(accumulatedFrameTimeGPU / frameCount):00.00}"; var oldColor = GUI.color; GUI.color = new Color(1, 1, 1, 1); float w = 300, h = 210; GUILayout.BeginArea(new Rect(32, 100, w, h), "Frame Stats", GUI.skin.window); GUILayout.Label(reportMsg, m_Style); GUILayout.EndArea(); GUI.color = oldColor; } private void CaptureTimings() { FrameTimingManager.CaptureFrameTimings(); uint frameTimingsCount = FrameTimingManag…

Timeline技能编辑器如何提取关键帧信息
type: item
date: 2021-12-29T09:16:00+02:00
description: 1）Timeline技能编辑器如何提取关键帧信息 ​2）Mesh资源开启R/W内存的翻倍问题 3）UI的Animator动画对Canvas.SendWillRenderCanvas()耗时影响 4）对Shader变体的理解 这是第281篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Script Q：最近在用Unity做一个技能编辑器，让策划可以在Timeline编辑器里编辑技能动画、施法特效、受击动画、受击特效和播放声音等等。编辑这些都没什么问题，我想根据编辑好的Timeline导出一系列行为节点，在Editor的环境下导出成配置（包含所有行为节点）。现在我不清楚怎么获取Timeline里第m帧开始某动画x，第n帧结束这些行为。同时怎么能给动画打上对应Tag？ A：Timeline的组成如下图： 每个Track对应一个TrackAsset其实就是一个PlayableAsset，整个Timeline也是一个TimelineAsset，里面存了所有Track的数据： 对于每个Clip的开始和结束时间在TimelineClip中可以获取： 感谢羽飞@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61c00a17d8413e18eb546b3b Mesh Q：为什么Profiler中显示开启网格的Read/Write没有使其内存翻倍，而仅仅是上升了一点？ A：如果是FBX中的网格资源，则该网格资源很有可能除了自身网格的顶点数据外，还带有动画和骨骼信息。而当开启FBX的Read/Write时，仅会使网格资源自身的内存翻倍，而动画和骨骼信息不会，且Profiler并不能将他们分开统计，从而产生了整体没有翻倍的现象，如图。 开启Read/Write： 没开Read/Write： 这一点可以通过将FBX设置中Animation Type设置为None、取消Import Animation勾选、取消Import Materials勾选证明。此时Profiler中该网格资源内存显著下降，并基本符合开启Read/Write前后内存翻倍了。 值得一提的是，在较新版本的Unity中（图截自2020.3），选中网格资源是可以看到其内存的理论大小和具体组成部分的。 感谢Faust@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61c05c15d8413e18eb54ec09 UGUI Q：对UGUI添加Animator动画会造成UI更新耗时吗？如果Animator组件处于Active状态但没有进行Loop会有持续耗时吗？ A：在Unity 2018.4版本中对于这个问题实验如下： 步骤1，场景中为一个UI添加修改Scale的动画，并复制1000个； 步骤2，添加了其Position和Color属性的动画； 步骤3，修改了所在Canvas的Render Mode为Overlay模式和Camera模式； 步骤4，修改了所在Canvas的Pixel Perfect为打开。 只进行1的情况下无论动画是否Loop，Canvas.SendWillRenderCanvas()都只会在刚开始时有一段高耗时。 而修改2之后的所有情况下，开启Loop时Canvas.SendWillRenderCanvas()始终具有高耗时。但关闭Loop后，播放完一次动画后Canvas.SendWillRenderCanvas()的耗时就始终接近于0了，如图： 而此时动画系统本身的Animator.Update()耗时仍然很高，如图： 总的来说，从2018.4上的这次实验来看，现版本的UGUI不会被不在播放状态的Animator影响而造成Canvas.SendWillRenderCanvas()耗时。 感谢Faust@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/61c05b07d8413e18eb54ea3e Shader Q：除了不建议使用Standard Shader外，还有其他的Unity默认的Shader不推荐使用吗？比如官方的Universal Render Pipeline/Particles/Unlit有6个变体，其中也用到了雾效的计算。但是我们项目中没有用到雾效，而且这个Shader用得非常多，这类情况是否有必要自己弄一个简洁版？ A：关于Shader变体数量主要影响的是Shader的…

Lua代码内存泄漏的疑惑
type: item
date: 2021-09-06T05:14:00+03:00
description: 1）Lua代码内存泄漏的疑惑 ​2）一个Lua重复加载后造成的泄露问题 3）关于Addressable中计数的疑惑 4）合并Mesh的插件推荐 这是第265篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Script Q：Lua Profiler提示调用红框中函数，每次都会增加大概0.23KB的内存，且随时间一直增加，请教一下，这个是因为闭包函数中用了局部变量i，局部table a导致的吗？ A：是局部变量table a的内存在增加。至于是否泄露：因为局部变量返回的时候被引用了，如果卸载合理，每次GC是会清除的，不会造成泄露。对代码的建议是：如果数据是相同的，建议做一个池子复用，不要每次生成。这样会造成堆内存升高导致触发GC，造成大量耗时。另外，闭包的创建也会增加内存。 感谢小ben@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/612355068f8c8342417da8a0 Script Q：现在的被动技是Lua写的，所以每场战斗会Reload，但是又没有调用package.loaded[‘xxx’] = nil来强制释放，目前用的Tolua，不知道会不会自动释放？ A：package.loaded其实是Lua内部维护的一个Table。Require的时候都会优先从package.loaded中查询一下，如果查询成功，会直接返回package.loaded[“Name”]， 如果需要释放，必须手动package.loaded[‘xxx’] = nil。 感谢萧小俊@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/6128c02c8f8c8342418590d6 Addressable Q：试用一下Addressables，看了看调试窗口，发现Instantiation Counts这里的值只要调用过一次Addressables.InstantiateAsync后就一直为1，根据文档的描述是这里是每帧Addressables.InstantiateAsync的调用次数，难道真的是每帧都在调用？还是说是Unity的显示有错？ Addressables版本1.16.19，Unity版本2020.3.14f1，测试代码如下： public AssetReference Prefab; List<GameObject> ActiveObjs; private void Update() { if (Input.GetMouseButtonDown(0)) { if (Camera.main.GetMouseInputCastPoint(Input.mousePosition, out var point)) {//这里是自己扩展的 Prefab.InstantiateAsync(point,Quaternion.identity).Completed += (op)=> { ActiveObjs.Add(op.Result); }; } } } void ReleaseInstance() { foreach (var item in ActiveObjs){ Prefab.AssetReference.ReleaseInstance(item); } ActiveObjs.Clear(); } A：这个并不是每帧调用的数据，这个面板里面统计的是“驻留”的Operation以及被引用的次数，可以帮助查看哪些该被卸载的Bundle但是却还在内存中。 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/612363588f8c8342417dc28c Mesh Q：在没有美术的前提下，Unity程序想要合并Mesh，求推荐好用的插件，我知道的有MeshBaker，有没有其它的推荐？ A1：推荐使用SimpleLod，不过这个我们没用只是测试过，主要还是MeshBaker。 感谢萧小俊@UWA问答社区提供了回答 A2：首先，StaticBatchingUtility.Combine这个方法归根结底是一个手动静态批处理的操作，它的直观作用是通过静态批处理降低DrawCall。虽然它可以合成Mesh，但是这个Mesh我确实拿不到（如果谁可以拿到请不吝赐教）。 然后回归该问题，其实需求只是一个功能性而并非优化性的问题，只要把几个Mesh拼接进一个物体就…

Unity内置资源如何打包避免冗余
type: item
date: 2021-05-14T06:06:00+03:00
description: 这是第249篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） 本期目录： Unity内置资源如何打包避免冗余 SpriteAtlas的“冗余”问题 关于Mesh占用内存的问题 UGUI.Rendering.UpdateBatches耗时较高 Plugins的DLL是如何影响Package的 AssetBundle Q：现在打包AssetBundle，Unity中内置资源能指定AssetBundle名称吗？内置资源在AssetBundle中的冗余一般是怎么解决的？ 查了现有资料，针对内置资源打包AssetBundle冗余的处理都是将内置资源提取或者下载到本地，然后修改资源的引用关系，这样打包就可以指定内置资源的AssetBundle名称。想了解下Unity现在支持脚本打包AssetBunle时指定内置资源的Bundle名称吗？从而防止多个资源依赖同一个内置资源，导致冗余吗？ A：可以使用Scriptable Build Pipeline来实现题主想要的功能，具体的方法可以参考Addressable中打包内置Shader的思路。 public static IList<IBuildTask> AssetBundleBuiltInResourcesExtraction() { var buildTasks = new List<IBuildTask>(); // Setup buildTasks.Add(new SwitchToBuildPlatform()); buildTasks.Add(new RebuildSpriteAtlasCache()); // Player Scripts buildTasks.Add(new BuildPlayerScripts()); buildTasks.Add(new PostScriptsCallback()); // Dependency buildTasks.Add(new CalculateSceneDependencyData()); #if UNITY_2019_3_OR_NEWER buildTasks.Add(new CalculateCustomDependencyData()); #endif buildTasks.Add(new CalculateAssetDependencyData()); buildTasks.Add(new StripUnusedSpriteSources()); buildTasks.Add(new CreateBuiltInResourcesBundle("UnityBuiltInResources")); //将CreateBuiltInShadersBundle改成自己创建的类 buildTasks.Add(new PostDependencyCallback()); // Packing buildTasks.Add(new GenerateBundlePacking()); buildTasks.Add(new UpdateBundleObjectLayout()); buildTasks.Add(new GenerateBundleCommands()); buildTasks.Add(new GenerateSubAssetPathMaps()); buildTasks.Add(new GenerateBundleMaps()); buildTasks.Add(new PostPackingCallback()); // Writing buildTasks.Add(new WriteSerializedFiles()); buildTasks.Add(new ArchiveAndCompressBundles()); buildTasks.Add(new AppendBundleHash()); buildTasks.Add(new PostWritingCallback()); // Generate manifest files // TODO: IMPL manifest generation return buildTasks; } [MenuItem("AssetBundles/GenerateAB")] public static void GenerateAB() { var outputPath = "Assets/AssetBundles"; if (!Directory.Exists(outputPath)) Directory.Cre…

下载AssetBundle的Mono内存问题
type: item
date: 2021-03-17T04:10:00+02:00
description: 1）下载AssetBundle的Mono内存问题 ​2）Unity 2019运行时获取Hierarchy上预制体资源路径 3）多个Submeshes模型合并后的显示问题 4）ToLua中访问Time.deltaTime为0 5）CacheServer莫名的断开连接 这是第242篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Memory Q：使用协程+UnityWebRequest下载Bundle时分配的内存释放不掉。 下载步骤如下： 1. 使用协程+UnityWebRequest下载Bundle； 2. 使用BinaryWriter将UnityWebRequest.downloadHandler.data的数据写入机器； 3. 调用UnityWebRequest的Dispose函数； 4. 调用Resources.UnloadUnusedAssets()，UnityWebRequest.ClearCookieCache()和System.GC.Collect()。 下载每一个Bundle都会执行如上流程，但是Profiler调试真机发现，分配的内存无法释放，会把Mono内存越撑越大，请问大家遇到过这种情况吗？ A：之前遇到过类似的问题，题主可以参考一下，我们使用的Unity版本是2018.4.31。 不管是之前的WWW还是现在的WebRequest，都是使用的其成员DownloadHandler进行下载。当你访问“.data”属性时，其实访问的是一个“GetData()”函数的包装，这个函数返回的是一段native-memory data buffer的拷贝，这也是问题的根结所在。 第一个可以优化的点就是减少“.data”的使用，用临时变量缓存下来。 第二个就是替换DownloadHandler，Unity提供了多种DownloadHandler，我们当时是下载图片，所以用的是DownloadHandlerTexture，看你的问题，可以试试DownloadHandlerAssetBundle。 参考：https://docs.unity3d.com/ScriptReference/Networking.DownloadHandlerAssetBundle-ctor.html 感谢Joke@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5d443ae927d7e5590f6cd84b Editor Q：美术希望在编辑器运行的状态下获取场景GameObject实例对应预制体的路径，以前Unity 2017是可以通过var pRoot = PrefabUtility.GetPrefabParent(go); return AssetDataBase.GetAssetPath(pRoot)，获取运行时预制路径的。 最近升级到2019发现接口已经更新，PrefabUtility.GetPrefabInstanceHandle(targetGameObject)、PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab)等接口都不能在Unity运行的时候去获取Hierarchy里面的GameObject路径。 我问题里面的关键是运行状态，也就是点了播放，然后获取Hierarchy上预制的存储路径。PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab)不点播放是可以获取，播放了只能获取Project上预制的存储路径。 A：PrefabUtility.GetNearestPrefabInstanceRoot：获取最近的预制体实例Root。 PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot：获取预制体路径。 if (PrefabUtility.IsPartOfPrefabInstance(seletedGo)) { string prefabAssetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(seletedGo); } GetPrefabAssetPathOfNearestInstanceRoot可以获取路径，“PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(prefab…

关于Camera.activeTexture和Camera.targetTexture的疑问
type: item
date: 2020-11-18T04:53:00+02:00
description: 1）关于Camera.activeTexture和Camera.targetTexture的疑问 ​2）如何降低动画文件的浮点数精度 3）使用EasyMovieTexture在Android播放视频失败 4）模型顶点色（Color）如何去除 5）多层3D场景寻路方案探讨 这是第227篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） Rendering Q：一直有个疑惑，Camera.activeTexture和Camera.targetTexture在Get的时候，Get到的是一个RenderTexture吗？ 我知道这两个的区别是一个只能获得当前所正在渲染的RenderTexture，一个是既可以获得也可以设置渲染目标，但这样activeTexture有什么必要性呢？ 是我对这两个的理解有错误吗？还有大家平时说的Backbuffer，在我渲染目标一直是屏幕的时候，这两个方法获得的都是Backbuffer吗？ A：第一个问题：Camera.targetTexture必须在相机指定Render Target才会非null，Camera.activeTexture获取到的值和调用的时机有关系。官方文档中写着可以在OnPostRender中获取到，比如使用了后处理，在OnPostRender中可以获取到后处理申请的RenderTexture，在Update中获取就是null。如果给相机设置了RenderTexture，那么targetTexture就是设置的RenderTexture。如果没有开启HDR，在OnPostRender中activeTexture获取到的也是这个RenderTexture。如果开启了HDR，则是一个另外申请的RenderTexture。 第二个问题：推荐使用RenderDoc查看渲染状态，分为两种情况，在安卓平台上开启了Always Blit和没开启会不一样。开启了Always Blit，会在最后多一个Present的过程，在Present之前，会将所有的渲染渲染到一个叫tex的RenderTexture上（这里不考虑后处理以及HDR导致生成了额外的RenderTexture），在Present的时候将tex Copy到Backbuffer里面。如果没有开启AlwaysBlit，比如Blit Type是Never，那么所有的渲染都是直接渲染到Backbuffer的（这里同样不考虑RenderTexture的情况），Blit Type为Auto的时候没有遇到出现Present的情况，在线性空间也没出现Present 。Backbuffer和那个用来Present的tex这两个对象都可以理解为系统提供的，从C#脚本中是没法获取到的，而且从Profiler里面也是看不到这两个对象的大小的。 总结起来就是：大部分情况下Camera.targetTexture都是为null的，除非相机设置了RenderTarget。 对于Camera.activeTexture，这个需要看调用时机，在OnPostRender中调用，如果有使用后处理或者HDR，则可以获取到申请到的RenderTexture，在Update里面获取是null的，其他的函数阶段没有详细测试过。 对于Backbuffer，这个系统是提供的，C#脚本是获取不到的。而且不一定是直接绘制到Backbuffer，就算没有使用后处理或者HDR，如果开启了Always Blit，也是会多一个中间层，在最后阶段中间层会Copy到Backbuffer。 感谢Xuan@UWA问答社区提供了回答，欢迎大家转至社区交流： https://answer.uwa4d.com/question/5faa4c5fdc477370c2c1f104 Animation Q：动画文件后处理可以做两件事，精度压缩，Scale曲线剔除。比起用工具修改原始FBX文件，这样比较灵活。 实际测试，在开启Optimal压缩的情况下，加上这个后处理，能再节省40%左右。 示例代码和测试结果见知乎专栏： https://zhuanlan.zhihu.com/p/27378492 void OnPostprocessModel(GameObject g) { // for skeleton animations. List<AnimationClip> animationClipList = new List<AnimationClip>(AnimationUtility.GetAnimationClips(g)); if (anim…

Unity动态网格简化算法
type: item
date: 2018-11-01T09:31:00+02:00
description: 在游戏开发中，我们有时需要对美术同学给出的模型进行简化。目的是在减少面数的同时，尽可能的维持模型的外观。这种技术可以用在LOD（Levels of Details）上，当模型与摄像机的距离大于一定值之后，使用面数较少的模型来代替高模，这样可以减少GPU带宽消耗和渲染压力。 简化分为三种： 静态的； 动态的； 视角依赖的。 通常情况下，我们会让美术提供面数不同的几个模型，或者我们使用工具对高模进行减面并存成多个Mesh，然后在游戏运行的时候，根据模型与摄像机的位置关系，动态的替换Mesh。这是一种静态的方法。 本文将讨论一种动态的网格简化算法。这种算法的好处在于，美术只需要提供一个高模，程序便可以自动的生成量级不同的低模。 原文链接： http://dev.gameres.com/Program/Visual/3D/PolygonReduction.pdf（感谢UWA答主马古斯提供的文章和思路） 三角边坍缩 这里使用了三角边坍缩的方法来进行网格简化，将两个顶点合并成一个顶点，如图所示： 对于要坍缩的边uv，删除这条边两侧的面A和面B，用v来替换u，连接v和u的其他邻居点，并删除u。其中v称为u的坍缩目标。 对于一个实体模型（具有封闭的边界，根据边界可以将空间分为模型内部和模型外部两部分），一次坍缩，可以移除两个三角面，三条边和一个顶点。通过反复的迭代，最终就会使模型简化到预期的面数。 但是如何选择要移除的点，才能尽可能小的影响模型的外观呢？这里就需要用到坍缩代价计算公式： 其中Tu是包含顶点u的三角形的集合，Tuv是同时包含顶点u和顶点v的三角形的集合。 上面公式表示将u坍缩到v（移除u）所需要的代价。第一部分是边的长度，直观上讲，在模型简化过程中，小的细节应该优先被移除。第二部分是u点周围的曲率变化，理论上曲率变化越小的顶点，所处的区域越平坦，应该优先被移除。需要注意的是，将u坍缩到v和将v坍缩到u的代价可能不一样。 通过这个公式，我们就可以对每个点计算坍缩到其相邻点的代价，然后选取坍缩代价最小的相邻点作为其坍缩目标。 实现细节 根据以上的描述，可以将实现分为以下步骤： 1.搜集顶点、三角面和三角边的关系； 2.计算坍缩代价和坍缩目标，并排序； 3.替换坍缩代价最小的点，并重新计算相邻点的坍缩代价和坍缩目标，更新有序列表； 4.判断当前顶点数量是否大于目标数量，是则重复第3步。 显然，在游戏中实时的进行以上步骤是不现实的，尤其是第2步，相当于对整个模型的所有顶点遍历了多次。所以，要将它拆分成离线烘焙和运行时两个部分。 离线烘焙 离线烘焙会输出两个int数组：permutation和vertex_map。 步骤： 1）收集顶点信息：主要是顶点位置和index，另外需要初始化两个列表：包含顶点的三角面列表和顶点的邻居列表； 2）收集三角面信息：获取每个三角面所包含的三个顶点，并计算法线（用于计算曲率）；同时，将该三角面加入顶点的三角面列表，并将每个顶点加入另外两个顶点的邻居列表中去； 3）计算顶点与其邻居点的坍缩代价，选择坍缩代价最小的邻居点作为坍缩目标； 4）依据坍缩代价对所有的顶点进行排序； 5）替换坍缩代价最小的顶点：获取坍缩代价最小的顶点u及其坍缩目标顶点v，遍历u的三角面列表，如果包含v就删除该三角面，否则将u替换为v。重新计算u的邻居点的坍缩代价和坍缩目标，并更新列表； 6）令permutation[u.index] = 当前顶点数量，令vertex_map[u.index] = v.index (如果没有坍缩目标，则赋值为-1)； 7）判断当前顶点总数是否大于0，是则重复第5步。 permutation保存了每个顶点被移除的倒数次序（1是最后被移除的，最大的是第一个被移除的），vertex_map保存了每个顶点的坍缩目标的位置。 运行时 输入需要绘制的最大顶点数量n。 步骤： 1.遍历三角面 1.1 获得当前三角面的三个顶点的index，即idx0、idx1和idx2。 1.2 如果permutation[idx0] >= n，则idx0=vertex_map[idx0]，否则执行1.5。 1.3 如果idx0==-1 or idx1 == idx0 or idx2 == idx0，该三角面不参与绘制。同理映射并判断idx1和idx2。 1.4 返回1.1。 1.5 当前三角面加入绘制列表。 2. 根据三角面的数据，整理顶点属性。 此外，网格的原始信息会被保留，在游戏运行期间，就可以在任意LOD上自由切换。 细节优化 为了得到更好的性能和较好的效果，本文还对上面的步骤进行了一下优化： 1）最小堆排序：离线烘焙第4步中，被移除点的邻居点需要重新计算坍缩代价，也就意味着坍缩列表也会动态变化。所以这里使用最小优先队列（最小…

警惕GfxDriver内存泄漏！
type: item
date: 2018-06-05T04:25:00+03:00
description: 本期聚集话题： UGUI Android齐刘海适配、UWA GOT测试Mono卡顿、如何清除Unity中创建的Mesh的顶点色、MeshBaker的适用性... 这是第114篇UWA技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题，建议阅读时间10分钟，认真读完必有收获。 UWA 问答社区：answer.uwa4d.com UWA QQ群2：793972859（原群已满员） 内存 Q：我用的是Unity 2017.2.0这个版本，在 PC Editor 上，Profiler 显示 GfxDriver 不断增加，经排查是由 Canvas 里一个游戏对象引起，该游戏对象成分如下： 只要将该游戏对象关闭，GfxDriver 立刻停止增加，因此我怀疑该版本的 Unity 存在问题，导致这种制作动画的方式都会引发内存泄漏，于是我把该游戏对象拉到一个空场景中，然而并没有发现 GfxDriver 增加。到此，不知道该怎么进一步排查问题。 这是Unity 2017上UGUI的Bug，在Unity 2017.1版本中无论是Editor还是Release版本都会出现该泄露问题。 Release版本在2017.2以后被修复，但Editor版本要在2017.4.1版本以后才被修复。 对于真机版本，题主在当前版本中可不用担心，如果担心Editor版总是因为内存过大而崩溃，可以尝试升级到2017.4.1以后。 该回答由UWA提供，欢迎大家转至社区进行进一步交流： https://answer.uwa4d.com/question/5b0fa6a754646026e9ddd6d7 UI制作 Q：有人做过 UGUI Android齐刘海（如荣耀10）的适配吗？大家有什么经验可以分享的吗？ 给个简单的方案吧，以iPhone X为例。 1）准备launch image，以关闭iPhone X默认的两侧黑边。（Unity 2017之后可以直接提供x的闪屏图片，可略过此步骤） cp -R "../yourPorject/Assets/ArtResources/SplashScreen/iphonex_h.png" "./Unity-iPhone/Images.xcassets/LaunchImage.launchimage/iphonex_h.png" cp -R "../yourPorject/Assets/ArtResources/SplashScreen/iphonex_v.png" "./Unity-iPhone/Images.xcassets/LaunchImage.launchimage/iphonex_v.png" cp -R "../yourPorject/Assets/ArtResources/SplashScreen/Contents.json" "./Unity-iPhone/Images.xcassets/LaunchImage.launchimage/Contents.json" 2）我们在UGUI Root下，有个desktop的概念，作为所有UI的祖先层，设为水平垂直方向均为stretch, Top设为88, Bottom设为-88。（88是最小间隔，132是官方推荐的安全间隔）。 其中第2步对其他ui使用者都是透明的，两侧填充无意义的UI图片，对UI制作上也几乎没有影响。整个改造过程很短，推荐尝试。 PS：未考虑iPhone X的横条。 感谢史云柯@UWA问答社区提供了回答 有一个简单的方案，就是给最上层界面配置一个横纵Stretch自动拉伸的RectTransform，检测当发现是iPhone X时，打开界面代码中自动设置 Left Top Right Bottom 为44.这个方案我在雨松那里看到的，是个很简单粗暴的方案，当然有些地方可能还要微调一下。参考网址：http://www.xuanyusong.com/archives/4464 感谢小小克劳德@UWA问答社区提供了回答 此问答来自问答社区，欢迎大家转至社区进行进一步交流： https://answer.uwa4d.com/question/5b0cd5fa09749726e4188d42 资源 Q：Unity中创建的Mesh为什么带有顶点色？如何才能创建不带顶点色的Mesh？或者怎么在unity中把顶点色给抹掉？ 我已经做过以下尝试： 1）mesh.color = null，mesh.colors32 = null 没用。 2）重新new一个Mesh，不赋值顶点色，没用。 3）转成obj再放到Unity中看，居然还有顶点色。但是把obj放到Max中看，是没有的，转成FBX再放到项目中，还是有顶点色。 经过一番探索，发现问题：关闭Use Direct…