Skip to content
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

Packing UV meshes results are invalid #116

Open
Korinin38 opened this issue Jun 23, 2023 · 2 comments
Open

Packing UV meshes results are invalid #116

Korinin38 opened this issue Jun 23, 2023 · 2 comments

Comments

@Korinin38
Copy link

Korinin38 commented Jun 23, 2023

Similar to #95
Tried packing Smiling boy from Real-World Textured Things dataset, ID#7. Repacking it results in a horrible manner:
UV charts visualisation
As mentioned in #95, packing can create invalid geometry (though I doubt it should be happening with valid input). I tried fixing it by removing faces that include vertices with Vertex::atlasIndex = -1, but there are still stray overlapping faces (and untextured regions on object):
image

Relevant code:

std::vector<tinyobj::shape_t> shapes;
// ... import from tiny_obj_loader

xatlas::Atlas *atlas = xatlas::Create();

for (int i = 0; i < (int) shapes.size(); i++) {
    const tinyobj::mesh_t &objMesh = shapes[i].mesh;
    xatlas::UvMeshDecl uvMeshDecl;
    uvMeshDecl.faceMaterialData = (const uint32_t *)objMesh.material_ids.data();
    uvMeshDecl.vertexCount = (uint32_t) objMesh.texcoords.size() / 2;
    uvMeshDecl.vertexUvData = objMesh.texcoords.data();
    uvMeshDecl.vertexStride = sizeof(float) * 2;
    uvMeshDecl.indexCount = (uint32_t) objMesh.indices.size();
    uvMeshDecl.indexData = objMesh.indices.data();
    uvMeshDecl.indexFormat = xatlas::IndexFormat::UInt32;

    xatlas::AddMeshError error = xatlas::AddUvMesh(atlas, uvMeshDecl);
    // ... error-handling
}

xatlas::ComputeCharts(atlas);
xatlas::PackCharts(atlas, options);

// ... file creation
// export
uint32_t firstVertex = 0;
for (uint32_t i = 0; i < atlas->meshCount; i++) {
    const xatlas::Mesh &mesh = atlas->meshes[i];
    for (uint32_t v = 0; v < mesh.vertexCount; v++) {
        const xatlas::Vertex &vertex = mesh.vertexArray[v];
        const float *pos = &shapes[i].mesh.positions[vertex.xref * 3];
        fprintf(file, "v %g %g %g\n", vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height, 0.f);
    }
    fprintf(file, "o %s\n", shapes[i].name.c_str());
    fprintf(file, "s off\n");
    for (uint32_t f = 0; f < mesh.indexCount; f += 3) {
        bool valid_vertex = true;
        for (uint32_t j = 0; j < 3; j++) {
            if (mesh.vertexArray[mesh.indexArray[f + j]].atlasIndex == -1) 
                valid_vertex = false;
        }
        // removing faces with invalid vertices
        if (!valid_vertex) {
            continue;
        }
        fprintf(file, "f ");
        for (uint32_t j = 0; j < 3; j++) {
            const uint32_t index = firstVertex + mesh.indexArray[f + j] + 1; // 1-indexed
            fprintf(file, "%d/%d/%d%c", index, index, index, j == 2 ? '\n' : ' ');
        }
    }
    firstVertex += mesh.vertexCount;
}
PackCharts options
xatlas::PackOptions options;
options.maxChartSize = 0;
options.padding = 0;
options.texelsPerUnit = 0.0f;
options.resolution = 1024;
options.bilinear = true;
options.blockAlign = false;
options.bruteForce = true;
options.createImage = false;
options.rotateChartsToAxis = true;
options.rotateCharts = true;
@Korinin38
Copy link
Author

Korinin38 commented Jun 23, 2023

I managed to isolate one component that is divided into two charts incorrectly:

this component becomes that after packing. (Sorry about scale inconsistencies)
The difference is apparent:
this
this

becomes that
that

Notice that a small part of the chart gets separated from the rest, while retaining the connection.

@Korinin38
Copy link
Author

Korinin38 commented Jun 26, 2023

Found the reason for this behavior:
Face is ignored (mesh->faceIgnore.set(face)) if the area of the face is considered to be zero (area <= internal::kAreaEpsilon (relevant code)). Ignored faces are skipped when dividing UV into charts.
That calculation can be too imprecise for massive UVs with normalised coordinates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant