gltf,是否要转置矩阵?
gltf, are matrices ever to be transposed?
在学习 gltf 时,我已经有 2 个可用的皮肤模型,现在我正在尝试 RiggedFigure。
其他 2 个模型工作得很好,我使用的是相同的代码。我正在使用 vscode gltf 扩展来验证我的输出。
文档指出:
Accessors of matrix type have data stored in column-major order; start of each column must be aligned to 4-byte boundaries.
特征矩阵也是主要的列,因此将原始字节复制到 Eigen::Matrix4f
类型的 stl 向量中应该会产生正确的数据,事实上,我拥有的 3 个模型中的 2 个就是这种情况到目前为止尝试过。
但是对于装配图,vs 代码说矩阵应该是(请原谅屏幕截图,但出于某种原因我无法复制粘贴矩阵):
我的代码打印:
0.999983 0.000442018 0.00581419 -0.00398856
0 0.997123 -0.0758045 0.0520021
-0.005831 0.0758032 0.997106 -0.684015
0 0 0 1
1 0 0 0
0 -0.01376 0.999905 -0.85674
0 -0.999905 -0.0137601 0.024791
0 0 0 1
1 0 0 0
0 0.979842 0.199774 -0.224555
0 -0.199774 0.979842 -1.05133
0 0 0 1
1 0 0 0
0 -0.00751853 0.999972 -1.12647
0 -0.999972 -0.00751847 0.00796944
0 0 0 1
-1 -1.50995e-07 0 0
0 0.00364935 0.999993 -1.19299
-1.51869e-07 0.999993 -0.00364941 0.00535393
0 0 0 1
-0.0623881 0.998036 -0.00569177 0.00162297
0.891518 0.0531644 -0.449853 0.404156
-0.448667 -0.0331397 -0.893084 0.998987
0 0 0 1
0.109672 0.988876 -0.100484 0.107683
-0.891521 0.0531632 -0.449849 0.404152
-0.439503 0.13892 0.887434 -0.993169
0 0 0 1
0.530194 0.847874 0.001751 -0.183428
0.760039 -0.474352 -0.444218 0.206564
-0.375811 0.236853 -0.895917 0.973213
0 0 0 1
-0.0705104 -0.619322 0.781965 -0.761146
-0.760038 -0.474352 -0.444223 0.206569
0.646043 -0.625645 -0.437261 0.633599
0 0 0 1
0.631434 0.775418 -0.00419003 -0.228155
0.649284 -0.53166 -0.543845 0.154659
-0.423935 0.340682 -0.839175 0.951451
0 0 0 1
0.111378 -0.773831 0.623523 -0.550204
-0.649284 -0.531661 -0.543845 0.15466
0.752347 -0.344271 -0.561651 0.809067
0 0 0 1
-0.830471 -0.549474 0.091635 -0.00030848
0.0339727 -0.214148 -0.97621 0.596867
0.556025 -0.807601 0.196511 -0.159297
0 0 0 1
-0.994689 0.102198 0.0121981 -0.0750653
-0.0339737 -0.214147 -0.97621 0.596867
-0.0971548 -0.97144 0.216482 -0.140501
0 0 0 1
-0.99973 0.0232223 -7.82996e-05 0.0784336
0.0051282 0.217484 -0.97605 0.357951
-0.0226493 -0.975788 -0.217544 0.0222206
0 0 0 1
-0.998171 -0.0599068 -0.00810355 -0.0775425
-0.00512856 0.217484 -0.97605 0.357951
0.0602345 -0.974224 -0.217393 0.0251548
0 0 0 1
-0.999327 0.0366897 0 0.0783684
0.0287104 0.781987 0.622632 -0.0567413
0.0228442 0.622213 -0.782514 0.0634761
0 0 0 1
-0.999326 0.00828946 0.0357652 -0.0814984
0.0287402 0.782804 0.621604 -0.0521458
-0.0228444 0.622213 -0.782514 0.0634761
0 0 0 1
0.994013 0.109264 0.000418345 -0.0755577
0.109252 -0.993835 -0.0188101 -0.0405796
-0.00164008 0.0187438 -0.999822 0.0227357
0 0 0 1
0.994011 -0.109281 0.000483894 0.0755372
-0.109253 -0.993836 -0.018811 -0.0405797
0.00253636 0.0186453 -0.999823 0.0228038
0 0 0 1
哪些是 vs 代码所说的转置版本。
我的加载代码是这样的(用错别字实例化Eigen::Matrix4f
):
void CopySparseBuffer(
void* dest,
const void* src,
const size_t element_count,
const size_t stride,
const size_t type_size)
{
assert(stride >= type_size);
// Typecast src and dest addresses to (char *)
unsigned char* csrc = (unsigned char*)src;
unsigned char* cdest = (unsigned char*)dest;
// Iterate over the total number of elements to copy
for(int i = 0; i < element_count; i++)
// Copy each byte of the element. Since the stride could be different from the
// type size (in the case of padding bytes for example) the right access
// should skip over any interleaved data, that's why we use the stride.
for(int j = 0; j < type_size; j++)
*(cdest + i * type_size + j) = *(csrc + i * stride + j);
}
template<typename T>
std::vector<T> ExtractDataFromAccessor(
const tinygltf::Model& model, const int accessor_index, bool print = false)
{
const int buffer_view_index = model.accessors[accessor_index].bufferView;
const int array_type = model.accessors[accessor_index].type;
const int component_type = model.accessors[accessor_index].componentType;
const int accessor_offset = model.accessors[accessor_index].byteOffset;
const int element_num = model.accessors[accessor_index].count;
const int buffer_index = model.bufferViews[buffer_view_index].buffer;
const int buffer_length = model.bufferViews[buffer_view_index].byteLength;
const int buffer_offset = model.bufferViews[buffer_view_index].byteOffset;
const int buffer_stride = model.bufferViews[buffer_view_index].byteStride;
const std::vector<unsigned char> data = model.buffers[buffer_index].data;
assert(
component_type == ComponentCode<T>() &&
"The component type found here should match that of the type (e.g. float and "
"float).");
assert(array_type == TypeCode<T>());
// Size in bytes of a single element (e.g. 12 for a vec3 of floats)
const int type_size = sizeof(T);
assert(
buffer_stride == 0 || buffer_stride >= sizeof(T) &&
"It doesn't make sense for a positive buffer "
"stride to be less than the type size");
assert(element_num * type_size <= buffer_length);
const size_t stride = std::max(buffer_stride, type_size);
std::vector<T> holder(element_num);
CopySparseBuffer(
holder.data(),
data.data() + buffer_offset + accessor_offset,
element_num,
stride,
type_size);
return holder;
}
我刚刚弄明白了,所以我会把它留在这里,以防将来有人遇到同样的情况。
VS 代码向量是列,而不是行,所以我的代码和 VS 代码实际上是一致的,只是 VS 代码输出令人困惑。
简而言之,一切正常,输出只是令人困惑。
在学习 gltf 时,我已经有 2 个可用的皮肤模型,现在我正在尝试 RiggedFigure。
其他 2 个模型工作得很好,我使用的是相同的代码。我正在使用 vscode gltf 扩展来验证我的输出。
文档指出:
Accessors of matrix type have data stored in column-major order; start of each column must be aligned to 4-byte boundaries.
特征矩阵也是主要的列,因此将原始字节复制到 Eigen::Matrix4f
类型的 stl 向量中应该会产生正确的数据,事实上,我拥有的 3 个模型中的 2 个就是这种情况到目前为止尝试过。
但是对于装配图,vs 代码说矩阵应该是(请原谅屏幕截图,但出于某种原因我无法复制粘贴矩阵):
我的代码打印:
0.999983 0.000442018 0.00581419 -0.00398856
0 0.997123 -0.0758045 0.0520021
-0.005831 0.0758032 0.997106 -0.684015
0 0 0 1
1 0 0 0
0 -0.01376 0.999905 -0.85674
0 -0.999905 -0.0137601 0.024791
0 0 0 1
1 0 0 0
0 0.979842 0.199774 -0.224555
0 -0.199774 0.979842 -1.05133
0 0 0 1
1 0 0 0
0 -0.00751853 0.999972 -1.12647
0 -0.999972 -0.00751847 0.00796944
0 0 0 1
-1 -1.50995e-07 0 0
0 0.00364935 0.999993 -1.19299
-1.51869e-07 0.999993 -0.00364941 0.00535393
0 0 0 1
-0.0623881 0.998036 -0.00569177 0.00162297
0.891518 0.0531644 -0.449853 0.404156
-0.448667 -0.0331397 -0.893084 0.998987
0 0 0 1
0.109672 0.988876 -0.100484 0.107683
-0.891521 0.0531632 -0.449849 0.404152
-0.439503 0.13892 0.887434 -0.993169
0 0 0 1
0.530194 0.847874 0.001751 -0.183428
0.760039 -0.474352 -0.444218 0.206564
-0.375811 0.236853 -0.895917 0.973213
0 0 0 1
-0.0705104 -0.619322 0.781965 -0.761146
-0.760038 -0.474352 -0.444223 0.206569
0.646043 -0.625645 -0.437261 0.633599
0 0 0 1
0.631434 0.775418 -0.00419003 -0.228155
0.649284 -0.53166 -0.543845 0.154659
-0.423935 0.340682 -0.839175 0.951451
0 0 0 1
0.111378 -0.773831 0.623523 -0.550204
-0.649284 -0.531661 -0.543845 0.15466
0.752347 -0.344271 -0.561651 0.809067
0 0 0 1
-0.830471 -0.549474 0.091635 -0.00030848
0.0339727 -0.214148 -0.97621 0.596867
0.556025 -0.807601 0.196511 -0.159297
0 0 0 1
-0.994689 0.102198 0.0121981 -0.0750653
-0.0339737 -0.214147 -0.97621 0.596867
-0.0971548 -0.97144 0.216482 -0.140501
0 0 0 1
-0.99973 0.0232223 -7.82996e-05 0.0784336
0.0051282 0.217484 -0.97605 0.357951
-0.0226493 -0.975788 -0.217544 0.0222206
0 0 0 1
-0.998171 -0.0599068 -0.00810355 -0.0775425
-0.00512856 0.217484 -0.97605 0.357951
0.0602345 -0.974224 -0.217393 0.0251548
0 0 0 1
-0.999327 0.0366897 0 0.0783684
0.0287104 0.781987 0.622632 -0.0567413
0.0228442 0.622213 -0.782514 0.0634761
0 0 0 1
-0.999326 0.00828946 0.0357652 -0.0814984
0.0287402 0.782804 0.621604 -0.0521458
-0.0228444 0.622213 -0.782514 0.0634761
0 0 0 1
0.994013 0.109264 0.000418345 -0.0755577
0.109252 -0.993835 -0.0188101 -0.0405796
-0.00164008 0.0187438 -0.999822 0.0227357
0 0 0 1
0.994011 -0.109281 0.000483894 0.0755372
-0.109253 -0.993836 -0.018811 -0.0405797
0.00253636 0.0186453 -0.999823 0.0228038
0 0 0 1
哪些是 vs 代码所说的转置版本。
我的加载代码是这样的(用错别字实例化Eigen::Matrix4f
):
void CopySparseBuffer(
void* dest,
const void* src,
const size_t element_count,
const size_t stride,
const size_t type_size)
{
assert(stride >= type_size);
// Typecast src and dest addresses to (char *)
unsigned char* csrc = (unsigned char*)src;
unsigned char* cdest = (unsigned char*)dest;
// Iterate over the total number of elements to copy
for(int i = 0; i < element_count; i++)
// Copy each byte of the element. Since the stride could be different from the
// type size (in the case of padding bytes for example) the right access
// should skip over any interleaved data, that's why we use the stride.
for(int j = 0; j < type_size; j++)
*(cdest + i * type_size + j) = *(csrc + i * stride + j);
}
template<typename T>
std::vector<T> ExtractDataFromAccessor(
const tinygltf::Model& model, const int accessor_index, bool print = false)
{
const int buffer_view_index = model.accessors[accessor_index].bufferView;
const int array_type = model.accessors[accessor_index].type;
const int component_type = model.accessors[accessor_index].componentType;
const int accessor_offset = model.accessors[accessor_index].byteOffset;
const int element_num = model.accessors[accessor_index].count;
const int buffer_index = model.bufferViews[buffer_view_index].buffer;
const int buffer_length = model.bufferViews[buffer_view_index].byteLength;
const int buffer_offset = model.bufferViews[buffer_view_index].byteOffset;
const int buffer_stride = model.bufferViews[buffer_view_index].byteStride;
const std::vector<unsigned char> data = model.buffers[buffer_index].data;
assert(
component_type == ComponentCode<T>() &&
"The component type found here should match that of the type (e.g. float and "
"float).");
assert(array_type == TypeCode<T>());
// Size in bytes of a single element (e.g. 12 for a vec3 of floats)
const int type_size = sizeof(T);
assert(
buffer_stride == 0 || buffer_stride >= sizeof(T) &&
"It doesn't make sense for a positive buffer "
"stride to be less than the type size");
assert(element_num * type_size <= buffer_length);
const size_t stride = std::max(buffer_stride, type_size);
std::vector<T> holder(element_num);
CopySparseBuffer(
holder.data(),
data.data() + buffer_offset + accessor_offset,
element_num,
stride,
type_size);
return holder;
}
我刚刚弄明白了,所以我会把它留在这里,以防将来有人遇到同样的情况。
VS 代码向量是列,而不是行,所以我的代码和 VS 代码实际上是一致的,只是 VS 代码输出令人困惑。
简而言之,一切正常,输出只是令人困惑。