Last active
June 25, 2019 05:58
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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