Files
tinyusdz/examples/triangulation_method_example.cc
Syoyo Fujita 96827e7607 Add triangle fan triangulation method option for 5+ gons in Tydra RenderMesh
Summary:
- Added TriangulationMethod enum to MeshConverterConfig with two options:
  * Earcut (default): Robust algorithm for complex/concave polygons
  * TriangleFan: Fast algorithm for convex polygons (simple fan splitting)
- Implemented triangle fan splitting for 5+ vertex polygons
  * Creates triangles from first vertex as pivot: (0,1,2), (0,2,3), etc.
  * Much simpler and faster than earcut for convex polygons
- Updated TriangulatePolygon() function signature to accept triangulation method
- Preserved backward compatibility with earcut as default method
- Added triangulation_method_example.cc demonstrating usage of both methods

Benefits:
- Performance improvement for applications with convex polygon meshes
- Flexible triangulation strategy based on polygon characteristics
- Default behavior unchanged for backward compatibility

Test plan:
- Build successfully with no compilation errors
- Example program demonstrates switching between triangulation methods
- Can be tested with USD files containing 5+ vertex polygons

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-20 02:39:15 +09:00

124 lines
4.1 KiB
C++

// Example demonstrating the new triangulation method option in TinyUSDZ Tydra
//
// This example shows how to use either:
// - Earcut algorithm (default): Robust for complex/concave polygons
// - Triangle Fan: Fast for simple convex polygons
#include <iostream>
#include <vector>
#include <string>
#include "tinyusdz.hh"
#include "tydra/render-data.hh"
#include "tydra/scene-access.hh"
int main(int argc, char** argv) {
if (argc < 2) {
std::cout << "Usage: " << argv[0] << " <input.usd> [fan|earcut]\n";
std::cout << "\nTriangulation methods:\n";
std::cout << " earcut (default): Robust algorithm for complex polygons\n";
std::cout << " fan: Fast triangle fan for convex polygons\n";
return 1;
}
std::string filename = argv[1];
bool use_fan = false;
if (argc >= 3) {
std::string method = argv[2];
if (method == "fan") {
use_fan = true;
std::cout << "Using triangle fan triangulation\n";
} else if (method == "earcut") {
std::cout << "Using earcut triangulation\n";
} else {
std::cerr << "Unknown triangulation method: " << method << "\n";
return 1;
}
} else {
std::cout << "Using default earcut triangulation\n";
}
// Load USD file
tinyusdz::Stage stage;
std::string warn, err;
bool ret = tinyusdz::LoadUSDFromFile(filename, &stage, &warn, &err);
if (!warn.empty()) {
std::cerr << "Warning: " << warn << "\n";
}
if (!ret) {
std::cerr << "Failed to load USD file: " << err << "\n";
return 1;
}
// Set up render scene converter with triangulation method
tinyusdz::tydra::RenderSceneConverterEnv env(stage);
// Configure mesh conversion
env.mesh_config.triangulate = true; // Enable triangulation
// Set the triangulation method
if (use_fan) {
env.mesh_config.triangulation_method =
tinyusdz::tydra::MeshConverterConfig::TriangulationMethod::TriangleFan;
} else {
env.mesh_config.triangulation_method =
tinyusdz::tydra::MeshConverterConfig::TriangulationMethod::Earcut;
}
// Convert to render scene
tinyusdz::tydra::RenderSceneConverter converter;
tinyusdz::tydra::RenderScene render_scene;
if (!converter.ConvertToRenderScene(env, &render_scene)) {
std::cerr << "Failed to convert to render scene: "
<< converter.GetError() << "\n";
return 1;
}
// Print statistics
std::cout << "\nConversion complete!\n";
std::cout << "Number of meshes: " << render_scene.meshes.size() << "\n";
size_t total_triangles = 0;
size_t total_original_faces = 0;
for (const auto& mesh : render_scene.meshes) {
if (!mesh.triangulatedFaceVertexIndices.empty()) {
size_t num_triangles = mesh.triangulatedFaceVertexIndices.size() / 3;
size_t num_original_faces = mesh.usdFaceVertexCounts.size();
total_triangles += num_triangles;
total_original_faces += num_original_faces;
std::cout << "\nMesh: " << mesh.prim_name << "\n";
std::cout << " Original faces: " << num_original_faces << "\n";
std::cout << " Triangulated faces: " << num_triangles << "\n";
// Count polygon types
std::map<uint32_t, size_t> poly_counts;
for (auto count : mesh.usdFaceVertexCounts) {
poly_counts[count]++;
}
std::cout << " Original polygon distribution:\n";
for (const auto& kv : poly_counts) {
std::cout << " " << kv.first << "-gons: " << kv.second << "\n";
}
}
}
std::cout << "\nTotal original faces: " << total_original_faces << "\n";
std::cout << "Total triangles: " << total_triangles << "\n";
if (use_fan) {
std::cout << "\nNote: Triangle fan was used for 5+ vertex polygons.\n";
std::cout << "This is faster but assumes polygons are convex.\n";
} else {
std::cout << "\nNote: Earcut algorithm was used for 5+ vertex polygons.\n";
std::cout << "This handles complex polygons correctly.\n";
}
return 0;
}