Skip to content

Instantly share code, notes, and snippets.

@zeux
Last active June 25, 2019 05:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeux/31eb8c73e1d4992a85c5f6d6871db9e4 to your computer and use it in GitHub Desktop.
Save zeux/31eb8c73e1d4992a85c5f6d6871db9e4 to your computer and use it in GitHub Desktop.
Isolate UV islands and move each island to 0..1 range if possible; this reduces the total UV range of the mesh.
unsigned int follow(std::vector<unsigned int>& ids, unsigned int v)
{
unsigned int nv = v;
while (ids[nv] != nv)
nv = ids[nv];
return ids[v] = nv;
}
size_t islandize(const std::vector<unsigned int>& indices, std::vector<unsigned int>& islands)
{
for (size_t i = 0; i < islands.size(); ++i)
islands[i] = unsigned(i);
for (size_t i = 0; i < indices.size(); i += 3)
{
static const int next[3] = {1, 2, 0};
for (int e = 0; e < 3; ++e)
{
unsigned int i0 = indices[i + e];
unsigned int i1 = indices[i + next[e]];
unsigned int v0 = follow(islands, i0);
unsigned int v1 = follow(islands, i1);
islands[std::max(v0, v1)] = std::min(v0, v1);
}
}
size_t result = 0;
for (size_t i = 0; i < islands.size(); ++i)
{
unsigned int v = islands[i];
assert(v <= unsigned(i));
if (v < unsigned(i))
islands[i] = islands[v];
else
islands[i] = unsigned(result++);
}
return result;
}
void reuvMesh(Mesh& mesh)
{
// UV bounds of the mesh can get pretty large
// this can happen in two cases:
// 1. mesh has tiled UVs
// 2. mesh has poorly boxmapped UVs that were left outside of 0..1 space
// we can't do much in case 1, but we can solve case 2 by moving entire UV islands to 0..1
size_t vertex_count = mesh.streams[0].data.size();
std::vector<unsigned int> islands(vertex_count);
size_t island_count = islandize(mesh.indices, islands);
std::vector<Attr> minmax(island_count);
for (size_t i = 0; i < mesh.streams.size(); ++i)
{
Stream& stream = mesh.streams[i];
if (stream.type != cgltf_attribute_type_texcoord)
continue;
for (size_t j = 0; j < island_count; ++j)
{
Attr minmax_dummy = {+FLT_MAX, +FLT_MAX};
minmax[j] = minmax_dummy;
}
for (size_t j = 0; j < vertex_count; ++j)
{
Attr& mm = minmax[islands[j]];
Attr& uv = stream.data[j];
mm.f[0] = std::min(mm.f[0], uv.f[0]);
mm.f[1] = std::min(mm.f[1], uv.f[1]);
}
for (size_t j = 0; j < vertex_count; ++j)
{
Attr& mm = minmax[islands[j]];
Attr& uv = stream.data[j];
uv.f[0] -= floorf(mm.f[0]);
uv.f[1] -= floorf(mm.f[1]);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment