Files
coven/modules/ufbx/test/test_triangulate.h

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