386 lines
12 KiB
C
386 lines
12 KiB
C
#undef UFBXT_TEST_GROUP
|
|
#define UFBXT_TEST_GROUP "transform"
|
|
|
|
UFBXT_FILE_TEST(maya_pivots)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "pCube1");
|
|
ufbxt_assert(node);
|
|
|
|
ufbx_vec3 origin_ref = { 0.7211236250, 1.8317762500, -0.6038020000 };
|
|
ufbxt_assert_close_vec3(err, node->local_transform.translation, origin_ref);
|
|
}
|
|
#endif
|
|
|
|
#if UFBXT_IMPL
|
|
static void ufbxt_check_rotation_order(ufbx_scene *scene, const char *name, ufbx_rotation_order order)
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, name);
|
|
ufbxt_assert(node);
|
|
ufbx_prop *prop = ufbx_find_prop(&node->props, "RotationOrder");
|
|
ufbxt_assert(prop);
|
|
ufbxt_assert((ufbx_rotation_order)prop->value_int == order);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_rotation_order)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbxt_check_rotation_order(scene, "XYZ", UFBX_ROTATION_ORDER_XYZ);
|
|
ufbxt_check_rotation_order(scene, "XZY", UFBX_ROTATION_ORDER_XZY);
|
|
ufbxt_check_rotation_order(scene, "YZX", UFBX_ROTATION_ORDER_YZX);
|
|
ufbxt_check_rotation_order(scene, "YXZ", UFBX_ROTATION_ORDER_YXZ);
|
|
ufbxt_check_rotation_order(scene, "ZXY", UFBX_ROTATION_ORDER_ZXY);
|
|
ufbxt_check_rotation_order(scene, "ZYX", UFBX_ROTATION_ORDER_ZYX);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_post_rotate_order)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbxt_check_rotation_order(scene, "pCube1", UFBX_ROTATION_ORDER_XYZ);
|
|
ufbxt_check_rotation_order(scene, "pCube2", UFBX_ROTATION_ORDER_ZYX);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(synthetic_pre_post_rotate)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbxt_check_rotation_order(scene, "pCube1", UFBX_ROTATION_ORDER_XYZ);
|
|
ufbxt_check_rotation_order(scene, "pCube2", UFBX_ROTATION_ORDER_ZYX);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_parented_cubes)
|
|
#if UFBXT_IMPL
|
|
{
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST_FLAGS(synthetic_geometric_squish, UFBXT_FILE_TEST_FLAG_OPT_HANDLING_IGNORE_NORMALS_IN_DIFF)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "pSphere1");
|
|
ufbxt_assert(node);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.scale.y, 0.01f);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST_FLAGS(synthetic_geometric_transform, UFBXT_FILE_TEST_FLAG_OPT_HANDLING_IGNORE_NORMALS_IN_DIFF)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "Parent");
|
|
ufbxt_assert(node);
|
|
ufbx_vec3 euler = ufbx_quat_to_euler(node->geometry_transform.rotation, UFBX_ROTATION_ORDER_XYZ);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.translation.x, -0.5f);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.translation.y, -1.0f);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.translation.z, -1.5f);
|
|
ufbxt_assert_close_real(err, euler.x, 20.0f);
|
|
ufbxt_assert_close_real(err, euler.y, 40.0f);
|
|
ufbxt_assert_close_real(err, euler.z, 60.0f);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.scale.x, 2.0f);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.scale.y, 3.0f);
|
|
ufbxt_assert_close_real(err, node->geometry_transform.scale.z, 4.0f);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_cube_hidden)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "pCube1");
|
|
ufbxt_assert(node);
|
|
ufbxt_assert(!node->visible);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_TEST(root_transform)
|
|
#if UFBXT_IMPL
|
|
{
|
|
|
|
ufbxt_diff_error err = { 0 };
|
|
|
|
char path[512];
|
|
ufbxt_file_iterator iter = { "maya_cube" };
|
|
while (ufbxt_next_file(&iter, path, sizeof(path))) {
|
|
ufbx_load_opts opts = { 0 };
|
|
|
|
ufbx_vec3 euler = { { 90.0f, 0.0f, 0.0f } };
|
|
|
|
opts.use_root_transform = true;
|
|
opts.root_transform.translation.x = -1.0f;
|
|
opts.root_transform.translation.y = -2.0f;
|
|
opts.root_transform.translation.z = -3.0f;
|
|
opts.root_transform.rotation = ufbx_euler_to_quat(euler, UFBX_ROTATION_ORDER_XYZ);
|
|
opts.root_transform.scale.x = 2.0f;
|
|
opts.root_transform.scale.y = 3.0f;
|
|
opts.root_transform.scale.z = 4.0f;
|
|
|
|
ufbx_scene *scene = ufbx_load_file(path, &opts, NULL);
|
|
ufbxt_assert(scene);
|
|
|
|
ufbxt_check_scene(scene);
|
|
|
|
ufbxt_assert_close_vec3(&err, scene->root_node->local_transform.translation, opts.root_transform.translation);
|
|
ufbxt_assert_close_quat(&err, scene->root_node->local_transform.rotation, opts.root_transform.rotation);
|
|
ufbxt_assert_close_vec3(&err, scene->root_node->local_transform.scale, opts.root_transform.scale);
|
|
|
|
ufbx_transform eval = ufbx_evaluate_transform(&scene->anim, scene->root_node, 0.1);
|
|
ufbxt_assert_close_vec3(&err, eval.translation, opts.root_transform.translation);
|
|
ufbxt_assert_close_quat(&err, eval.rotation, opts.root_transform.rotation);
|
|
ufbxt_assert_close_vec3(&err, eval.scale, opts.root_transform.scale);
|
|
|
|
ufbx_scene *state = ufbx_evaluate_scene(scene, &scene->anim, 0.1, NULL, NULL);
|
|
ufbxt_assert(state);
|
|
|
|
ufbxt_assert_close_vec3(&err, state->root_node->local_transform.translation, opts.root_transform.translation);
|
|
ufbxt_assert_close_quat(&err, state->root_node->local_transform.rotation, opts.root_transform.rotation);
|
|
ufbxt_assert_close_vec3(&err, state->root_node->local_transform.scale, opts.root_transform.scale);
|
|
|
|
ufbx_free_scene(state);
|
|
ufbx_free_scene(scene);
|
|
}
|
|
|
|
ufbxt_assert(iter.num_found >= 8);
|
|
|
|
ufbxt_logf(".. Absolute diff: avg %.3g, max %.3g (%zu tests)", err.sum / (ufbx_real)err.num, err.max, err.num);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_TEST(blender_axes)
|
|
#if UFBXT_IMPL
|
|
{
|
|
char path[512], name[512];
|
|
|
|
static const char *axis_names[] = {
|
|
"px", "nx", "py", "ny", "pz", "nz",
|
|
};
|
|
|
|
for (uint32_t fwd_ix = 0; fwd_ix < 6; fwd_ix++) {
|
|
for (uint32_t up_ix = 0; up_ix < 6; up_ix++) {
|
|
|
|
// Don't allow collinear axes
|
|
if ((fwd_ix >> 1) == (up_ix >> 1)) continue;
|
|
|
|
ufbx_coordinate_axis axis_fwd = (ufbx_coordinate_axis)fwd_ix;
|
|
ufbx_coordinate_axis axis_up = (ufbx_coordinate_axis)up_ix;
|
|
|
|
snprintf(name, sizeof(name), "blender_axes/axes_%s%s", axis_names[fwd_ix], axis_names[up_ix]);
|
|
|
|
ufbxt_file_iterator iter = { name };
|
|
while (ufbxt_next_file(&iter, path, sizeof(path))) {
|
|
ufbxt_diff_error err = { 0 };
|
|
|
|
// Load normally and check axes
|
|
{
|
|
ufbx_scene *scene = ufbx_load_file(path, NULL, NULL);
|
|
ufbxt_assert(scene);
|
|
ufbxt_check_scene(scene);
|
|
|
|
ufbx_coordinate_axis axis_front = axis_fwd ^ 1;
|
|
|
|
ufbxt_assert(scene->settings.axes.front == axis_front);
|
|
ufbxt_assert(scene->settings.axes.up == axis_up);
|
|
|
|
ufbx_free_scene(scene);
|
|
}
|
|
|
|
// Axis conversion
|
|
for (int mode = 0; mode < 4; mode++) {
|
|
ufbxt_hintf("mode = %d", mode);
|
|
ufbx_load_opts opts = { 0 };
|
|
|
|
bool transform_root = (mode % 2) != 0;
|
|
bool use_adjust = (mode / 2) != 0;
|
|
|
|
opts.target_axes = ufbx_axes_right_handed_z_up;
|
|
opts.target_unit_meters = 1.0f;
|
|
|
|
if (transform_root) {
|
|
opts.use_root_transform = true;
|
|
opts.root_transform = ufbx_identity_transform;
|
|
opts.root_transform.translation.z = 1.0f;
|
|
}
|
|
|
|
if (use_adjust) {
|
|
opts.space_conversion = UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS;
|
|
} else {
|
|
opts.space_conversion = UFBX_SPACE_CONVERSION_TRANSFORM_ROOT;
|
|
}
|
|
|
|
ufbx_scene *scene = ufbx_load_file(path, &opts, NULL);
|
|
ufbxt_assert(scene);
|
|
ufbxt_check_scene(scene);
|
|
|
|
ufbx_node *plane = ufbx_find_node(scene, "Plane");
|
|
ufbxt_assert(plane && plane->mesh);
|
|
ufbx_mesh *mesh = plane->mesh;
|
|
|
|
ufbxt_assert(mesh->num_faces == 1);
|
|
ufbx_face face = mesh->faces.data[0];
|
|
ufbxt_assert(face.num_indices == 3);
|
|
|
|
if (use_adjust && !transform_root) {
|
|
ufbx_node *root = scene->root_node;
|
|
|
|
ufbx_vec3 identity_scale = { 1.0f, 1.0f, 1.0f };
|
|
ufbxt_assert_close_quat(&err, root->local_transform.rotation, ufbx_identity_quat);
|
|
ufbxt_assert_close_vec3(&err, root->local_transform.scale, identity_scale);
|
|
}
|
|
|
|
for (uint32_t i = 0; i < face.num_indices; i++) {
|
|
ufbx_vec3 pos = ufbx_get_vertex_vec3(&mesh->vertex_position, face.index_begin + i);
|
|
ufbx_vec2 uv = ufbx_get_vertex_vec2(&mesh->vertex_uv, face.index_begin + i);
|
|
|
|
pos = ufbx_transform_position(&plane->geometry_to_world, pos);
|
|
|
|
ufbx_vec3 ref;
|
|
if (uv.x < 0.5f && uv.y < 0.5f) {
|
|
ref.x = 1.0f;
|
|
ref.y = 1.0f;
|
|
ref.z = 3.0f;
|
|
} else if (uv.x > 0.5f && uv.y < 0.5f) {
|
|
ref.x = 2.0f;
|
|
ref.y = 2.0f;
|
|
ref.z = 3.0f;
|
|
} else if (uv.x < 0.5f && uv.y > 0.5f) {
|
|
ref.x = 1.0f;
|
|
ref.y = 2.0f;
|
|
ref.z = 4.0f;
|
|
} else {
|
|
ufbxt_assert(0 && "Shouldn't exist");
|
|
}
|
|
|
|
if (transform_root) {
|
|
ref.z += 1.0f;
|
|
}
|
|
|
|
ufbxt_assert_close_vec3(&err, pos, ref);
|
|
}
|
|
|
|
ufbx_free_scene(scene);
|
|
}
|
|
|
|
ufbxt_logf(".. Absolute diff: avg %.3g, max %.3g (%zu tests)", err.sum / (ufbx_real)err.num, err.max, err.num);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if UFBXT_IMPL
|
|
static ufbx_load_opts ufbxt_scale_to_cm_opts()
|
|
{
|
|
ufbx_load_opts opts = { 0 };
|
|
opts.target_unit_meters = 0.01f;
|
|
return opts;
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST_OPTS(maya_scale_no_inherit, ufbxt_scale_to_cm_opts)
|
|
#if UFBXT_IMPL
|
|
{
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "joint1");
|
|
ufbxt_assert(node);
|
|
ufbxt_assert(node->inherit_type == UFBX_INHERIT_NORMAL);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.x, 0.02f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.y, 0.03f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.z, 0.04f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.x, 2.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.y, 3.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.z, 4.0f);
|
|
}
|
|
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "joint2");
|
|
ufbxt_assert(node);
|
|
ufbxt_assert(node->inherit_type == UFBX_INHERIT_NO_SCALE);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.x, 100.0f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.y, 100.0f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.z, 100.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.x, 100.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.y, 100.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.z, 100.0f);
|
|
}
|
|
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "joint3");
|
|
ufbxt_assert(node);
|
|
ufbxt_assert(node->inherit_type == UFBX_INHERIT_NO_SCALE);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.x, 1.0f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.y, 1.0f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.z, 1.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.x, 1.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.y, 1.0f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.z, 1.0f);
|
|
}
|
|
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "joint4");
|
|
ufbxt_assert(node);
|
|
ufbxt_assert(node->inherit_type == UFBX_INHERIT_NO_SCALE);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.x, 1.5f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.y, 2.5f);
|
|
ufbxt_assert_close_real(err, node->local_transform.scale.z, 3.5f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.x, 1.5f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.y, 2.5f);
|
|
ufbxt_assert_close_real(err, node->world_transform.scale.z, 3.5f);
|
|
}
|
|
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "joint3");
|
|
|
|
{
|
|
ufbx_transform transform = ufbx_evaluate_transform(&scene->anim, node, 1.0);
|
|
ufbxt_assert_close_real(err, transform.scale.x, 0.3f);
|
|
ufbxt_assert_close_real(err, transform.scale.y, 0.6f);
|
|
ufbxt_assert_close_real(err, transform.scale.z, 0.9f);
|
|
}
|
|
|
|
{
|
|
ufbx_transform transform = ufbx_evaluate_transform(&scene->anim, node, 0.5);
|
|
ufbxt_assert_close_real(err, transform.scale.x, 0.67281f);
|
|
ufbxt_assert_close_real(err, transform.scale.y, 0.81304f);
|
|
ufbxt_assert_close_real(err, transform.scale.z, 0.95326f);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(synthetic_node_dag)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *root = scene->root_node;
|
|
ufbx_node *a = ufbx_find_node(scene, "A");
|
|
ufbx_node *b = ufbx_find_node(scene, "B");
|
|
ufbx_node *c = ufbx_find_node(scene, "C");
|
|
ufbx_node *d = ufbx_find_node(scene, "D");
|
|
|
|
ufbxt_assert(root && a && b && c && d);
|
|
ufbxt_assert(root->children.count == 1);
|
|
ufbxt_assert(root->children.data[0] == a);
|
|
|
|
ufbxt_assert(a->parent == root);
|
|
ufbxt_assert(a->children.count == 1);
|
|
ufbxt_assert(a->children.data[0] == b);
|
|
|
|
ufbxt_assert(b->parent == a);
|
|
ufbxt_assert(b->children.count == 1);
|
|
ufbxt_assert(b->children.data[0] == c);
|
|
|
|
ufbxt_assert(c->parent == b);
|
|
ufbxt_assert(c->children.count == 1);
|
|
ufbxt_assert(c->children.data[0] == d);
|
|
|
|
ufbxt_assert(d->parent == c);
|
|
ufbxt_assert(d->children.count == 0);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST_FLAGS(synthetic_node_cycle_fail, UFBXT_FILE_TEST_FLAG_ALLOW_ERROR)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbxt_assert(!scene);
|
|
}
|
|
#endif
|