- 吐槽
- GPA Geometry Output 没有 UV
- 问题实例
- 开始实现
- 提取 VBV, IBV
- GPA buffer list view format 攻略
- 工具演示导出
- GPA 的 VBV,IBV的 BUG
- must be a multiple of 3 的解决办法
- indices out of bounds vertices - 暂无解决方法
- indices out of bounds vertices - 尝试解决的方法
- Project
- References
以前写过一篇: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
- 这个会使用比较多,但是这个有些问题:没有 normalizednubyte 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 格式即可
上面我是提取: 《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;
工具演示导出
我之前就怀疑还原模型的话,如果这些 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.
在我的工具中,是这么来处理的:
因为是在 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 是很大的数值统统删除,保留前面的数据,95% 是OK的,就可以导出来了
Project- github 工程后续上传
- GPA_CSV2MESH_TOOL_opt_sss_吕蒙_白起_马云禄_再次优化_projectsetting_shadowsize_法线RG解析
- GPA-Mesh - hub友 C++写的一个,没用过,也不知道怎么用
- INTEL GPA mesh ripper tutorial + tool (x32,x64,DX9,10,11) - 2014 年的时候国外友人写了 GPA Hook 来抓自己想要的资源