feat(ugc): opt-in metal and glow shader groups in made models

Player models are multishader (RenderComponent shader 100): the client
wraps each NiLODNode and draws it with the mapShaders id in its name.
With shader_metal, shader_brushed or shader_glow set, the opaque bricks
are split by look into S<id>_Metal_Model, S<id>_Brushed_Model and
S<id>_Glow_Model beside S01_Opaque_Model and S01_Alpha_Model, each with
every LOD level. Metal is LU Toolbox's metallic colors plus Materials.xml
types (shinySteel; brushedSteel and matteSteel for brushed), glow its
glow colors. Glow shapes get an emissive material (glow_emissive) and
their plain color, not the baked one. Transparent glow stays in S01_Alpha.

All off by default, which writes the same bytes as before (tested). Not
how live looked; models already made change only when made again.

The icon renderer reads the groups back by tag and draws glow at its
plain color and metal with a tinted reflection and highlight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-28 09:55:00 -05:00
parent b65220b446
commit c39b7ee935
16 changed files with 560 additions and 45 deletions

View File

@@ -209,7 +209,7 @@ void UgcProcessor::Worker() {
const auto nif = m_Storage.ReadNif(Kind::MODEL, job.id, "model.nif");
auto options = settings.icon;
UgcIconParams::Apply(options, job.iconValues);
outcome.ok = nif && UgcJobs::IconFromNif(*nif, options, outcome.files, outcome.error);
outcome.ok = nif && UgcJobs::IconFromNif(*nif, options, outcome.files, outcome.error, settings.shaders.TagLooks());
if (!nif) outcome.error = "the model has no stored .nif yet";
}
if (outcome.ok && outcome.files.contains("assembly.nif")) {
@@ -252,7 +252,7 @@ void UgcProcessor::Worker() {
const auto nif = m_Storage.ReadNif(Kind::MODEL, job.id, "model.nif");
auto options = settings.icon;
UgcIconParams::Apply(options, job.iconValues);
done.outcome.ok = nif && UgcJobs::IconFromNif(*nif, options, done.outcome.files, done.outcome.error);
done.outcome.ok = nif && UgcJobs::IconFromNif(*nif, options, done.outcome.files, done.outcome.error, settings.shaders.TagLooks());
if (!nif) done.outcome.error = "no stored .nif";
} else {
done.outcome = job.kind == Kind::MODEL