From bdbdd8e2220b9cdac297cb92736bcadb36c1df06 Mon Sep 17 00:00:00 2001 From: Clifford Garwood Date: Mon, 10 Aug 2026 07:45:50 -0400 Subject: [PATCH] fix(imex): resolve ghost colors live at render time, not at bake time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ghost GLVolumes baked their filament color once in calc_imex_ghosts and only rebuilt when build_imex_ghost_cache_key changed. The key covers the mesh-shaping inputs (mode topology, pem, object set, per-plate head map) but not filament_colour, and no invalidation hook fires on filament preset or color changes — so a ghost baked under a transient palette (late-loading project colors, a subsequently edited filament color) kept the stale color forever. A failed lookup at bake time baked GLVolume::UNPRINTABLE_COLOR, which renders as a jet-black ghost while the hover tooltip — which re-resolves live — shows the correct color. Re-stamp each ghost's color in _render_imex_ghosts from get_imex_head_filament_color, the same resolution the tooltip runs, so the two can never disagree. Resolution is hoisted into a per-head map so instances sharing a head resolve once per frame; the alpha baked by calc_imex_ghosts is preserved. The render loop already stamps color per ghost per frame (set_render_color + model.set_color), so the added cost is a couple of map lookups. The cache key stays scoped to what it actually protects: the expensive mesh bake and transforms. Co-Authored-By: Claude Fable 5 --- src/slic3r/GUI/GLCanvas3D.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 31cc15770b..c85d40d5e5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -7559,8 +7559,21 @@ void GLCanvas3D::_render_imex_ghosts() // Refresh per-frame so ghost positions reflect the primary's live drag state. active_plate->update_imex_ghost_transforms(primary_live_xf); const auto& ghosts = active_plate->get_imex_ghost_volumes(); + // Re-resolve ghost colors live instead of trusting the bake: the ghost cache key + // covers mesh-shaping inputs (mode, pem, object set) but not filament_colour, so + // a palette edit or a late-loading project color would leave stale — or + // UNPRINTABLE-black — ghosts until an unrelated rebuild. This is the same + // resolution the hover tooltip runs, so the two can never disagree. + std::map head_colors; for (const auto& g : ghosts) { if (!g || !g->is_active) continue; + const int head = PartPlate::imex_ghost_head_from_composite_id(g->composite_id.object_id); + auto hc = head_colors.find(head); + if (hc == head_colors.end()) + hc = head_colors.emplace(head, active_plate->get_imex_head_filament_color(head)).first; + ColorRGBA color = hc->second; + color.a(g->color.a()); // keep the ghost alpha baked by calc_imex_ghosts + g->color = color; const Transform3d model_matrix = g->world_matrix(); shader->set_uniform("volume_world_matrix", model_matrix); shader->set_uniform("slope.volume_world_normal_matrix",