zeux / meshoptimizer

Mesh optimization library that makes meshes smaller and faster to render
MIT License
5.54k stars 475 forks source link

Questions: Material Index and UVs #149

Closed oschakravarthi closed 4 years ago

oschakravarthi commented 4 years ago

Hi,

In my model, there can be two adjacent-co-planar triangles with different material IDs. They should not be merged. How to handle this case?

Moreover, I have UVs defined at Triangle Vertex. I mean, for a given Cube model, I have, Vertices: 24 Vertex Normals: 24 Indices: 36 UVs: 36 (Every triangle will have 3 UVs; (one for each vertex in triangle)

Now I could not find a way to set UVs in the simplified mesh from the original mesh. Any clue?

Thanks in advance.

zeux commented 4 years ago

Re: material IDs - right now simplification algorithm doesn't support per-triangle material, unfortunately. I've thought about it before and it's on the todo list but it's behind a bunch of other more important work.

There's two workarounds for this:

  1. Simplify material subsets of the meshes separately. This can introduce gaps between the pieces so isn't a great solution.
  2. Add a material index as a vertex attribute during simplification; then the simplifier will automatically respect the boundaries.

The way (2) needs to be implemented is approximately as follows:

  1. Deindex the geometry, preparing a flat vertex stream with no index buffer where for each triangle there's three vertices with all the necessary information
  2. For each 3 vertices of the triangle, add material index to each of them
  3. Construct an optimal index buffer from the result using meshopt_meshopt_generateVertexRemap, see README.

E.g. using a struct like this

struct Vertex
{
   float position[3];
   float normal[3];
   float uv[2];
   int materialid;
};

Now I could not find a way to set UVs in the simplified mesh from the original mesh.

If you'd like to preserve the original data of the mesh, you need to pass a "GPU-ready" mesh to meshopt_simplify. The way this works is that you have to duplicate vertices that have the same position but different normals or texture coordinates, so for a cube you must have 24 vertices (as each vertex has a unique position/normal/etc.), 4 for each face.

Incidentally, the approach outlined for solving the material id issue works here as well. Just generate a flat list of Vertex structures, e.g. using the definition above, from your data; then generate an index buffer from it like this:

    std::vector<unsigned int> remap(total_indices);
    size_t total_vertices = meshopt_generateVertexRemap(&remap[0], NULL, total_indices, &vertices[0], total_indices, sizeof(Vertex));

    result.indices.resize(total_indices);
    meshopt_remapIndexBuffer(&result.indices[0], NULL, total_indices, &remap[0]);

    result.vertices.resize(total_vertices);
    meshopt_remapVertexBuffer(&result.vertices[0], &vertices[0], total_indices, sizeof(Vertex), &remap[0]);

And then simplify the resulting data using meshopt_simplify.

Hope that helps; I have some plans to improve the interface and implementation of simplification algorithms so maybe some of this won't be necessary in the future, but right now this is the best alternative.

oschakravarthi commented 4 years ago

Hi @zeux

Thanks for your solution. It worked.

This is my mesh after decimation. image

When I smooth vertex normals, few triangles are turning black. The reason is those triangles have vertices which are not shared. Can we do anything to remove/fix these kind of triangles while decimating?

Thanks in advance.

image

image

image

zeux commented 4 years ago

Hmm - in theory this should not happen. However, there are currently a couple of bugs with border classification that may make these holes appear (this might be similar to #122 and #88). I'm planning to fix these, but it would be good to make sure this indeed is the problem. Any chance you could share the model as perhaps an .obj or .gltf file?

zeux commented 4 years ago

The bugs with border classification have been fixed but it occurs to me that this is more likely to be the same issue as #86 - inverted triangles result in incorrect normal computation, assuming normals are recomputed post-simplification. I'll need to figure out how to best fix that.

oschakravarthi commented 4 years ago

Hi @zeux Thanks for your help. I realized that keeping Normal in Vertex (as we discussed earlier) is not required because the Vertex normals should be re-computed. The reason for those black spots is because of my blind algorithm for computing Vertex normals. I am yet to figure-out the best algorithm which identifies sharp edges and computes vertex normals in a smart way. Please let me know if you have any inputs

oschakravarthi commented 4 years ago

Hi @zeux ,

When I use the latest code which you have checked-in 5 days back, the model is not coming properly. It is coming like this. image

Without those changes, it comes like this

image

zeux commented 4 years ago

I can take a look at this if you send me the model.

oschakravarthi commented 4 years ago

hi @zeux , I verified from my side. It is a problem in my code. No issues in your code. Thank you

zeux commented 4 years ago

Since the problems with triangle flips (that are causing bad normals for naive generation) are tracked in #86 I'm going to close this as a duplicate; haven't figured out yet what the best way to fix that yet.