diff --git a/docs/HLSD/design-tab.md b/docs/HLSD/design-tab.md index c4bb9fd297..996447f764 100644 --- a/docs/HLSD/design-tab.md +++ b/docs/HLSD/design-tab.md @@ -189,6 +189,15 @@ degenerate edges are left out (`GeometryEngine::display_edges`), and the polylin once per shape, keyed by its `TShape`, because a recompute that leaves a body unchanged is the common case. +While a feature card is open, its preview ghost is the whole model the candidate would produce, +drawn translucent over the bodies, so every face the feature leaves alone is in both at the same +depth. The ghost is drawn with a depth bias that pushes it back (`GLVolume::depth_bias`), so on a shared face +the body always wins instead of the two copies z-fighting, and the ghost shows only where the +result reaches past the bodies. Material a feature removes lies inside the old solid and would not +show at all, so the tools whose result mostly coincides with the body — Fillet/Chamfer, Draft, +Hole and the Mate hover — hide the bodies once the preview is valid and draw the result alone, +opaque. + ## Showing what is selected A selection is drawn on the faces it names, never as a tint over the body: a translucent diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 597b960710..77010cbf9d 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -310,6 +310,7 @@ GLVolume::GLVolume(float r, float g, float b, float a) , force_native_color(false) , force_neutral_color(false) , force_sinking_contours(false) + , depth_bias(false) , picking(false) , tverts_range(0, size_t(-1)) { @@ -1332,11 +1333,17 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, shader->set_uniform("projection_matrix", projection_matrix); const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose(); shader->set_uniform("view_normal_matrix", view_normal_matrix); + if (volume.first->depth_bias) { + glsafe(::glEnable(GL_POLYGON_OFFSET_FILL)); + glsafe(::glPolygonOffset(1.0f, 1.0f)); + } //BBS: add outline related logic if (volume.first->selected && shader_can_outline && GUI::wxGetApp().show_outline()) volume.first->render_with_outline(cnv_size); else volume.first->render(); + if (volume.first->depth_bias) + glsafe(::glDisable(GL_POLYGON_OFFSET_FILL)); #if ENABLE_ENVIRONMENT_MAP if (use_environment_texture) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 663979690f..664cd109cf 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -232,6 +232,10 @@ public: bool force_neutral_color : 1; // Whether or not to force rendering of sinking contours bool force_sinking_contours : 1; + // Orca: draw this volume with a positive depth bias (glPolygonOffset, pushed away from the + // camera), so on a surface it shares with another volume the other volume wins the depth + // test instead of z-fighting it + bool depth_bias : 1; // Is render for picking bool picking : 1; // slice error diff --git a/src/slic3r/GUI/CAD/DesignCanvas.cpp b/src/slic3r/GUI/CAD/DesignCanvas.cpp index 0e7296ccd4..6af0ee7ae1 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.cpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.cpp @@ -378,10 +378,14 @@ void DesignCanvas::reload(bool keep_view) v->set_color(c); } } else if (obj_idx == 1) { - // The ghost is normally a faint blue overlay on the visible body. In preview-only - // mode it IS the result (base bodies hidden), so render it opaque so it reads as a - // finished solid rather than a see-through hint. + // The ghost is the whole resulting model, normally drawn as a faint blue overlay on + // the visible bodies. Every face the feature leaves alone is in both, at the same + // depth, so the ghost is drawn with a depth bias: the bodies win on those faces instead + // of the two copies z-fighting, and the ghost shows only where the result reaches past + // the bodies. In preview-only mode it IS the result (base bodies hidden), so render it + // opaque so it reads as a finished solid rather than a see-through hint. v->set_color(m_body_hidden ? ColorRGBA(0.40f, 0.82f, 1.0f, 1.0f) : ghost); + v->depth_bias = true; } } diff --git a/src/slic3r/GUI/CAD/DesignPanel.cpp b/src/slic3r/GUI/CAD/DesignPanel.cpp index 046bf0486d..5ff0f4c8a8 100644 --- a/src/slic3r/GUI/CAD/DesignPanel.cpp +++ b/src/slic3r/GUI/CAD/DesignPanel.cpp @@ -11185,10 +11185,12 @@ void DesignPanel::refresh_preview() // Confirm so the user sees the gate before clicking; the red status says why. m_candidate_ok = ok; update_confirm_button(); - // Fillet/Chamfer/Draft: once the target edge/face yields a valid result, show ONLY the + // Fillet/Chamfer/Draft/Hole: once the target edge/face yields a valid result, show ONLY the // preview (hide the base bodies) so the user sees the finished shape, not the old solid - // doubled with the ghost. Before a valid pick the body stays visible so it can be picked. - m_viewport->set_body_hidden((m_active == Tool::Dressup || m_active == Tool::Draft) && ok); + // doubled with the ghost. A hole's cut lies inside the old solid, so without this the body + // would hide it entirely. Before a valid pick the body stays visible so it can be picked. + m_viewport->set_body_hidden((m_active == Tool::Dressup || m_active == Tool::Draft || + m_active == Tool::Hole) && ok); m_status->Refresh(); // Refresh the in-canvas Extrude depth arrow (self-gates: only while the Extrude card is open).