mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
fix(ugc): glitter sparkles that move on placed models
Why the glitter never moved: player models (LOT 14) are wrapped in weeblewobble.kfm (RenderComponentWrapper 9845), so the client makes them an LWOSkinnedRenderComponent, whose Run (0x00d6d3d0) updates the scene graph (and so any NiTextureTransformController) only while animation is enabled, and LWOModelBehaviorComponent::EnableAnimation (0x00be2740) turns it off for modelType 2, which every placed property model is. The root flags 0x102 added earlier are only read by the base render component. Nothing in a placed model's .nif can move. What does move: shader classes set globals in their own per-frame Run. Distortion Directional (Ocean) (mapShaders 79, Run 0x010b90c0) slides its texture layers by fixed shares of a tile a second, as the game's own pond ripples (S79__pond_ripplesShape). Glitter bricks now get a sparkle group, S79_GlitterSparkle_Model: their triangles lifted 0.005 off the brick, vertex colors white tinted by the brick, UVs placed per brick, alpha tested (ShaderCommon's alpha test phase, GREATEREQUAL 127), with a stored texture of flat sparkles at alpha 230: one layer's sparkle alone averages under the test, two meeting pass, so sparkles flash and go out as the layers cross. The flecks stay (LEGO-AnimUV, now without the controllers and flags that never ran). The icon and the dashboard's 3D view leave the sparkles out. New settings: shader_glitter_sparkle (79, 0 off), glitter_sparkle_size, glitter_sparkle_amount, glitter_sparkle_tint, glitter_sparkle_brightness; glitter_speed is now how fast sparkles flash (the sparkle tile). Only glitter output changes; non-glitter models are byte-identical. Check in game: reprocess a property with glitter models, then look at them from a few angles and distances, on each graphics quality: - sparkles flash on and off all over the glitter bricks, continuously - no flickering fight between the sparkles and the brick surface - transparent glitter bricks still see-through, flecks still visible - nothing drawn where there is no glitter brick; icons unchanged apart from the flecks Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -474,12 +474,17 @@ namespace {
|
||||
c.Add(Text(UGC, "metal_material_types", "Metal material types", "Materials.xml MaterialTypes drawn as metal, comma separated (none: only LU Toolbox's metallic colors).", "shinySteel"));
|
||||
c.Add(Text(UGC, "brushed_material_types", "Brushed steel material types", "Materials.xml MaterialTypes drawn as brushed steel, comma separated (none: no such colors).", "brushedSteel,matteSteel"));
|
||||
c.Add(Text(UGC, "brushed_colors", "Brushed steel colors", "LEGO color ids drawn as brushed steel whatever their Materials.xml type, comma separated: by default the drum lacquered 298,300,1002,1004 (none: no colors).", "298,300,1002,1004"));
|
||||
c.Add(Int(UGC, "shader_glitter", "Glitter shader", "mapShaders id for glitter colors, in S<id>_Glitter_Model and (transparent ones) S<id>_GlitterAlpha_Model: 21 is LEGO-AnimUV, which lays a white fleck texture stored in the model over the color and moves it. 0: off, they stay plastic." + notLive, "21", 0, 9999));
|
||||
c.Add(Int(UGC, "shader_glitter", "Glitter shader", "mapShaders id for glitter colors, in S<id>_Glitter_Model and (transparent ones) S<id>_GlitterAlpha_Model: 21 is LEGO-AnimUV, which lays a white fleck texture stored in the model over the color (still: the client never updates a placed model; see the sparkle shader). 0: off, they stay plastic." + notLive, "21", 0, 9999));
|
||||
c.Add(Text(UGC, "glitter_material_types", "Glitter material types", "Materials.xml MaterialTypes drawn as glitter, comma separated (none: only the glitter colors below).", "glitter"));
|
||||
c.Add(Text(UGC, "glitter_colors", "Glitter colors", "LEGO color ids drawn as glitter whatever their Materials.xml type, comma separated: by default 114,117, which LEGO's color data calls glitter and the client's Materials.xml plain plastic (none: no colors).", "114,117"));
|
||||
c.Add(Float(UGC, "glitter_size", "Glitter tile size", "The fleck texture's tile in model units (a stud is 0.8): how far apart the flecks are, the same on every brick.", "1.6", 0.1f, 100));
|
||||
c.Add(Int(UGC, "glitter_density", "Glitter flecks", "Flecks in one tile of the glitter texture.", "50", 0, 2000));
|
||||
c.Add(Float(UGC, "glitter_speed", "Glitter speed", "How fast the flecks drift: 1 moves them a tile in 7 s one way and 11 s the other; 0 keeps them still.", "1", 0, 100));
|
||||
c.Add(Int(UGC, "shader_glitter_sparkle", "Glitter sparkle shader", "mapShaders id for the glitter bricks' sparkles, in S<id>_GlitterSparkle_Model over both glitter groups (only with the glitter shader on): 79 is Distortion Directional (Ocean), whose texture layers the client moves every frame on its own, so a sparkle flashes where two layers' sparkles meet. Nothing else moves on a placed model (the client never updates it). 0: no sparkles.", "79", 0, 9999));
|
||||
c.Add(Float(UGC, "glitter_sparkle_size", "Glitter sparkle size", "A sparkle's diameter in model units (a stud is 0.8).", "0.1", 0.01f, 1));
|
||||
c.Add(Float(UGC, "glitter_sparkle_amount", "Glitter sparkle amount", "Percent of each moving sparkle layer covered by sparkles; a sparkle shows where two meet, so about this share squared of a brick sparkles at once.", "5", 0, 50));
|
||||
c.Add(Float(UGC, "glitter_speed", "Glitter sparkle speed", "How fast sparkles flash and go out: 1 is about half a second each (the sparkle texture is made bigger so the client's fixed layer motion crosses sparkles faster).", "1", 0.1f, 4));
|
||||
c.Add(Float(UGC, "glitter_sparkle_tint", "Glitter sparkle tint", "Percent: how far the sparkles take their brick's color (0: white).", "30", 0, 100));
|
||||
c.Add(Float(UGC, "glitter_sparkle_brightness", "Glitter sparkle brightness", "Percent: the sparkles' vertex color (the client lights them like its other surfaces).", "100", 0, 100));
|
||||
c.Add(Bool(UGC, "glitter_random", "Glitter placed per brick", "Each glitter brick gets its own fleck pattern (turned and moved by a number of the brick's own, the same every time the model is made); off: the same pattern on every brick.", true));
|
||||
c.Add(Text(UGC, "satin_colors", "Satin colors", "Satin (opal) color ids, comma separated: they stay transparent plastic (the client has no satin shader) but are made milky and less see-through. By default LEGO's satin colors 360,362,363,364,365,366,367,376 (none: off)." + notLive, "360,362,363,364,365,366,367,376"));
|
||||
c.Add(Float(UGC, "satin_opacity", "Satin opacity", "Percent: the opacity of transparent satin bricks, instead of the transparent opacity.", "75", 0, 100));
|
||||
|
||||
@@ -491,7 +491,7 @@ namespace UgcRoutes {
|
||||
|
||||
Route(eHTTPMethod::GET, "/api/ugc/mesh/:id", Perm("properties_view"),
|
||||
"A player model's generated .nif converted for the 3D view (NifFile::Encode, as the scenery meshes, with each mesh's shader look; the glitter "
|
||||
"groups' meshes have the GLITTER look, their UVs and uvScroll, and the texture name \"glitter\"). Query: ?lod=0 (most detailed) "
|
||||
"groups' meshes have the GLITTER look, their UVs and the texture name \"glitter\"; the glitter sparkles the SPARKLE look and \"sparkle\"). Query: ?lod=0 (most detailed) "
|
||||
"to 3, &version=current|previous, &ao=0 for the mesh before the lighting bake. The header adds triangles and vertices",
|
||||
[](HTTPReply& reply, const HTTPContext& context) {
|
||||
const auto id = PathId<LWOOBJID>(context.path, 3);
|
||||
@@ -501,9 +501,11 @@ namespace UgcRoutes {
|
||||
const bool baked = QueryValue(context.queryString, "ao") != "0";
|
||||
const std::string file = std::string(previous ? "previous." : "") + (baked ? "model.nif" : "model.noao.nif");
|
||||
const auto url = InternalUrl() + "/files/model/" + std::to_string(*id) + "/" + file;
|
||||
// The glitter groups' tag: the setting's, and the client's LEGO-AnimUV (21) for models made with another
|
||||
// The glitter groups' tag: the setting's, and the client's LEGO-AnimUV (21) for models made with another;
|
||||
// the sparkles' likewise (Distortion Directional, 79), alpha tested
|
||||
const auto glitterTag = GeneralUtils::TryParse<int32_t>(UgcSetting("shader_glitter").value_or("21")).value_or(21);
|
||||
Workers::Reply(reply, context, false, [url, lod, glitterTag](HTTPReply& out) {
|
||||
const auto sparkleTag = GeneralUtils::TryParse<int32_t>(UgcSetting("shader_glitter_sparkle").value_or("79")).value_or(79);
|
||||
Workers::Reply(reply, context, false, [url, lod, glitterTag, sparkleTag](HTTPReply& out) {
|
||||
const auto fetched = CachedGet(url);
|
||||
if (fetched->status != 200) return ReplyError(out, *fetched, url);
|
||||
std::string error;
|
||||
@@ -513,6 +515,11 @@ namespace UgcRoutes {
|
||||
std::vector<std::string> textures(model->meshes.size());
|
||||
for (size_t i = 0; i < model->meshes.size(); i++) {
|
||||
const auto& material = model->meshes[i].material;
|
||||
if (material.embeddedTexture >= 0 && material.alphaTest && (material.shaderTag == sparkleTag || material.shaderTag == 79)) {
|
||||
looks[i] |= NifFile::SPARKLE;
|
||||
textures[i] = "sparkle";
|
||||
continue;
|
||||
}
|
||||
if (material.embeddedTexture < 0 || (material.shaderTag != glitterTag && material.shaderTag != 21)) continue;
|
||||
looks[i] |= NifFile::GLITTER;
|
||||
textures[i] = "glitter";
|
||||
|
||||
@@ -174,7 +174,7 @@ async function loadGeneratedModel(url) {
|
||||
// ---- Viewer ----
|
||||
|
||||
const materialCache = new Map();
|
||||
// The glitter colours' moving flecks (window.LDD_GLITTER, the UGC server's glitter settings), updated each frame
|
||||
// The glitter colours' flecks (window.LDD_GLITTER, the UGC server's glitter settings)
|
||||
const glitterMaterials = [];
|
||||
function material(id) {
|
||||
if (!materialCache.has(id)) {
|
||||
@@ -192,9 +192,8 @@ function material(id) {
|
||||
});
|
||||
const glitter = window.LDD_GLITTER;
|
||||
if (glitter && (glitter.colors || []).includes(Number(id))) {
|
||||
// Moving as the game moves its fleck texture: a tile in U in 7 s and in V in 11 s at speed 1
|
||||
const speed = glitter.speed || 0;
|
||||
glitterMaterials.push(addGlitter(created, { coordinates: 'position', tile: glitter.tile || 1.6, flecks: glitter.flecks || 50, scroll: [speed / 7, speed / 11] }));
|
||||
// Still, as the game draws them on a placed model
|
||||
glitterMaterials.push(addGlitter(created, { coordinates: 'position', tile: glitter.tile || 1.6, flecks: glitter.flecks || 50 }));
|
||||
}
|
||||
materialCache.set(id, created);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ export function shaderOf(manifest, asset, mesh) {
|
||||
|
||||
// NifFile::eShaderLook bits
|
||||
export const SHADER_LOOK = { UNLIT: 1, NO_TEXTURE: 2, NO_VERTEX_COLORS: 4, MATERIAL_COLOR: 8, TWO_LAYERS_BLENDED: 16, TWO_LAYERS_ADDED: 32, REFLECTIVE: 64, BRUSHED: 128, EMISSIVE: 256,
|
||||
GLITTER: 512 };
|
||||
GLITTER: 512, SPARKLE: 1024 };
|
||||
|
||||
/**
|
||||
* Glitter for a three.js material (the UGC server's glitter colors, UgcGlitter): white flecks over the color before
|
||||
|
||||
@@ -123,6 +123,8 @@ export function createNifViewer(container) {
|
||||
let seeThrough = !!mesh.blend && mesh.alpha < 0.99;
|
||||
if (mesh.blend && hasColors) for (let i = 3; i < mesh.colors.length && !seeThrough; i += 4) seeThrough = mesh.colors[i] < 250;
|
||||
const look = mesh.look || 0;
|
||||
// The glitter sparkles (drawn over the glitter bricks) aren't drawn here
|
||||
if (look & SHADER_LOOK.SPARKLE) continue;
|
||||
const metal = metalOf(look);
|
||||
// Glow: the emissive shader's vertex color, unlit (its vertex alpha is the glow, not opacity)
|
||||
const material = look & SHADER_LOOK.EMISSIVE
|
||||
|
||||
Reference in New Issue
Block a user