以前写过一篇:Unity - RenderDoc 抓帧导出 FBX(带UV)
吐槽
我估计GPA是怕收律师函,因为如果 GPA 将所有资源一键提取,一键导出,那么可能很多开发商会告他
GPA Geometry Output 没有 UV
可以看到也好几个帖子问 GPA 官方,都是被官方忽悠回答了:
- UV MAPS capture
- GPA: No UV map support?
(除了这个,我自己还搜索过还几个类似有人问这个问题,结果同样被官方忽悠)
- 我之前尝试过用 GPA,RenderDoc 来抓取模型,结果 GPA 导不出 UV,而且 VBV 数据长度还对不上,RenderDoc 还不能对抓取模拟器 - unity shader - 圣斗士星矢 人物 shader 还原 - GPA 抓帧提取资源、shader,ROOT权限、救砖、ro.debuggable=1(最终还是RenderDoc无法抓帧) - 在现在这篇文章我尝试着将不同 VBV 元素长度的组装,我都以 indices 的长度来读取顶点数据的长度来构建模型,结果发现还真的可行,就是有不少无用的 primitive
- RenderDoc 是可以直接导出带 UV 的,可以查看我之前的一篇:Unity - RenderDoc 抓帧导出 FBX(带UV)
既然GPA不整模型导出带UV,那么今天我们实现一个 GPA 中的模型导出 UV 的工具
问题实例
如果直接将 input gemoetry 导出
会得到一个除了 position 之外,没有其他数据的网格,如下:
然后,对应的 shader vs input 有6个 register
如果我们要向将这些顶点数据都导出来,直接使用 GPA 功能默认的Geometry output是导不出来的
开始实现
提取 VBV, IBV
上面的 VS_INPUT
可以看到 input attribute 的定义
但是这些数据是从哪些 VBV(vertex buffer viewer) 输入的呢?
我们可以点击 Resource 中的 Shader,选择:Vertex shader 后
然后查看使用到的数据有哪些,如下图:
OK,留意:
然后我们可以将每个 VBV 个、单个 IBV 设置导出 CSV Titles 格式,下面以导出 position.csv 为例
- 根据shader input attribute 定义,定位使用的 vbv序号
- 在 resource 中,找到对应的 vbv
- 给 vbv 的 titles 设置好格式
- 最后 导出 csv
其他的 tangent, normal, uv0, uv1, color0 都可以使用类似的方式导出,如上图,这个模型的数据我是使用下面的格式导出的
因为我们使用的是 unity mesh,那么TEXCOORD0 的 position 我们需要将其 semantic 修改为 POSITION,同理,normal 和 uv0 都使用对应的:NORMAL, TEXCOORD0 来替代
参考如下(注意每个 shader 的 VBV 是干嘛用的,需要自行去查看 shader 怎么使用,以此分析他们的所属的 semantic,因为每个 shader 都有可能不一样):
VBV, IBV 导出的 csv format:
-
position : VBV1 -
float POSITION.x;float POSITION.y;float POSITION.z;
-
tangent : VBV2 -
float TANGENT.x;float TANGENT.y;float TANGENT.z;float TANGENT.w;
-
half
精度的 tangent :half TANGENT.x;half TANGENT.y;half TANGENT.z;half TANGENT.w;
- 有些精度低一些,为了性能考虑的是有的,抓帧逆向效果都可以看到很多地方有类似的做法
-
-
normal : VBV3 -
float NORMAL.x;float NORMAL.y;float NORMAL.z;
-
half
精度的 tangent :half NORMAL.x;half NORMAL.y;half NORMAL.z;
-
-
uv0 : VBV0 -
half TEXCOORD0.x;half TEXCOORD0.y;byte4p
-
uv1 : VBV0 -
byte4p; half TEXCOORD4.x;half TEXCOORD4.y;
-
color0 : VBV1
float TEXCOORD5.x;float TEXCOORD5.y;float TEXCOORD5.z;float TEXCOORD5.w; byte4p
ubyte COLOR0.x;ubyte COLOR0.y;ubyte COLOR0.z;ubyte COLOR0.w; byte4p
-
ubyte TEXCOORD5.x;ubyte TEXCOORD5.y;ubyte TEXCOORD5.z;ubyte TEXCOORD5.w; byte4p
- 这个会使用比较多,但是这个有些问题:没有 normalized -
nubyte TEXCOORD5.x;nubyte TEXCOORD5.y;nubyte TEXCOORD5.z;nubyte TEXCOORD5.w; byte4p
- 然后添加了前缀n
后,还是不能 normalized,所以这个我在工具中特殊弄了一些开关,可是设置 VBV 是否需要 normalized
-
index : IBV - 不需要格式,直接导出,只要确保第二列是 index 的值即可
另外要记得[type][n]p的padding设置,这样才能stride到对应的vertex data 长度
比如下面的法线,使用的是 half 精度的,而且有 36 个 byte 的 padding
那么我们使用: half NORMAL.x;half NORMAL.y;half NORMAL.z;half NORMAL.w;byte36p;
list view 格式即可
GPA buffer list view format 攻略
上面我是提取: 《CFDG》 的方式,可以罗列出下面的 buffer view format,基本上 CFDG 的 MRA 流 PBR 都是这套规则即可
// jave.lin : 下面提供 list view format 的样例,可以用于CTRL+C,V到 GPA list view 中
// 注意 : padding 不要处理
// 注意 : semantic 要设置对 (依赖 shader 分析 对应的作用后,才能正确设置 semantic)
// position-float3
float POSITION.x;float POSITION.y;float POSITION.z;
// tangent-float4
float TANGENT.x;float TANGENT.y;float TANGENT.z;float TANGENT.w;
// tangent-half4
half TANGENT.x;half TANGENT.y;half TANGENT.z;half TANGENT.w;
// normal-float4
float NORMAL.x;float NORMAL.y;float NORMAL.z;float NORMAL.w;
// normal-half4
half NORMAL.x;half NORMAL.y;half NORMAL.z;half NORMAL.w;
// normal-float3
float NORMAL.x;float NORMAL.y;float NORMAL.z;
// normal-half3
half NORMAL.x;half NORMAL.y;half NORMAL.z;
// uv0-float2
float TEXCOORD0.x;float TEXCOORD0.y;
// uv0-half2
half TEXCOORD0.x;half TEXCOORD0.y;
// uv1-float2
float TEXCOORD1.x;float TEXCOORD1.y;
// uv1-half2
half TEXCOORD1.x;half TEXCOORD1.y;
// color0-ubyte4
ubyte COLOR0.x;ubyte COLOR0.y;ubyte COLOR0.z;ubyte COLOR0.w;
工具演示导出
GPA 的 VBV,IBV的 BUG
我之前就怀疑还原模型的话,如果这些 IBV, VBV 长度都不对的话,除了浪费数据,还可能出问题
因为很多 VBV 和 IBV 的元素数量是对不上的
今天在抓帧某个角色的 卧蚕(眼部底下部分) 模型时候就出现这个问题
从下面的 IBV 可以看到1091,1092 之间的索引跨度很大,是有问题的
23901 的索引直接就超出了 VBV 顶点总数的数量
从下面的数据分析, Primitive 总数才 364 个三角形
VBV position 数量才 10313,但是 IBV 的索引已经远超这个范围了,这个很明显是 GPA 的数据显示上的 BUG
所以部分模型的导出可能遇到:
Fail setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 2046, VertexCount: 10314
Fail setting triangles. The number of supplied triangle indices must be a multiple of 3.
must be a multiple of 3 的解决办法
在我的工具中,是这么来处理的:
因为是在 set triangles 的时候发生的错误
那么我们只要将 indices 的长度保持在 缓存元素数量可以整除3即可:indices.Count % 3 == 0
// jave.lin : push padding or remove padding
// jave.lin : 这么处理可以避免 https://blog.csdn.net/linjf520/article/details/127066726 文章中提及的 BUG:
// - Fail setting triangles. Some indices are referencing out of bounds vertices. IndexCount: xxx, VertexCount: xxx
// - Fail setting triangles. The number of supplied triangle indices must be a multiple of 3.
if (indices.Count > 0 && indices.Count % 3 != 0)
{
var loopCount = 0;
var lastOneVal = indices[indices.Count - 1];
var lastOneIsZeroVal = lastOneVal == 0;
while (indices.Count > 0 && indices.Count % 3 != 0)
{
if (loopCount > 10)
break;
loopCount++;
if (lastOneIsZeroVal)
{
// jave.lin : remove padding 如果尾部是 0 索引,我们可以用删除 padding 的方式
indices.RemoveAt(indices.Count - 1);
}
else
{
// jave.lin : push padding, 否则我们使用 push 最后一个顶点作为 padding 的方式
indices.Add(lastOneVal);
}
}
}
indices out of bounds vertices - 暂无解决方法
比如:Failed setting triangles. Some indices are referencing out of bounds vertices. IndexCount: 2049, VertexCount: 281
这个问题是 GPA 的 BUG
暂时无解,连 index 的数值都错了,我们是不可能知道正确的数值的,只能猜:比如,可能是 数据类型溢出?
就是新版本的 fbx 模型,可能使用了 index buffer 的索引值的压缩技术,可能在 GPA 中没有对应实现解析,那么肯定会有报错的
这个 index 索引值的压缩技术大概是这么个思路:
- 如果
index < byte.MaxValue
,那么 index 使用byte
类型解析 - 如果
index < ushort.MaxValue
,那么 使用ushort
类型解析 - 如果
index < uint.MaxValue
,那么 使用uint
类型解析
indices out of bounds vertices - 尝试解决的方法
可以尝试将后续开始 indices 是很大的数值统统删除,保留前面的数据,95% 是OK的,就可以导出来了
Invalid worldAABB.Object is too large or too far away from the origin - 解决方法
看起来是 AABB 太大导致,很有可能是坐标数值出问题
我直接 google : Invalid worldAABB.Object is too large or too far away from the origin
找到一篇: Assertion failed: Invalid worldAABB. Object is too large or too far away from the origin
然后我添加了检测 local position 大于 1000 的都打印出来 (一般来说说不会整这么大的 local pos)
发现输出在: 12506 的 idx position 数值非常大
其实也可以打开 position.csv 使用正则搜索: \b\d+,\d{2}
,一样可以搜索到 大于 2 位以上的数值
如果向定位数值位数,之久修改,比如,超过 百位可以修改为: \b\d+,\d{3}
超过千位: \b\d+,\d{4}
,以此类推,修改后面的 \d{n}
里面的 n
数值即可
OK,如下图,我们找到了异常的数据
我们要思考一下,为何是正常的呢?
很明显,这些是优化 VBV 的数据复用了一些 内存块
然后 GPA 里面没有 resize 这个大小,或是显示的时候,没丢对应的大小进去
导致 GPA 显示一丢后续无用的数据
那我们到底要怎么处理这些无用的数据呢?
怎么判断他是无用的呢?
方法就是: 根据 indices 的数量来定范围即可
比如,indices 里面最大的有效索引值,我们需要先知道,假如叫: var indices_max_val = indices.Max() + 1;
只要遍历顶点属性数据 (vertex attribute) 的时候 (position, color, uv等数据的时候) 的时候
如果这次的遍历次数 大于或等于 indices_max_val
我们就停止,不再处理
但是注意,indices 里面同样有可能有多余的数据,因此我们要看一下索引跨度很大的情况,删除后续无用的数据
我将之前的截图 挪到这再瞄一下,如下图
这样一般就不会出现: Invalid worldAABB.Object is too large or too far away from the origin
的问题
但如果你的模型本身 local pos 就很大的数值,那你应该考虑制作方法是否除了问题
因为一般模型的 local pos 不会很大,否则会有精度问题
如果实在是有这类需求,可以考虑,模型切块,分块加载 (streaming load)
比如,大世界里面的 超大地形的切块,或是 地表模型的切块
另一个问题: 有些TEXCOORD[n].y 是不需要翻转的,因为这些数据不是采样用的
如果我们直接对所有的 TEXCOORD[n].y 都判断是 dx 的就 1- y 的处理的话,那么对于一些模型中,将部分数据存于 TEXCOORD[n].y 的话,就会出错
因此我们额外有添加了其他的选项来确定要不要翻转这些数据
另一个问题:导出的 FBX 中,UV 无法保存 vector3 或是 vector4 的数据 (已有解决方法)
具体参考另一篇: Unity - 导出的FBX模型,无法将 vector4 保存在 uv 中(使用 Unity Mesh 保存即可)
为何方便导出,我将工具扩展了,可以导出 FBX,也可以选择导出 Unity Mesh
对于一些带有自定义的 TEXCOORD[n] 的数据,建议使用 Unity Mesh 导出
对于 *.obj 数据同样有不能保存 vector3, vector4 的问题
选项如下图
文章来源:https://www.toymoban.com/news/detail-406802.html
增加了 readable 的选项便于导出后就自动设置
对于导出 FBX,unity mesh ,此选项同样都有作用
文章来源地址https://www.toymoban.com/news/detail-406802.html
Project
- github 工程: javelinlin/GPA_CSV2MESH_TOOL_pure_version
- GPA_CSV2MESH_TOOL_opt_sss_吕蒙_白起_马云禄_再次优化_projectsetting_shadowsize_法线RG解析
- GPA_CSV2MESH_TOOL_甘宁_吕蒙_马云禄_孙尚香_雕像_V2.rar
- GPA_CSV2MESH_TOOL_pure_version.rar
References
- GPA-Mesh - hub友 C++写的一个,没用过,也不知道怎么用
- INTEL GPA mesh ripper tutorial + tool (x32,x64,DX9,10,11) - 2014 年的时候国外友人写了 GPA Hook 来抓自己想要的资源
到了这里,关于教你如何使用GPA导出模型,另送一个 GPA CSV2MESH Tool in unity的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!