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

Vertices are moved to zero #95

Open
AlbertoFrancoDD opened this issue Apr 8, 2021 · 9 comments
Open

Vertices are moved to zero #95

AlbertoFrancoDD opened this issue Apr 8, 2021 · 9 comments

Comments

@AlbertoFrancoDD
Copy link

AlbertoFrancoDD commented Apr 8, 2021

Hi,
I am integrating xatlas into a project we are doing for one of our customers. I have found a weird behaviour and I am not sure if it is a bug or a problem with my input. The result is that some vertices in the meshes that I pass to xatlas are collapsed to zero, see image below:

image

What I am doing is quite simple, the code is as follows:

static xatlas::Atlas* s_atlasData = nullptr;

int BeginTexturePacking()
{
  if (s_atlasData) {
    xatlas::Destroy(s_atlasData);
    s_atlasData = nullptr;
  }

  s_atlasData = xatlas::Create();
  return 1;
}

int AddUvMesh(
  float* texcoords, int texcoords_count,
  unsigned int* indices, int index_count
)
{
  xatlas::UvMeshDecl uvmesh;

  std::vector<uint32_t> facemat;
  facemat.resize(index_count / 3, 0);

  uvmesh.faceMaterialData = facemat.data();

  uvmesh.indexOffset = 0;
  uvmesh.indexCount = index_count;
  uvmesh.indexData = indices;
  uvmesh.indexFormat = xatlas::IndexFormat::UInt32;

  uvmesh.vertexCount = texcoords_count;
  uvmesh.vertexStride = 2 * sizeof(float);
  uvmesh.vertexUvData = texcoords;

  auto err = xatlas::AddUvMesh(s_atlasData, uvmesh);
  if (err != xatlas::AddMeshError::Success) {
    return 0;
  }

  return 1;
}


int PackTextures()
{
  xatlas::PackOptions packOpts;
  xatlas::ChartOptions chartOpts;

  // packOpts.bruteForce = true;
  packOpts.padding = 0;
  packOpts.rotateCharts = false;

  chartOpts.fixWinding = true;

  xatlas::ComputeCharts(s_atlasData, chartOpts);
  xatlas::PackCharts(s_atlasData, packOpts);

  return 1;
}

int GetPackedMesh(int index, float* texturedata, int totalCount)
{
  if (index >= s_atlasData->meshCount || index < 0) {
    return 0;
  }

  // Copy the output back to the input vectors
  auto& mesh = s_atlasData->meshes[index];

  float oneOverWidth  = 1.0f / (float)s_atlasData->width;
  float oneOverHeight = 1.0f / (float)s_atlasData->height;

  for (int k = 0; k < totalCount; ++k) {
    texturedata[k * 2 + 0] = mesh.vertexArray[k].uv[0] * oneOverWidth;
    texturedata[k * 2 + 1] = mesh.vertexArray[k].uv[1] * oneOverHeight;
  }


  return 1;
}

This is happening with several meshes not just the one displayed on the image, I checked the example and it seems to me that I am doing everything right, Any idea?

@jpcy
Copy link
Owner

jpcy commented Apr 9, 2021

Any invalid geometry (e.g. zero-length edges) can't be atlased. Vertex::atlasIndex will be -1 and so Vertex::uv will be (0,0). I'm guessing that is what is happening here. Do you see (0,0) vertices in the output of the example or viewer? They skip invalid vertices when rasterizing the atlas texture.

@AlbertoFrancoDD
Copy link
Author

I do not see them in the viewer and that was why I was not understanding it proper. Ok, so I shall check the atlas index and place them next to the closest valid vertex. This is a little inconvenient as I cannot assume that the UVs will be perfectly clear as they may be generated with all sort of mapping. I will work this issue around then.

@john-chapman
Copy link

@AlbertoFrancoDD it looks like you're not taking into account that ComputeCharts() may increase the vertex count of the input mesh. Some shared verts may need to be duplicated and put into separate charts, so you need to construct new mesh data with these extra vertices (using xatlas::Vertex::xref to copy other vertex attributes into the new mesh data).

@AlbertoFrancoDD
Copy link
Author

@john-chapman IS there a way to block this? I need the mesh to stay consistent with the cuts that were performed by the artist, I cannot change the input mesh.

@john-chapman
Copy link

john-chapman commented May 12, 2021

The output mesh is exactly consistent with the input mesh - all other vertex data is unchanged, xatlas just needs to duplicate some vertices so that the generated charts will have unique UVs. I don't think there's any way to avoid this, but it shouldn't be a problem.

@Shuenhoy
Copy link

image

I met the same problem. No idea why xatlas wants to split the left part and the right part into two charts.
I am wondering whether this is a way to specify the vertex-chart relation manually, and all the vertices belonging to the same chart would just take the same rigid moving, even there are so-called "invalid vertices".

@PerspectivesLab
Copy link

can you guys provide an explicit example in c++ @john-chapman on how to re create a new mesh based on xatlas::Vertex::xref ?
thx

@john-chapman
Copy link

@PerspectivesLab Here's an outline of the way xref should be used. It's basically the original index of each output vertex - it tells you where to get the data for an output vertex from the input mesh.

// Example below assumes that YourMeshClass::operator[] accesses vertex data.
const YourMeshClass& inMesh; // Your source mesh for xatlas to process.
YourMeshClass outMesh; // The new mesh that we'll create below.

// Create/generate xatlas::Atlas*.
xatlas::Atlas* atlas = xatlas::Create();
// Setup chart/pack options, add inMesh data to atlas.
// ...
// Generate charts.
xatlas::Generate(atlas, chartOptions, packOptions);

// Construct outMesh from inMesh data + xatlas generated data.
xatlas::Mesh& atlasMesh = atlas->meshes[0]; // Could be per submesh.
outMesh.setVertexCount(atlasMesh.vertexCount);
for (uint32_t outVertexIndex = 0; outVertexIndex < atlasMesh.vertexCount; outVertexIndex++)
{
	xatlas::Vertex& vertex = atlasMesh.vertexArray[outVertexIndex];
	uint32_t inVertexIndex = vertex.xref; // Index of input vertex from which this output vertex originated.
	outMesh[outVertexIndex] = inMesh[inVertexIndex]; // Copy data from the input mesh to the output mesh.
	outMesh[outVertexIndex].lightmapUV = { vertex.uv[0] / atlas->width, vertex.uv[1] / atlas->height };
}
outMesh.setIndexData(atlasMesh.indexCount, atlasMesh.indexArray);

@PerspectivesLab
Copy link

@john-chapman thank you, your help is highly appreciated !

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

5 participants