Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Mapboxearcut correct facing #321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 160 additions & 16 deletions tiny_obj_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -1534,16 +1534,17 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);

} else {
vertex_index_t i0 = face.vertex_indices[0];
vertex_index_t i1(-1);
vertex_index_t i2 = face.vertex_indices[1];
//vertex_index_t i0 = face.vertex_indices[0];
//vertex_index_t i1(-1);
//vertex_index_t i2 = face.vertex_indices[1];

#if 0
// find the two axes to work in
size_t axes[2] = {1, 2};
for (size_t k = 0; k < npolys; ++k) {
i0 = face.vertex_indices[(k + 0) % npolys];
i1 = face.vertex_indices[(k + 1) % npolys];
i2 = face.vertex_indices[(k + 2) % npolys];
vetex_index_t i0 = face.vertex_indices[(k + 0) % npolys];
vetex_index_t i1 = face.vertex_indices[(k + 1) % npolys];
vetex_index_t i2 = face.vertex_indices[(k + 2) % npolys];
size_t vi0 = size_t(i0.v_idx);
size_t vi1 = size_t(i1.v_idx);
size_t vi2 = size_t(i2.v_idx);
Expand Down Expand Up @@ -1591,8 +1592,70 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
break;
}
}
#else
// Compute 3D signed area vector to determine 2D projection axis
// TODO: Find best plane to project(the direction of signed area?)

size_t axes[2] = {1, 2};
{
double sx = 0.0;
double sy = 0.0;
double sz = 0.0;

for (size_t k = 0; k < npolys; k++) {

size_t k0 = k;
size_t k1 = (k + 1) % npolys;

vertex_index_t i0 = face.vertex_indices[k0];
vertex_index_t i1 = face.vertex_indices[k1];

size_t vi0 = size_t(i0.v_idx);
size_t vi1 = size_t(i1.v_idx);

if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size())) {
// Invalid index.
continue;
}

real_t v0x = v[vi0 * 3 + 0];
real_t v0y = v[vi0 * 3 + 1];
real_t v0z = v[vi0 * 3 + 2];
real_t v1x = v[vi1 * 3 + 0];
real_t v1y = v[vi1 * 3 + 1];
real_t v1z = v[vi1 * 3 + 2];

real_t cx = v0y * v1z - v0z * v1y;
real_t cy = v0z * v1x - v0x * v1z;
real_t cz = v0x * v1y - v0y * v1x;

sx += cx;
sy += cy;
sz += cz;
}

// Use the largest magnitude to determine 2D plane to project
sx = std::fabs(sx);
sy = std::fabs(sy);
sz = std::fabs(sz);

const real_t epsilon = std::numeric_limits<real_t>::epsilon();
if (sx > epsilon || sy > epsilon || sz > epsilon) {
if (sx > sy && sx > sz) {
} else {
axes[0] = 0;
if (sz > sx && sz > sy) {
axes[1] = 1;
}
}
}
}

#endif

#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT

std::cout << "axes = " << axes[0] << ", " << axes[1] << "\n";
using Point = std::array<real_t, 2>;

// first polyline define the main polygon.
Expand All @@ -1603,7 +1666,7 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,

// Fill polygon data(facevarying vertices).
for (size_t k = 0; k < npolys; k++) {
i0 = face.vertex_indices[k];
vertex_index_t i0 = face.vertex_indices[k];
size_t vi0 = size_t(i0.v_idx);

assert(((3 * vi0 + 2) < v.size()));
Expand All @@ -1614,31 +1677,112 @@ static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group,
polyline.push_back({v0x, v0y});
}

// Compute signed area(orientation of the polygon face)
// https://math.stackexchange.com/questions/2860567/correct-way-to-find-the-area-of-a-concave-quadrilateral-in-co-ordinate-geometry
// This works both concave and convex polygon thanks to Shoelace formula.
double signed_area_sum = 0.0;
for (size_t k = 0; k < npolys; k++) {

size_t k0 = k;
size_t k1 = (k + 1) % npolys;
//size_t k2 = (k + 2) % npolys;

//double e01[2];
//double e21[2];

//e01[0] = polyline[k0][0] - polyline[k1][0];
//e01[1] = polyline[k0][1] - polyline[k1][1];
//e21[0] = polyline[k2][0] - polyline[k1][0];
//e21[1] = polyline[k2][1] - polyline[k1][1];
//double cross = e01[0] * e21[1] - e01[1] * e21[0];
//std::cout << "cross[" << k << "] = " << cross << "\n";

double d = (polyline[k0][0] * polyline[k1][1]) - (polyline[k1][0] * polyline[k0][1]);
std::cout << "d[" << k << "] = " << d << "\n";
signed_area_sum += d;
}
std::cout << "signed_area_sum = " << signed_area_sum << "\n";

