mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
feat(ugc): live accurate color variation (-6 to 6 per channel, opaque bricks only)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -479,7 +479,8 @@ namespace {
|
||||
c.Add(Int(UGC, "max_attempts", "Attempts before giving up", "", "3", 1, 100, true));
|
||||
c.AddSection("UGC models", "How a model's mesh is made from its bricks (LU Toolbox's steps).", eLayout::ROWS, Condition{ MASTER, "enable_ugc_server", { "1" } });
|
||||
c.Add(Labels(Choice(UGC, "color_palette", "Colors", "LU Toolbox's LU palette (unknown colors black), or the client's Materials.xml.", "lu_toolbox", { "lu_toolbox", "brickdb" }), { "LU Toolbox", "Brick database" }));
|
||||
c.Add(Unit(Float(UGC, "color_variation", "Color variation", "Each brick's brightness is shifted by up to this much (the same every time the model is made). 0: none.", "5", 0, 100), "%"));
|
||||
c.Add(Labels(Choice(UGC, "color_variation_mode", "Color variation kind", "toolbox: LU Toolbox's, each brick's brightness shifted by up to Color variation. live: live accurate, a whole number from -6 to 6 added to each of a brick's red, green and blue (0-255), transparent bricks left as they are; Color variation is not used. The same every time a model is made.", "toolbox", { "toolbox", "live" }), { "LU Toolbox", "Live accurate" }));
|
||||
c.Add(Unit(Float(UGC, "color_variation", "Color variation", "Each brick's brightness is shifted by up to this much (the same every time the model is made). 0: none. Only for the LU Toolbox kind.", "5", 0, 100), "%"));
|
||||
c.Add(Unit(Float(UGC, "transparent_opacity", "Transparent opacity", "", "58.82", 0, 100), "%"));
|
||||
c.Add(Unit(Float(UGC, "color_brightness", "Model color brightness", "The models' vertex colors (not the icons'). 100: as the palette has them; lower is darker. Models already made keep theirs until they are made again.", "100", 0, 200), "%"));
|
||||
c.Add(Text(UGC, "transparent_colors", "Always transparent colors", "LEGO color ids drawn transparent whatever Materials.xml says, comma separated: by default 129, the transparent glitter violet, which Materials.xml has opaque (none: no colors). Their opacity is Transparent opacity.", "129"));
|
||||
|
||||
@@ -208,6 +208,16 @@ namespace UgcPalette {
|
||||
return color * (newValue / value);
|
||||
}
|
||||
|
||||
int32_t LiveVariationStep(float random) {
|
||||
return std::clamp(static_cast<int32_t>(std::floor(random * 13.0f)), 0, 12) - 6;
|
||||
}
|
||||
|
||||
glm::vec3 ApplyLiveVariation(const glm::vec3& linear, float random) {
|
||||
const auto step = static_cast<float>(LiveVariationStep(random));
|
||||
const auto srgb = glm::round(LinearToSrgb(linear) * 255.0f);
|
||||
return SrgbToLinear(glm::clamp(srgb + step, 0.0f, 255.0f) / 255.0f);
|
||||
}
|
||||
|
||||
float BrickRandom(uint64_t seed, uint32_t brick, uint32_t material) {
|
||||
const auto bits = SplitMix(SplitMix(seed ^ (static_cast<uint64_t>(brick) << 32)) ^ material);
|
||||
return static_cast<float>(bits >> 40) / static_cast<float>(1ull << 24);
|
||||
|
||||
@@ -41,6 +41,12 @@ namespace UgcPalette {
|
||||
*/
|
||||
glm::vec3 ApplyVariation(const glm::vec3& color, float variationPercent, float random);
|
||||
|
||||
// The live accurate color variation of one color (linear): a whole number from -6 to 6 picked by `random` (0..1)
|
||||
// added to each of its 0-255 sRGB channels, clamped to 0..255
|
||||
glm::vec3 ApplyLiveVariation(const glm::vec3& linear, float random);
|
||||
// That number: -6 to 6 inclusive, each equally likely
|
||||
int32_t LiveVariationStep(float random);
|
||||
|
||||
/**
|
||||
* The random number (0..1) of one brick's material: the same for the same seed, brick and material every time,
|
||||
* so making a model again gives the same colors, and the same in every LOD (LU Toolbox restarts its random sequence
|
||||
|
||||
@@ -289,7 +289,9 @@ namespace UgcModel {
|
||||
linear = UgcPalette::SrgbToLinear(glm::vec3(material.r, material.g, material.b) / 255.0f);
|
||||
if (transparent) alpha = material.a < 255 ? material.a / 255.0f : std::clamp(options.transparentOpacity / 100.0f, 0.0f, 1.0f);
|
||||
}
|
||||
if (options.colorVariation > 0.0f) {
|
||||
if (options.variationMode == BuildOptions::eVariation::LIVE) {
|
||||
if (!transparent) linear = UgcPalette::ApplyLiveVariation(linear, UgcPalette::BrickRandom(options.seed, brick, colorId));
|
||||
} else if (options.colorVariation > 0.0f) {
|
||||
const float variation = options.colorVariation * (luToolbox ? UgcPalette::VariationScale(colorId) : 1.0f);
|
||||
linear = UgcPalette::ApplyVariation(linear, variation, UgcPalette::BrickRandom(options.seed, brick, colorId));
|
||||
}
|
||||
|
||||
@@ -99,6 +99,9 @@ namespace UgcModel {
|
||||
struct BuildOptions {
|
||||
ePalette palette{ ePalette::LU_TOOLBOX };
|
||||
float colorVariation{ 5.0f }; // percent, 0: none (LU Toolbox: Apply Color Variation, 5%)
|
||||
// LU Toolbox's (colorVariation percent of the brightness), or live accurate: -6 to 6 added to each 0-255
|
||||
// channel, opaque bricks only (colorVariation unused)
|
||||
enum class eVariation : uint8_t { TOOLBOX, LIVE } variationMode{ eVariation::TOOLBOX };
|
||||
uint64_t seed{}; // of the variation's random numbers
|
||||
float transparentOpacity{ 58.82f }; // percent, transparent bricks' vertex alpha (LU Toolbox palette only)
|
||||
float brightness{ 100.0f }; // percent, the models' vertex colors (not icons'); 100: as the palette has them
|
||||
|
||||
@@ -369,7 +369,8 @@ namespace UgcJobs {
|
||||
stats["ms"] = { { "build", std::lround(buildMs) }, { "hiddenSurfaces", std::lround(hsrMs) }, { "ambientOcclusion", std::lround(aoMs) },
|
||||
{ "icon", std::lround(iconMs) }, { "total", std::lround(Since(started)) } };
|
||||
stats["settings"] = { { "palette", settings.build.palette == UgcModel::ePalette::LU_TOOLBOX ? "lu_toolbox" : "brickdb" },
|
||||
{ "colorVariation", settings.build.colorVariation }, { "transparentOpacity", settings.build.transparentOpacity },
|
||||
{ "colorVariation", settings.build.colorVariation },
|
||||
{ "colorVariationMode", settings.build.variationMode == UgcModel::BuildOptions::eVariation::LIVE ? "live" : "toolbox" }, { "transparentOpacity", settings.build.transparentOpacity },
|
||||
{ "removeHiddenFaces", settings.hsr.enabled }, { "groundPlane", settings.hsr.groundPlane }, { "hsrResolution", settings.hsr.resolution },
|
||||
{ "ao", settings.ao.enabled }, { "aoDistance", settings.ao.distance }, { "aoSamples", settings.ao.samples }, { "aoStrength", settings.ao.strength } };
|
||||
const auto madeWith = MadeWith(settings);
|
||||
|
||||
@@ -94,6 +94,7 @@ namespace {
|
||||
UgcJobs::Settings settings;
|
||||
settings.build.palette = Game::config->GetValue("color_palette") == "brickdb" ? UgcModel::ePalette::BRICKDB : UgcModel::ePalette::LU_TOOLBOX;
|
||||
settings.build.colorVariation = std::clamp(Setting<float>("color_variation", 5.0f), 0.0f, 100.0f);
|
||||
settings.build.variationMode = Game::config->GetValue("color_variation_mode") == "live" ? UgcModel::BuildOptions::eVariation::LIVE : UgcModel::BuildOptions::eVariation::TOOLBOX;
|
||||
settings.build.transparentOpacity = std::clamp(Setting<float>("transparent_opacity", 58.82f), 0.0f, 100.0f);
|
||||
settings.build.brightness = std::clamp(Setting<float>("color_brightness", 100.0f), 0.0f, 200.0f);
|
||||
{
|
||||
|
||||
@@ -44,12 +44,15 @@ max_attempts=3
|
||||
|
||||
# Models are made like LU Toolbox's Process Model and Bake Lighting make them; these default to its settings.
|
||||
# color_palette: lu_toolbox (its LU palette, unknown colors black) or brickdb (the client's Materials.xml).
|
||||
# color_variation: each brick's brightness is shifted by up to this percent (the same every time; 0: none).
|
||||
# color_variation_mode: toolbox (LU Toolbox's: the brightness shifted by up to color_variation) or live (live accurate:
|
||||
# a whole number from -6 to 6 added to each of an opaque brick's 0-255 red, green and blue; transparent bricks unchanged).
|
||||
# color_variation: each brick's brightness is shifted by up to this percent (the same every time; 0: none; toolbox only).
|
||||
# transparent_opacity: transparent bricks' opacity in percent.
|
||||
# color_brightness: the models' colors in percent (not icons'; 100: as the palette has them, lower is darker).
|
||||
# transparent_colors: color ids drawn transparent whatever Materials.xml says, comma separated (empty: the default, 129,
|
||||
# the transparent glitter violet, which Materials.xml has opaque; none: no colors).
|
||||
color_palette=lu_toolbox
|
||||
color_variation_mode=toolbox
|
||||
color_variation=5
|
||||
transparent_opacity=58.82
|
||||
color_brightness=100
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -2234,3 +2235,21 @@ TEST(UgcRays, OtherBackendsMakeTheSameOcclusion) {
|
||||
EXPECT_EQ(made.files.at("icon.png"), embreeModel.files.at("icon.png")) << UgcRays::Name(backend);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UgcPalette, LiveVariationAddsMinusSixToSix) {
|
||||
// Every step from -6 to 6 is reachable and nothing outside it
|
||||
std::set<int32_t> steps;
|
||||
for (int i = 0; i < 1000; i++) steps.insert(UgcPalette::LiveVariationStep(i / 1000.0f));
|
||||
steps.insert(UgcPalette::LiveVariationStep(1.0f));
|
||||
EXPECT_EQ(steps.size(), 13u);
|
||||
EXPECT_EQ(*steps.begin(), -6);
|
||||
EXPECT_EQ(*steps.rbegin(), 6);
|
||||
// The step is added to each 0-255 sRGB channel and clamped
|
||||
const auto color = UgcPalette::SrgbToLinear(glm::vec3(100.0f, 0.0f, 253.0f) / 255.0f);
|
||||
const auto up = glm::round(UgcPalette::LinearToSrgb(UgcPalette::ApplyLiveVariation(color, 0.999f)) * 255.0f);
|
||||
EXPECT_EQ(up, glm::vec3(106.0f, 6.0f, 255.0f));
|
||||
const auto down = glm::round(UgcPalette::LinearToSrgb(UgcPalette::ApplyLiveVariation(color, 0.0f)) * 255.0f);
|
||||
EXPECT_EQ(down, glm::vec3(94.0f, 0.0f, 247.0f));
|
||||
const auto same = glm::round(UgcPalette::LinearToSrgb(UgcPalette::ApplyLiveVariation(color, 0.5f)) * 255.0f);
|
||||
EXPECT_EQ(same, glm::vec3(100.0f, 0.0f, 253.0f));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user