企业网站剖析,wordpress 谷歌字体解决,想做个赚钱的网站不知道做那种,网页设计与制作试卷分析报告文章目录 目的问题解决方案验证保存为 Unity Mesh 结果 - OK保存为 *.obj 文件结果 - not OK#xff0c;但是可以 DIY importer注意References 目的
备忘#xff0c;便于日后自己索引 问题
为了学习了解大厂项目的效果#xff1a; 上周为了将 王者荣耀的 杨玉环 的某个皮肤… 文章目录 目的问题解决方案验证保存为 Unity Mesh 结果 - OK保存为 *.obj 文件结果 - not OK但是可以 DIY importer注意References 目的
备忘便于日后自己索引 问题
为了学习了解大厂项目的效果 上周为了将 王者荣耀的 杨玉环 的某个皮肤的头发效果还原 所以我想直接抓模型再还原 shader 我使用的还是以前的老方法 GPA 夜神模拟器具体可以查看以前的另一篇教程具体参考教你如何使用GPA导出模型另送一个 GPA CSV2MESH Tool in unity
抓出来的数据导出 FBX 后我看不出什么异常
直到我逐行的 shader 还原效果的时候 发现 vertex input 数据有 float4 uv1 : TEXCOORD1; float4 uv2 : TEXCOORD2;
但是发现 shader 调试发现uv1, uv2 使用颜色输出都发现了数据不对的 BUG
然后我还想在 unity Game 视图下使用 RenderDoc 抓帧分析一下 结果 Load RenderDoc 之后直接导致 unity 闪退
瞄了一下 CSharp 代码发现我使用的是 Mesh.uv APIgetter and setter 都是 Vector2[] 的所以 zw 是不可能设置上的
然后瞄了一下 Mesh 是有 void SetUVs(int channel, Vector4[] uvs) 的 API 的 但是经过测试还是发现 UV的 zw 无法保存下来
最终我问了一下unity 技术官方结果他们测试是OK的 (因为他们是对 Mesh 内存数据的实时修改) 然后我也试了一下确实OK但是经过自己跟进一步测试发现使用 FBX Exporter 导出之后UV 还是会丢失的 我将测试总结一下 unity Mesh 中会保存 uv vector4 的数据到时经过 FBX Exporter 插件导出之后uv 就不可能保存 Vector4 了
然后我分析了一下 FBX Exporter 插件的代码 发现一丢丢问题 我将 FBX Exporter Local 化后再按照我下面截图的内容修改后还是无法导出 如何 local 化可以参考我之前的文章Unity - 如何修改一个 Package 或是如何将 Package Local化 发现 Unity 中 AutoDesk 的 package 里面封装的 API FbxLayerElemetnUV.Create 进入是继承 UV2 的 也要先 local但是这个 package 比较特殊在 PackageManager 中不显示的方法可以是先从 Library/PackageCache/com.autodesk.fbx4.2.0 剪贴到 [项目目录]/Packages/下面然后使用 Package add from disk 的方式 然后再开始修改代码 从 public class FbxLayerElementUV : FbxLayerElementTemplateFbxVector2 修改为 新 public class FbxLayerElementUV : FbxLayerElementTemplateFbxVector4 结果发现还是不行 因为之前说的unity editor 下无论 game view, 还是 scene view 直接 Load RenderDoc 都会导致unity 闪退 然后我再使用 RenderDoc 真机 抓帧分析果然是没有 vertex input TEXCOORD0 zw 分量数据的 解决方案
于是我就有点怀疑 FBX 是不能保存 uv 超过4 分量数据的 然后百度 ‘fbx 文本 file header’ 找到这篇
FBX文件结构解读【文本格式】 译文原始地址在这FBX文件结构解读翻译之前的原文在这A quick tutorial about the FBX ASCII format
google ‘fbx ascii file header’ 找到
FBX binary file format specification - blender 的 再 ‘How to save uv data more than 4 components in fbx file’ 找到FBX export/import only supports Vector2 in UV (but the uvs can contain upto Vector4 in Unity) - 这个人遇到的问题和我一模一样里面的解决方式就是使用 AssetData.CreateAsset(mesh, path) 的方式来解决的
经过前面 还有很多篇
看完 ascii 格式的 FBX 头文件后我就知道uv 存不了 vector4 了那我就在猜
王者荣耀 也是使用 unity 开发的难不成他们 TEXCOORD[N] 保存超过 2 个以上的分量数据都是使用 unity Mesh 的方式来保存的吗 验证
试一下 unity mesh 能否成功 - OK测试一下 *.obj 格式能否将 uv 保存超过 2 个分量以上的数据 - OK但是AB打包可能不会打进去目录中注意的部分会有讲到 保存为 Unity Mesh 结果 - OK
先构建uv数据 然后设置数据 然后 shader 打印
之前的z是全黑色w全白色现在都有对应的强度了OK说明 unity mesh 还是OK的 想要了解 unity mesh 如何保存数据我们可以将 AssetDatabase.CreateAsset 之后的 Mesh.asset 文件用文本编辑器打开瞄一下就好啦 保存为 *.obj 文件结果 - not OK但是可以 DIY importer
首先我们用 blender 简单整一个 cube将 uv 展好如下
然后导出 *.obj 放到 unity 里面瞄一下如下图 然后我们直接给 obj 里面的 vt 增加 字段数据的分量看看 unity 有否变化然后发现是没有变化的
然后我们发现修改不了 原始的 .obj 里面在 library 下的 mesh cache 信息 .fbx 同样如此
比如下面的代码我将问题写在注释了 var assetObj AssetDatabase.LoadAssetAtPathObject(assetPath); // assetObj nullvar modelPrefab AssetDatabase.LoadAssetAtPathGameObject(assetPath); // modelPrefab nullvar mesh_filter modelPrefab.GetComponentInChildrenMeshFilter(); // 所有导致 modelPrefab 出现空引用的 BUG完整如下 public class AssetsImporterExt : AssetPostprocessor
{private void OnPreprocessModel(){var mi assetImporter as ModelImporter;if (mi null) return;// assetPath Assets/Test/Test_uv.objvar assetPath assetImporter.assetPath;var assetObj AssetDatabase.LoadAssetAtPathObject(assetPath); // assetObj nullvar modelPrefab AssetDatabase.LoadAssetAtPathGameObject(assetPath); // modelPrefab nullvar mesh_filter modelPrefab.GetComponentInChildrenMeshFilter(); // 所有导致 modelPrefab 出现空引用的 BUGif (mesh_filter null) return;var mesh mesh_filter.sharedMesh;var uvs new ListVector4();mesh.GetUVs(0, uvs);var ext System.IO.Path.GetExtension(assetPath).ToLower();if (ext .obj){var spliter new string[] { };var sb new StringBuilder();var dirty false;using(var reader new StreamReader(assetPath)){var idx 0;while (!reader.EndOfStream){var line reader.ReadLine();if (line.StartsWith(vt)){sb.Clear();var args line.Split(spliter, System.StringSplitOptions.RemoveEmptyEntries);if (args.Length 3) sb.Append(args[3]);if (args.Length 4) sb.Append( args[4]);Debug.Log($extension uv data zw : {sb});var uv_data uvs[idx]; // get from arrayif (args.Length 3){if (!float.TryParse(args[3], out float val)|| float.IsNaN(val)|| float.IsInfinity(val)){val 0f;}uv_data.z val; // update z component}if (args.Length 4){if (!float.TryParse(args[4], out float val)|| float.IsNaN(val)|| float.IsInfinity(val)){val 0f;}uv_data.w val; // update w component}uvs[idx] uv_data; // update to arrayidx;dirty true;} // end of if (line.StartsWith(vt))} // end of while (!reader.EndOfStream)} // end of using(var reader new StreamReader(assetPath))if (dirty){EditorUtility.SetDirty(mesh);EditorUtility.SetDirty(modelPrefab);AssetDatabase.SaveAssetIfDirty(modelPrefab);}} // end of if (ext .obj)}
既然 原始模型的 mesh 修改不了那么我们可以处理 prefab 里面的 mesh下面进行尝试一下 其实这帖子 FBX export/import only supports Vector2 in UV (but the uvs can contain upto Vector4 in Unity) 里面也有人是这样的思路如下图
先来一段代码看看能否修改成功 private void OnPostprocessPrefab(GameObject gameObject){var mf gameObject.GetComponentInChildrenMeshFilter();if (mf null) return;var mesh_path AssetDatabase.GetAssetPath(mf.sharedMesh);Debug.Log($mehs_path : {mesh_path});var mesh mf.sharedMesh;var uvs new ListVector4();mesh.GetUVs(0, uvs);var ext System.IO.Path.GetExtension(mesh_path).ToLower();if (ext .obj){var spliter new string[] { };var sb new StringBuilder();var dirty false;using (var reader new StreamReader(mesh_path)){var idx 0;while (!reader.EndOfStream){var line reader.ReadLine();if (line.StartsWith(vt)){sb.Clear();var args line.Split(spliter, System.StringSplitOptions.RemoveEmptyEntries);if (args.Length 3) sb.Append(args[3]);if (args.Length 4) sb.Append( args[4]);Debug.Log($extension uv data zw : {sb});var uv_data uvs[idx]; // get from arrayif (args.Length 3){if (!float.TryParse(args[3], out float val)|| float.IsNaN(val)|| float.IsInfinity(val)){val 0f;}uv_data.z val; // update z component}if (args.Length 4){if (!float.TryParse(args[4], out float val)|| float.IsNaN(val)|| float.IsInfinity(val)){val 0f;}uv_data.w val; // update w component}uvs[idx] uv_data; // update to arrayidx;dirty true;} // end of if (line.StartsWith(vt))} // end of while (!reader.EndOfStream)} // end of using(var reader new StreamReader(assetPath))if (dirty){mesh.SetUVs(0, uvs);EditorUtility.SetDirty(mesh);EditorUtility.SetDirty(gameObject);AssetDatabase.SaveAssetIfDirty(gameObject);AssetDatabase.SaveAssets();AssetDatabase.Refresh();}} // end of if (ext .obj)}OK有了上面的 postprocess 代码 prefab我们 reimport 测试一下 可以看到 Test_uv.obj 里面的 mesh 的 uv 从 flaot2 变成了 float4 了如下图
然后我们看一下 测试 shader 的效果发现是有数据异常的一部分有设置成功一部分没有那么很有可能是 *.obj 的顶点数解析和unity不一样
首先瞄一下*.obj 里面有 14 条 uv 信息 xy 分量是原来的后面的 zw (0.25, 0.5) 都是我后续增加的
然后我们断点发现unity 解析出来会有 24 个 uv 信息如下图
观察了一下规律可以发现他将一些多面共点拆分为分别的三角面的对应的独立点 因此我们可以根据 uv.xy 如果坐标相同那么我们就将 uv.zw 记录一份共享这些 uv.xy 的数据的 zw 数据即可 继续修改一下代码 private void OnPostprocessPrefab(GameObject gameObject){var mf gameObject.GetComponentInChildrenMeshFilter();if (mf null) return;var mesh_path AssetDatabase.GetAssetPath(mf.sharedMesh);Debug.Log($mehs_path : {mesh_path});var mesh mf.sharedMesh;var uvs new ListVector4();mesh.GetUVs(0, uvs);var ext System.IO.Path.GetExtension(mesh_path).ToLower();if (ext .obj){var dict new Dictionarystring, Vector2();var spliter new string[] { };var sb new StringBuilder();var dirty false;using (var reader new StreamReader(mesh_path)){var idx 0;while (!reader.EndOfStream){var line reader.ReadLine();if (line.StartsWith(vt)){sb.Clear();var args line.Split(spliter, System.StringSplitOptions.RemoveEmptyEntries);if (args.Length 3) sb.Append(args[3]);if (args.Length 4) sb.Append( args[4]);Debug.Log($extension uv data zw : {sb});var uv_data uvs[idx]; // get from arrayvar key1 float.Parse(args[1]).ToString(0.000000);var key2 float.Parse(args[2]).ToString(0.000000);var key ${key1},{key2};if (!dict.TryGetValue(key, out var zwVec)){if (args.Length 3){if (!float.TryParse(args[3], out float val)|| float.IsNaN(val)|| float.IsInfinity(val)){val 0f;}uv_data.z val; // update z component}if (args.Length 4){if (!float.TryParse(args[4], out float val)|| float.IsNaN(val)|| float.IsInfinity(val)){val 0f;}uv_data.w val; // update w component}zwVec.x uv_data.z;zwVec.y uv_data.w;dict[key] new Vector2(zwVec.x, zwVec.y); // update to dict}uvs[idx] uv_data; // update to arrayidx;dirty true;} // end of if (line.StartsWith(vt))} // end of while (!reader.EndOfStream)} // end of using(var reader new StreamReader(assetPath))if (dirty){// 将 xy 相同的都共用 uv.zw 数据for (int i 0; i uvs.Count; i){var uv uvs[i];var key ${uv.x.ToString(0.000000)},{uv.y.ToString(0.000000)};if (dict.TryGetValue(key, out var zwVec)){uv.z zwVec.x;uv.w zwVec.y;uvs[i] uv;}}mesh.SetUVs(0, uvs);EditorUtility.SetDirty(mesh);EditorUtility.SetDirty(gameObject);AssetDatabase.SaveAssetIfDirty(gameObject);AssetDatabase.SaveAssets();AssetDatabase.Refresh();}} // end of if (ext .obj)}查看渲染结果正常了
然后我们试试修改 *.obj 里面的uv 扩展数据瞄一下效果如何
最后的渲染效果如下 注意 *.obj 这种方式暂时没去验证能否将打包出来的 ab 里面的 mesh 修改因为里头的文件信息是再 library 里面的临时生成的问题打包不会打包进去 但是使用 *.asset 来保存 unity mesh 的方式肯定可以因为变成了文件信息 References
FBX export/import only supports Vector2 in UV (but the uvs can contain upto Vector4 in Unity)