fix(ugc): each glitter brick gets its own fleck pattern

Every glitter brick had the same flecks in the same places: the UVs were
the vertex positions projected on an axis plane, so bricks a whole tile
apart (and every brick of the same shape at the same spot in its own
model) looked identical. Each brick now has a number of its own
(UgcGlitter::BrickSeed, from the model's id and the brick's index, kept
per vertex in Mesh::brickSeeds) that turns the projection by an angle
and moves it by an offset under a tile, differently for each axis
plane. A model made again gets the same patterns; every LOD of a brick
the same one. The icon now draws the flecks on the UVs the .nif has
(Mesh::uvs read back by FromNif). New setting glitter_random (1; 0 puts
the same pattern on every brick as before). Non-glitter models are
byte-identical (hash tests unchanged).

Check in game: reprocess a model with several glitter bricks of the
same shape; the fleck patterns differ from brick to brick.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 00:17:43 -05:00
parent 0a1e33d3d2
commit 63bfaf545e
11 changed files with 148 additions and 11 deletions

View File

@@ -144,7 +144,8 @@ namespace {
out.I32(-1); // collision object
}
// `glitter`: with a UV set projected for the glitter texture (UgcGlitter::Uv)
// `glitter`: with a UV set projected for the glitter texture (UgcGlitter::Uv), placed by each vertex's brick
// (Mesh::brickSeeds) when the glitter is random
std::string TriShapeData(const UgcModel::Mesh& mesh, const UgcGlitter::Params* glitter = nullptr) {
Writer out;
const auto count = static_cast<uint16_t>(mesh.positions.size());
@@ -191,7 +192,8 @@ namespace {
}
if (uvs) {
for (size_t v = 0; v < mesh.positions.size(); v++) {
const auto uv = UgcGlitter::Uv(mesh.positions[v], mesh.normals[v], glitter->tile);
const uint32_t seed = glitter->random && v < mesh.brickSeeds.size() ? mesh.brickSeeds[v] : 0;
const auto uv = UgcGlitter::Uv(mesh.positions[v], mesh.normals[v], glitter->tile, seed);
out.Float(uv.x);
out.Float(uv.y);
}