mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 10:53:44 +00:00
feat(ugc): glitter flecks (LEGO-AnimUV) and milky satin in made models
Glitter colors (Materials.xml type glitter, glitter_colors 114,117) go into S21_Glitter_Model and, transparent, S21_GlitterAlpha_Model (shader_glitter, default 21, LEGO-AnimUV). Their shapes get box-projected UVs, an NiTexturingProperty with a stored 128 px mipmapped fleck texture (NiSourceTexture + NiPersistentSrcTextureRendererData, as the client's own env_ag_ocean-maelstrom.nif) and two NiTextureTransformControllers looping the base map's translation (glitter_size, glitter_density, glitter_speed). The shader lays the texture over the vertex color by its alpha and outputs the vertex alpha, so transparent glitter blends as S01_Alpha does. Satin colors (satin_colors, LEGO's opal colors) stay in S01_Alpha but get satin_opacity and are whitened by satin_whiten. NifFile reads the base map's scroll speed (uvScroll) from the controllers; the icon draws still flecks, the UGC 3D view and the LXFML viewers moving ones. stats.json counts the glitter groups. With shader_glitter 0 and no satin colors the files are the same bytes as before (tested). Also keeps glow_emissive for the icon (it was reset by the icon settings). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -223,7 +223,7 @@ namespace UgcModel {
|
||||
Model model;
|
||||
std::set<uint32_t> missing;
|
||||
const bool luToolbox = options.palette == ePalette::LU_TOOLBOX;
|
||||
bool anyGlow = false, anyLook = false;
|
||||
bool anyGlow = false, anyLook = false, anyTransparentLook = false;
|
||||
for (uint32_t brick = 0; brick < parts.size(); brick++) {
|
||||
const auto& part = parts[brick];
|
||||
const auto design = library.GetDesign(part.designId, options.lod);
|
||||
@@ -283,10 +283,16 @@ namespace UgcModel {
|
||||
linear = UgcPalette::ApplyVariation(linear, variation, UgcPalette::BrickRandom(options.seed, brick, colorId));
|
||||
}
|
||||
if (!options.icon && options.brightness != 100.0f) linear *= std::max(options.brightness, 0.0f) / 100.0f;
|
||||
if (options.satinColors.contains(colorId)) {
|
||||
// Satin: milky, and less see-through than clear plastic
|
||||
linear = glm::mix(linear, glm::vec3(1.0f), std::clamp(options.satinWhiten / 100.0f, 0.0f, 1.0f));
|
||||
if (transparent) alpha = std::clamp(options.satinOpacity / 100.0f, 0.0f, 1.0f);
|
||||
}
|
||||
const glm::vec4 color(UgcPalette::LinearToSrgb(linear), alpha);
|
||||
anyGlow = anyGlow || glow != glm::vec3(0.0f);
|
||||
const auto look = transparent ? eLook::PLASTIC : LookOf(colorId, library.GetMaterial(colorId), options.looks);
|
||||
anyLook = anyLook || look != eLook::PLASTIC;
|
||||
auto look = LookOf(colorId, library.GetMaterial(colorId), options.looks);
|
||||
if (transparent && look != eLook::GLITTER) look = eLook::PLASTIC;
|
||||
(transparent ? anyTransparentLook : anyLook) = (transparent ? anyTransparentLook : anyLook) || look != eLook::PLASTIC;
|
||||
const auto base = static_cast<uint32_t>(mesh.positions.size());
|
||||
const size_t vertexCount = geometry.positions.size() / 3;
|
||||
for (size_t v = 0; v < vertexCount; v++) {
|
||||
@@ -298,10 +304,8 @@ namespace UgcModel {
|
||||
mesh.positions.push_back(glm::vec3(part.transform * glm::vec4(position, 1.0f)));
|
||||
mesh.normals.push_back(normal);
|
||||
mesh.colors.push_back(color);
|
||||
if (&mesh == &model.opaque) {
|
||||
model.opaque.glow.push_back(glow);
|
||||
model.opaque.looks.push_back(look);
|
||||
}
|
||||
if (&mesh == &model.opaque) model.opaque.glow.push_back(glow);
|
||||
mesh.looks.push_back(look);
|
||||
}
|
||||
for (const auto i : geometry.indices) mesh.indices.push_back(base + i);
|
||||
}
|
||||
@@ -309,6 +313,7 @@ namespace UgcModel {
|
||||
if (!anyGlow) model.opaque.glow.clear();
|
||||
else model.opaque.glow.resize(model.opaque.positions.size(), glm::vec3(0.0f));
|
||||
if (!anyLook) model.opaque.looks.clear();
|
||||
if (!anyTransparentLook) model.transparent.looks.clear();
|
||||
model.missingDesigns.assign(missing.begin(), missing.end());
|
||||
return model;
|
||||
}
|
||||
@@ -376,7 +381,7 @@ namespace UgcModel {
|
||||
// Blending only shows where something is see-through (the game's brick models blend every shape)
|
||||
bool seeThrough = source.material.alphaBlend && source.material.alpha < 0.99f;
|
||||
for (size_t v = 0; source.material.alphaBlend && !seeThrough && v < mesh.colors.size(); v++) seeThrough = mesh.colors[v].a < 0.99f;
|
||||
if (const auto look = tagLooks.find(source.material.shaderTag); !seeThrough && look != tagLooks.end() && look->second != eLook::PLASTIC) {
|
||||
if (const auto look = tagLooks.find(source.material.shaderTag); look != tagLooks.end() && look->second != eLook::PLASTIC && (!seeThrough || look->second == eLook::GLITTER)) {
|
||||
mesh.looks.assign(mesh.positions.size(), look->second);
|
||||
}
|
||||
(seeThrough ? model.transparent : model.opaque).Append(mesh);
|
||||
|
||||
Reference in New Issue
Block a user