264 lines
7.1 KiB
C
264 lines
7.1 KiB
C
#undef UFBXT_TEST_GROUP
|
|
#define UFBXT_TEST_GROUP "triangulate"
|
|
|
|
#if UFBXT_IMPL
|
|
size_t do_triangulate_test(ufbx_scene *scene)
|
|
{
|
|
size_t num_fail = 0;
|
|
|
|
for (size_t mesh_ix = 0; mesh_ix < scene->meshes.count; mesh_ix++) {
|
|
ufbx_mesh *mesh = scene->meshes.data[mesh_ix];
|
|
ufbxt_assert(mesh->instances.count == 1);
|
|
bool should_be_top_left = mesh->instances.data[0]->name.data[0] == 'A';
|
|
ufbxt_assert(mesh->num_faces == 1);
|
|
ufbx_face face = mesh->faces.data[0];
|
|
ufbxt_assert(face.index_begin == 0);
|
|
ufbxt_assert(face.num_indices == 4);
|
|
uint32_t tris[6];
|
|
bool ok = ufbx_triangulate_face(tris, 6, mesh, face);
|
|
ufbxt_assert(ok);
|
|
|
|
size_t top_left_ix = 0;
|
|
ufbx_real best_dot = HUGE_VALF;
|
|
for (size_t ix = 0; ix < 4; ix++) {
|
|
ufbx_vec3 v = ufbx_get_vertex_vec3(&mesh->vertex_position, ix);
|
|
ufbx_real dot = v.x + v.z;
|
|
if (dot < best_dot) {
|
|
top_left_ix = ix;
|
|
best_dot = dot;
|
|
}
|
|
}
|
|
|
|
uint32_t top_left_count = 0;
|
|
for (size_t i = 0; i < 6; i++) {
|
|
if (tris[i] == top_left_ix) top_left_count++;
|
|
}
|
|
|
|
if (should_be_top_left != (top_left_count == 2)) {
|
|
ufbxt_logf("Fail: %s", mesh->instances.data[0]->name.data);
|
|
num_fail++;
|
|
}
|
|
}
|
|
|
|
ufbxt_logf("Triangulations OK: %zu/%zu", scene->meshes.count - num_fail, scene->meshes.count);
|
|
return num_fail;
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_triangulate)
|
|
#if UFBXT_IMPL
|
|
{
|
|
size_t num_fail = do_triangulate_test(scene);
|
|
ufbxt_assert(num_fail <= 4);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_triangulate_down)
|
|
#if UFBXT_IMPL
|
|
{
|
|
size_t num_fail = do_triangulate_test(scene);
|
|
ufbxt_assert(num_fail <= 1);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(maya_tri_cone)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "pCone1");
|
|
ufbxt_assert(node && node->mesh);
|
|
ufbx_mesh *mesh = node->mesh;
|
|
|
|
for (size_t i = 0; i < mesh->num_faces; i++) {
|
|
ufbx_face face = mesh->faces.data[i];
|
|
ufbxt_assert(face.num_indices >= 3 && face.num_indices <= 32);
|
|
|
|
uint32_t tris[32];
|
|
|
|
size_t num_tris = face.num_indices - 2;
|
|
for (size_t i = 0; i < 32; i++) {
|
|
ufbx_panic panic;
|
|
panic.did_panic = false;
|
|
size_t num_tris_returned = ufbx_catch_triangulate_face(&panic, tris, i, mesh, face);
|
|
if (i >= num_tris * 3) {
|
|
ufbxt_assert(!panic.did_panic);
|
|
ufbxt_assert(num_tris_returned == num_tris);
|
|
} else {
|
|
ufbxt_assert(panic.did_panic);
|
|
ufbxt_assert(num_tris_returned == 0);
|
|
}
|
|
}
|
|
|
|
ufbxt_assert(ufbx_triangulate_face(tris, ufbxt_arraycount(tris), mesh, face));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if UFBXT_IMPL
|
|
|
|
static void ufbxt_ngon_write_obj(const char *path, ufbx_mesh *mesh, const uint32_t *indices, size_t num_triangles)
|
|
{
|
|
FILE *f = fopen(path, "w");
|
|
|
|
for (size_t i = 0; i < mesh->num_vertices; i++) {
|
|
ufbx_vec3 v = mesh->vertices.data[i];
|
|
fprintf(f, "v %f %f %f\n", v.x, v.y, v.z);
|
|
}
|
|
|
|
fprintf(f, "\n");
|
|
for (size_t i = 0; i < num_triangles; i++) {
|
|
const uint32_t *tri = indices + i * 3;
|
|
fprintf(f, "f %u %u %u\n",
|
|
mesh->vertex_indices.data[tri[0]] + 1,
|
|
mesh->vertex_indices.data[tri[1]] + 1,
|
|
mesh->vertex_indices.data[tri[2]] + 1);
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
static ufbx_vec2 ufbxt_ngon_3d_to_2d(const ufbx_vec3 basis[2], ufbx_vec3 pos)
|
|
{
|
|
ufbx_vec2 uv;
|
|
uv.x = ufbxt_dot3(basis[0], pos);
|
|
uv.y = ufbxt_dot3(basis[1], pos);
|
|
return uv;
|
|
}
|
|
|
|
static void ufbxt_check_ngon_triangulation(ufbxt_diff_error *err, ufbx_mesh *mesh, ufbx_face face, uint32_t *indices, size_t num_triangles, const ufbx_vec3 basis[2])
|
|
{
|
|
// Check that the area matches for now
|
|
// TODO: More rigorous tests
|
|
|
|
ufbx_real poly_area = 0.0f;
|
|
for (size_t i = 0; i < face.num_indices; i++) {
|
|
ufbx_vec2 a = ufbxt_ngon_3d_to_2d(basis, ufbx_get_vertex_vec3(&mesh->vertex_position, face.index_begin + i + 0));
|
|
ufbx_vec2 b = ufbxt_ngon_3d_to_2d(basis, ufbx_get_vertex_vec3(&mesh->vertex_position, face.index_begin + (i + 1) % face.num_indices));
|
|
poly_area += 0.5f * (a.x*b.y - a.y*b.x);
|
|
}
|
|
|
|
ufbx_real tri_area = 0.0f;
|
|
for (size_t i = 0; i < num_triangles; i++) {
|
|
ufbx_vec2 a = ufbxt_ngon_3d_to_2d(basis, ufbx_get_vertex_vec3(&mesh->vertex_position, indices[i*3 + 0]));
|
|
ufbx_vec2 b = ufbxt_ngon_3d_to_2d(basis, ufbx_get_vertex_vec3(&mesh->vertex_position, indices[i*3 + 1]));
|
|
ufbx_vec2 c = ufbxt_ngon_3d_to_2d(basis, ufbx_get_vertex_vec3(&mesh->vertex_position, indices[i*3 + 2]));
|
|
ufbx_real area = 0.5f * (a.x*(b.y-c.y) + b.x*(c.y-a.y) + c.x*(a.y-b.y));
|
|
ufbxt_assert(area >= -0.01f);
|
|
tri_area += area;
|
|
}
|
|
|
|
ufbxt_assert_close_real(err, poly_area, tri_area);
|
|
}
|
|
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(blender_300_ngon_intersection)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "Plane");
|
|
ufbxt_assert(node && node->mesh);
|
|
ufbx_mesh *mesh = node->mesh;
|
|
|
|
ufbxt_assert(mesh->num_faces == 1);
|
|
ufbx_face face = mesh->faces.data[0];
|
|
|
|
uint32_t indices[3*3];
|
|
size_t num_tris = ufbx_triangulate_face(indices, ufbxt_arraycount(indices), mesh, face);
|
|
ufbxt_assert(num_tris == 3);
|
|
|
|
const ufbx_vec3 basis[2] = {
|
|
{ { 1.0f, 0.0f, 0.0f } },
|
|
{ { 0.0f, 1.0f, 0.0f } },
|
|
};
|
|
ufbxt_check_ngon_triangulation(err, mesh, face, indices, num_tris, basis);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(blender_300_ngon_e)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "Plane");
|
|
ufbxt_assert(node && node->mesh);
|
|
ufbx_mesh *mesh = node->mesh;
|
|
|
|
ufbxt_assert(mesh->num_faces == 1);
|
|
ufbx_face face = mesh->faces.data[0];
|
|
|
|
uint32_t indices[10*3];
|
|
size_t num_tris = ufbx_triangulate_face(indices, ufbxt_arraycount(indices), mesh, face);
|
|
ufbxt_assert(num_tris == 10);
|
|
|
|
const ufbx_vec3 basis[2] = {
|
|
{ { 1.0f, 0.0f, 0.0f } },
|
|
{ { 0.0f, 1.0f, 0.0f } },
|
|
};
|
|
ufbxt_check_ngon_triangulation(err, mesh, face, indices, num_tris, basis);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(blender_300_ngon_abstract)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "Plane");
|
|
ufbxt_assert(node && node->mesh);
|
|
ufbx_mesh *mesh = node->mesh;
|
|
|
|
ufbxt_assert(mesh->num_faces == 1);
|
|
ufbx_face face = mesh->faces.data[0];
|
|
|
|
uint32_t indices[144*3];
|
|
size_t num_tris = ufbx_triangulate_face(indices, ufbxt_arraycount(indices), mesh, face);
|
|
ufbxt_assert(num_tris == 144);
|
|
|
|
const ufbx_vec3 basis[2] = {
|
|
{ { 1.0f, 0.0f, 0.0f } },
|
|
{ { 0.0f, 1.0f, 0.0f } },
|
|
};
|
|
ufbxt_check_ngon_triangulation(err, mesh, face, indices, num_tris, basis);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(blender_300_ngon_big)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "Plane");
|
|
ufbxt_assert(node && node->mesh);
|
|
ufbx_mesh *mesh = node->mesh;
|
|
|
|
ufbxt_assert(mesh->num_faces == 1);
|
|
ufbx_face face = mesh->faces.data[0];
|
|
|
|
uint32_t expected_tris = 8028;
|
|
uint32_t *indices = malloc(expected_tris * 3 * sizeof(uint32_t));
|
|
ufbxt_assert(indices);
|
|
|
|
size_t num_tris = ufbx_triangulate_face(indices, expected_tris * 3, mesh, face);
|
|
ufbxt_assert(num_tris == expected_tris);
|
|
|
|
const ufbx_vec3 basis[2] = {
|
|
{ { 1.0f, 0.0f, 0.0f } },
|
|
{ { 0.0f, 1.0f, 0.0f } },
|
|
};
|
|
ufbxt_check_ngon_triangulation(err, mesh, face, indices, num_tris, basis);
|
|
|
|
free(indices);
|
|
}
|
|
#endif
|
|
|
|
UFBXT_FILE_TEST(blender_300_ngon_irregular)
|
|
#if UFBXT_IMPL
|
|
{
|
|
ufbx_node *node = ufbx_find_node(scene, "Plane");
|
|
ufbxt_assert(node && node->mesh);
|
|
ufbx_mesh *mesh = node->mesh;
|
|
|
|
uint32_t indices[256];
|
|
|
|
for (size_t i = 0; i < mesh->num_faces; i++) {
|
|
ufbx_face face = mesh->faces.data[i];
|
|
|
|
size_t num_tris = ufbx_triangulate_face(indices, ufbxt_arraycount(indices), mesh, face);
|
|
ufbxt_assert(num_tris == face.num_indices - 2);
|
|
}
|
|
}
|
|
#endif
|