fix(ugc): metal look only from the client's material types

LU Toolbox's metallic table also has colors the client's Materials.xml types
shinyPlastic, such as 131, the grey of many baseplates, so whole baseplates went
into S88_Metal_Model. Metal now comes from the Materials.xml types (shinySteel)
and the settings' colors only; the table still gives colors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-30 03:43:30 -05:00
parent 5265da7b2e
commit 19b6443fb4
6 changed files with 14 additions and 17 deletions

View File

@@ -171,10 +171,6 @@ namespace UgcPalette {
return Transparent().contains(id); return Transparent().contains(id);
} }
bool IsMetallic(uint32_t id) {
return Metallic().contains(id);
}
std::optional<glm::vec3> Glow(uint32_t id) { std::optional<glm::vec3> Glow(uint32_t id) {
const auto it = GlowColors().find(id); const auto it = GlowColors().find(id);
return it != GlowColors().end() ? std::optional(it->second) : std::nullopt; return it != GlowColors().end() ? std::optional(it->second) : std::nullopt;

View File

@@ -18,7 +18,6 @@ namespace UgcPalette {
std::optional<glm::vec3> Linear(uint32_t id, bool icon = false); std::optional<glm::vec3> Linear(uint32_t id, bool icon = false);
bool IsTransparent(uint32_t id); bool IsTransparent(uint32_t id);
bool IsMetallic(uint32_t id);
// The glow color (linear) of a glowing material, nullopt for the others // The glow color (linear) of a glowing material, nullopt for the others
std::optional<glm::vec3> Glow(uint32_t id); std::optional<glm::vec3> Glow(uint32_t id);

View File

@@ -204,7 +204,6 @@ namespace UgcModel {
eLook LookOf(uint32_t id, const UgcBricks::Material& material, const LookRules& rules) { eLook LookOf(uint32_t id, const UgcBricks::Material& material, const LookRules& rules) {
if (const auto color = rules.colors.find(id); color != rules.colors.end()) return color->second; if (const auto color = rules.colors.find(id); color != rules.colors.end()) return color->second;
if (rules.paletteGlow && UgcPalette::Glow(id)) return eLook::GLOW; if (rules.paletteGlow && UgcPalette::Glow(id)) return eLook::GLOW;
if (rules.paletteMetallic && UgcPalette::IsMetallic(id)) return eLook::METAL;
const auto type = rules.materialTypes.find(material.type); const auto type = rules.materialTypes.find(material.type);
return type != rules.materialTypes.end() ? type->second : eLook::PLASTIC; return type != rules.materialTypes.end() ? type->second : eLook::PLASTIC;
} }

View File

@@ -81,15 +81,15 @@ namespace UgcModel {
}; };
/** /**
* Which colors have which look, from the client's data: a Materials.xml MaterialType (brickdb.zip) and LU Toolbox's * Which colors have which look, from the client's data: a Materials.xml MaterialType (brickdb.zip), LU Toolbox's
* metallic and glow colors (UgcPalette), and colors named in the settings. A named color wins, then glow over metal; * glow colors (UgcPalette) and colors named in the settings. A named color wins, then glow; transparent bricks are
* transparent bricks are plastic unless their color is glitter. * plastic unless their color is glitter. LU Toolbox's metallic table is not a look: it has colors the client types
* shinyPlastic (131, 139, 179, 183, 184, ...), plastic in the client's data.
*/ */
struct LookRules { struct LookRules {
std::map<uint32_t, eLook> colors; // LEGO color ids given a look by the settings (brushed_colors, glitter_colors) std::map<uint32_t, eLook> colors; // LEGO color ids given a look by the settings (brushed_colors, glitter_colors)
std::map<std::string, eLook> materialTypes{ { "shinySteel", eLook::METAL }, { "brushedSteel", eLook::BRUSHED }, { "matteSteel", eLook::BRUSHED }, std::map<std::string, eLook> materialTypes{ { "shinySteel", eLook::METAL }, { "brushedSteel", eLook::BRUSHED }, { "matteSteel", eLook::BRUSHED },
{ "glitter", eLook::GLITTER } }; { "glitter", eLook::GLITTER } };
bool paletteMetallic{ true }; // LU Toolbox's Metallic colors (UgcPalette::IsMetallic) are METAL
bool paletteGlow{ true }; // its glow colors (UgcPalette::Glow) are GLOW bool paletteGlow{ true }; // its glow colors (UgcPalette::Glow) are GLOW
}; };

View File

@@ -452,9 +452,11 @@ all of its levels, so each look needs a group of its own.
| `satin_whiten` | 20 | Percent: how far satin colors are moved towards white (in linear RGB, after the color variation). | | `satin_whiten` | 20 | Percent: how far satin colors are moved towards white (in linear RGB, after the color variation). |
Which color has which look is data, not a list in the code (`UgcModel::LookOf`): glow is LU Toolbox's glow table Which color has which look is data, not a list in the code (`UgcModel::LookOf`): glow is LU Toolbox's glow table
(`UgcPalette::Glow`: 50, 294, 329, 9000-9027), metal is LU Toolbox's metallic table (`UgcPalette::IsMetallic`) plus (`UgcPalette::Glow`: 50, 294, 329, 9000-9027), metal is the Materials.xml types above (the clients checked have 8 or
the Materials.xml types above (the clients checked have 8 or 14 `shinySteel` colors, and 1 or 3 `glitter` ones: 129, 14 `shinySteel` colors, and 1 or 3 `glitter` ones: 129, 341, 351), glitter is the `glitter` type plus
341, 351), glitter is the `glitter` type plus `glitter_colors`. Pearl stays plastic (the client has no shader for it). `glitter_colors`. LU Toolbox's metallic table only colors bricks, it gives no look: most of it is `shinyPlastic` in the
client's Materials.xml (131, the grey of many baseplates, is plastic in the client's brick colors too), and it put
whole baseplates in `S88_Metal_Model`. Pearl stays plastic (the client has no shader for it).
Only opaque bricks get metal and glow: a transparent glowing color (294 with the brick database palette, alpha 150) Only opaque bricks get metal and glow: a transparent glowing color (294 with the brick database palette, alpha 150)
stays in `S01_Alpha_Model`. Transparent bricks can be glitter (every glitter color the clients have is transparent: stays in `S01_Alpha_Model`. Transparent bricks can be glitter (every glitter color the clients have is transparent:
341 and 351 have alpha 150, 129 is in `transparent_colors`). 341 and 351 have alpha 150, 129 is in `transparent_colors`).

View File

@@ -476,7 +476,7 @@ TEST(UgcPalette, ColorVariationMatchesLuToolbox) {
EXPECT_FALSE(UgcPalette::IsTransparent(21)); EXPECT_FALSE(UgcPalette::IsTransparent(21));
EXPECT_TRUE(UgcPalette::Glow(9013).has_value()); EXPECT_TRUE(UgcPalette::Glow(9013).has_value());
EXPECT_FALSE(UgcPalette::Glow(21).has_value()); EXPECT_FALSE(UgcPalette::Glow(21).has_value());
EXPECT_TRUE(UgcPalette::IsMetallic(309)); EXPECT_TRUE(UgcPalette::Linear(309).has_value()); // LU Toolbox's metallic colors are colors, not looks
EXPECT_FALSE(UgcPalette::Linear(123456).has_value()); EXPECT_FALSE(UgcPalette::Linear(123456).has_value());
EXPECT_NEAR(UgcPalette::LinearToSrgb(*UgcPalette::Linear(1, true)).r, 0.7f, 1e-5f); EXPECT_NEAR(UgcPalette::LinearToSrgb(*UgcPalette::Linear(1, true)).r, 0.7f, 1e-5f);
EXPECT_NEAR(UgcPalette::LinearToSrgb(red).r * 255.0f, 222.0f, 0.5f); // LDD's bright red EXPECT_NEAR(UgcPalette::LinearToSrgb(red).r * 255.0f, 222.0f, 0.5f); // LDD's bright red
@@ -1146,7 +1146,8 @@ TEST(UgcShaders, LooksComeFromTheColorData) {
EXPECT_EQ(UgcModel::LookOf(21, plastic, rules), UgcModel::eLook::PLASTIC); EXPECT_EQ(UgcModel::LookOf(21, plastic, rules), UgcModel::eLook::PLASTIC);
EXPECT_EQ(UgcModel::LookOf(5000, steel, rules), UgcModel::eLook::METAL); // a Materials.xml shinySteel EXPECT_EQ(UgcModel::LookOf(5000, steel, rules), UgcModel::eLook::METAL); // a Materials.xml shinySteel
EXPECT_EQ(UgcModel::LookOf(5000, brushed, rules), UgcModel::eLook::BRUSHED); EXPECT_EQ(UgcModel::LookOf(5000, brushed, rules), UgcModel::eLook::BRUSHED);
EXPECT_EQ(UgcModel::LookOf(183, plastic, rules), UgcModel::eLook::METAL); // LU Toolbox's metallic, shinyPlastic in Materials.xml EXPECT_EQ(UgcModel::LookOf(183, plastic, rules), UgcModel::eLook::PLASTIC); // LU Toolbox's metallic, shinyPlastic in Materials.xml
EXPECT_EQ(UgcModel::LookOf(131, plastic, rules), UgcModel::eLook::PLASTIC); // the same (a grey that is often a whole baseplate)
EXPECT_EQ(UgcModel::LookOf(329, plastic, rules), UgcModel::eLook::GLOW); // LU Toolbox's glow colors EXPECT_EQ(UgcModel::LookOf(329, plastic, rules), UgcModel::eLook::GLOW); // LU Toolbox's glow colors
EXPECT_EQ(UgcModel::LookOf(50, plastic, rules), UgcModel::eLook::GLOW); EXPECT_EQ(UgcModel::LookOf(50, plastic, rules), UgcModel::eLook::GLOW);
EXPECT_EQ(UgcModel::LookOf(9016, plastic, rules), UgcModel::eLook::GLOW); EXPECT_EQ(UgcModel::LookOf(9016, plastic, rules), UgcModel::eLook::GLOW);
@@ -1158,13 +1159,12 @@ TEST(UgcShaders, LooksComeFromTheColorData) {
EXPECT_EQ(UgcModel::LookOf(150, steel, named), UgcModel::eLook::METAL); EXPECT_EQ(UgcModel::LookOf(150, steel, named), UgcModel::eLook::METAL);
UgcModel::LookRules none; UgcModel::LookRules none;
none.materialTypes.clear(); none.materialTypes.clear();
none.paletteMetallic = false;
EXPECT_EQ(UgcModel::LookOf(5000, steel, none), UgcModel::eLook::PLASTIC); EXPECT_EQ(UgcModel::LookOf(5000, steel, none), UgcModel::eLook::PLASTIC);
EXPECT_EQ(UgcModel::LookOf(150, steel, none), UgcModel::eLook::PLASTIC); EXPECT_EQ(UgcModel::LookOf(150, steel, none), UgcModel::eLook::PLASTIC);
// Built: opaque vertices get their color's look, transparent bricks none (their glow stays with them) // Built: opaque vertices get their color's look, transparent bricks none (their glow stays with them)
UgcBricks::BrickLibrary library(MakeRes(), 0); UgcBricks::BrickLibrary library(MakeRes(), 0);
library.SetMaterials({ { 5000, brushed } }); library.SetMaterials({ { 150, steel }, { 5000, brushed } });
std::string error; std::string error;
const auto model = UgcModel::Build(UgcModel::ParseLxfml(R"(<LXFML versionMajor="5"><Bricks> const auto model = UgcModel::Build(UgcModel::ParseLxfml(R"(<LXFML versionMajor="5"><Bricks>
<Brick><Part designID="3001" materials="150"><Bone transformation="1,0,0,0,1,0,0,0,1,0,0,0"/></Part></Brick> <Brick><Part designID="3001" materials="150"><Bone transformation="1,0,0,0,1,0,0,0,1,0,0,0"/></Part></Brick>
@@ -1189,6 +1189,7 @@ TEST(UgcShaders, LooksComeFromTheColorData) {
TEST(UgcShaders, WritesAGroupPerLookWithEveryLevel) { TEST(UgcShaders, WritesAGroupPerLookWithEveryLevel) {
UgcBricks::BrickLibrary library(MakeRes(), 0); UgcBricks::BrickLibrary library(MakeRes(), 0);
library.SetMaterials({ { 150, { 152, 155, 153, 255, "shinySteel" } } }); // the client's Materials.xml entry
auto settings = SmallSettings(); auto settings = SmallSettings();
settings.build.colorVariation = 0.0f; settings.build.colorVariation = 0.0f;
settings.shaders.metal = 88; settings.shaders.metal = 88;