polygon.push_back(polyline);
std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
// => result = 3 * faces, clockwise

assert(indices.size() % 3 == 0);

std::cout << "npolys = " << npolys << "\n";
std::cout << "# of indices = " << indices.size() << "\n";

// Reconstruct vertex_index_t
// Since mapbox earcut produce triangles in clockwise-order(ignores face orientation), we need to reverse it
// depending on the face orientation of input triangle.
//
// NOTE: wavefront .obj uses right-handed coordinate and face is defined in counter-clockwise order.


// default: CW(mapbox earcut) -> CCW(wavefront .obj)
size_t voffset0 = 2;
size_t voffset1 = 1;
size_t voffset2 = 0;

// Check the face orientation of a triangle(all other triangles should have same orientation)
// triangle may be degenerated. find a triangle with finite area and use it.
for (size_t k = 0; k < indices.size() / 3; k++)
{
size_t v_idx0 = face.vertex_indices[indices[3 * k + voffset0]].v_idx;
size_t v_idx1 = face.vertex_indices[indices[3 * k + voffset1]].v_idx;
size_t v_idx2 = face.vertex_indices[indices[3 * k + voffset2]].v_idx;

real_t v0x = v[v_idx0 * 3 + axes[0]];
real_t v0y = v[v_idx0 * 3 + axes[1]];

real_t v1x = v[v_idx1 * 3 + axes[0]];
real_t v1y = v[v_idx1 * 3 + axes[1]];

real_t v2x = v[v_idx2 * 3 + axes[0]];
real_t v2y = v[v_idx2 * 3 + axes[1]];

real_t e0x = v1x - v0x;
real_t e0y = v1y - v0y;
real_t e1x = v2x - v1x;
real_t e1y = v2y - v1y;

real_t cross_tri = e0x * e1y - e0y * e1x;

if (std::fabs(cross_tri) > static_cast<real_t>(0.0)) {

std::cout << "vx = " << v_idx0 << ", " << v_idx1 << ", " << v_idx2 << "\n";
std::cout << "idx = " << v_idx0 << ", " << v_idx1 << ", " << v_idx2 << "\n";
std::cout << "cross_tri = " << cross_tri << "\n";
std::cout << "cross_signbit = " << cross_tri << "\n";
if (std::signbit(cross_tri) != std::signbit(signed_area_sum)) {
// reverse the oredering of earcut produced face indices
std::cout << "swap orientation\n";
voffset0 = 0;
voffset1 = 1;
voffset2 = 2;
break;
}
}
}

for (size_t k = 0; k < indices.size() / 3; k++) {
{
index_t idx0, idx1, idx2;
idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx;
idx0.vertex_index = face.vertex_indices[indices[3 * k + voffset0]].v_idx;
idx0.normal_index =
face.vertex_indices[indices[3 * k + 0]].vn_idx;
face.vertex_indices[indices[3 * k + voffset0]].vn_idx;
idx0.texcoord_index =
face.vertex_indices[indices[3 * k + 0]].vt_idx;
idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx;
face.vertex_indices[indices[3 * k + voffset0]].vt_idx;
idx1.vertex_index = face.vertex_indices[indices[3 * k + voffset1]].v_idx;
idx1.normal_index =
face.vertex_indices[indices[3 * k + 1]].vn_idx;
face.vertex_indices[indices[3 * k + voffset1]].vn_idx;
idx1.texcoord_index =
face.vertex_indices[indices[3 * k + 1]].vt_idx;
idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx;
face.vertex_indices[indices[3 * k + voffset1]].vt_idx;
idx2.vertex_index = face.vertex_indices[indices[3 * k + voffset2]].v_idx;
idx2.normal_index =
face.vertex_indices[indices[3 * k + 2]].vn_idx;
face.vertex_indices[indices[3 * k + voffset2]].vn_idx;
idx2.texcoord_index =
face.vertex_indices[indices[3 * k + 2]].vt_idx;
face.vertex_indices[indices[3 * k + voffset2]].vt_idx;

shape->mesh.indices.push_back(idx0);
shape->mesh.indices.push_back(idx1);
Expand Down