Offer the Sliced Objects as a Solid Model While Dragging

The reductions built for dragging still draw toolpaths, and a plate of large
objects has many even one layer in four. The objects themselves are cheaper:
a mesh costs its triangles once, and the preview already loads the objects
as shells for its translucent ghost. So the Simplification choice gains a
fourth entry, Solid model, that draws the shells opaque in their filament
colours instead of the toolpaths while the user drags.

The visible layer range still holds. The shells are cut at the range's top
and bottom through the shader's z range, and the toolpath set bound while
dragging keeps just those two layers, drawn afterwards so that they cap the
cut with what was really printed there. The prime tower is added to the
shells from its sliced mesh, positioned as the print placed it; it keeps its
opaque colour and so stays out of the translucent ghost. Supports have no
mesh and are not shown in this mode, which the preference text says.

Verified on the tall fixture and on a nine-cube plate: mid-drag the objects
and the tower are solids capped by their top layer, cut to a shortened layer
range, and with the preference off the preview is pixel identical to before.
This commit is contained in:
Hanif Koh
2026-09-11 20:31:51 +08:00
parent c2eea1cada
commit 36cd425bb3
7 changed files with 85 additions and 7 deletions

View File

@@ -208,7 +208,7 @@ void AppConfig::set_defaults()
{ {
const std::string mode = get("preview_reduced_detail_mode"); const std::string mode = get("preview_reduced_detail_mode");
if (mode != "layers" && mode != "no_infill" && mode != "shell") if (mode != "layers" && mode != "no_infill" && mode != "shell" && mode != "solid")
set("preview_reduced_detail_mode", "no_infill"); set("preview_reduced_detail_mode", "no_infill");
} }

View File

@@ -172,6 +172,9 @@ enum class EReducedDetailMode : uint8_t
NoInternalInfill, NoInternalInfill,
// only the segments on the visible surface of the print are kept // only the segments on the visible surface of the print are kept
ShellOnly, ShellOnly,
// only the bottom and top of the visible layer range are kept, for a caller that draws the
// print itself some other way and needs just the two faces the range cuts open
EndLayersOnly,
COUNT COUNT
}; };

View File

@@ -1779,6 +1779,11 @@ void ViewerImpl::update_enabled_entities()
} }
if (!build_reduced) if (!build_reduced)
continue; continue;
if (m_settings.reduced_detail_mode == EReducedDetailMode::EndLayersOnly) {
if (whole_layer)
(v.is_option() ? enabled_options_reduced : enabled_segments_reduced).push_back(static_cast<uint32_t>(i));
continue;
}
if (!whole_layer && (v.layer_id % layer_stride) != 0) { if (!whole_layer && (v.layer_id % layer_stride) != 0) {
// the surfaces of a skipped layer that either side can see stay, so that a step does not vanish // the surfaces of a skipped layer that either side can see stay, so that a step does not vanish
if (shell_reduced && (visible_from_above || visible_from_below)) if (shell_reduced && (visible_from_above || visible_from_below))

View File

@@ -565,7 +565,7 @@ private:
bool use_rest_set() const { return !use_reduced_set() && build_rest_set(); } bool use_rest_set() const { return !use_reduced_set() && build_rest_set(); }
// how many layers each drawn segment of the bound set stands in for // how many layers each drawn segment of the bound set stands in for
float active_height_scale() const { float active_height_scale() const {
if (use_reduced_set()) if (use_reduced_set() && m_settings.reduced_detail_mode != EReducedDetailMode::EndLayersOnly)
return static_cast<float>(std::max<uint32_t>(1, m_settings.reduced_detail_layer_stride)); return static_cast<float>(std::max<uint32_t>(1, m_settings.reduced_detail_layer_stride));
if (use_rest_set() && m_settings.rest_detail_mode == EReducedDetailMode::ShellOnly) if (use_rest_set() && m_settings.rest_detail_mode == EReducedDetailMode::ShellOnly)
return static_cast<float>(std::max<uint32_t>(1, m_settings.rest_layer_stride)); return static_cast<float>(std::max<uint32_t>(1, m_settings.rest_layer_stride));

View File

@@ -1175,6 +1175,7 @@ void GCodeViewer::load_as_gcode(const GCodeProcessorResult& gcode_result, const
// ORCA: simplify the preview while the user is dragging // ORCA: simplify the preview while the user is dragging
m_reduced_detail_while_dragging = get_app_config()->get_bool("preview_reduced_detail_while_dragging"); m_reduced_detail_while_dragging = get_app_config()->get_bool("preview_reduced_detail_while_dragging");
m_reduced_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_reduced_detail_mode")); m_reduced_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_reduced_detail_mode"));
m_solid_model_while_dragging = m_reduced_detail_mode == libvgcode::EReducedDetailMode::EndLayersOnly;
m_reduced_detail_layer_stride = static_cast<unsigned int>(std::max(1, std::stoi(get_app_config()->get("preview_reduced_detail_layer_stride")))); m_reduced_detail_layer_stride = static_cast<unsigned int>(std::max(1, std::stoi(get_app_config()->get("preview_reduced_detail_layer_stride"))));
m_rest_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_rest_detail_mode")); m_rest_detail_mode = reduced_detail_mode_from_string(get_app_config()->get("preview_rest_detail_mode"));
apply_reduced_detail_settings(); apply_reduced_detail_settings();
@@ -1653,8 +1654,15 @@ void GCodeViewer::reset()
void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin, bool draw_scene) void GCodeViewer::render(int canvas_width, int canvas_height, int right_margin, bool draw_scene)
{ {
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
if (draw_scene) // while dragging in the solid model mode the objects stand in for their toolpaths, cut to the
render_shells(canvas_width, canvas_height); // visible layer range; the toolpath set then holds only the range's bottom and top layers
const bool solid_model = m_interacting && m_solid_model_while_dragging && m_viewer.is_reduced_detail();
if (draw_scene) {
if (solid_model)
render_solid_model(canvas_width, canvas_height);
else
render_shells(canvas_width, canvas_height);
}
if (m_viewer.get_extrusion_roles_count() == 0) if (m_viewer.get_extrusion_roles_count() == 0)
return; return;
@@ -2007,6 +2015,7 @@ void GCodeViewer::set_reduced_detail_while_dragging(bool value)
void GCodeViewer::set_reduced_detail_mode(const std::string& mode) void GCodeViewer::set_reduced_detail_mode(const std::string& mode)
{ {
m_reduced_detail_mode = reduced_detail_mode_from_string(mode); m_reduced_detail_mode = reduced_detail_mode_from_string(mode);
m_solid_model_while_dragging = m_reduced_detail_mode == libvgcode::EReducedDetailMode::EndLayersOnly;
apply_reduced_detail_settings(); apply_reduced_detail_settings();
} }
@@ -2020,6 +2029,8 @@ libvgcode::EReducedDetailMode GCodeViewer::reduced_detail_mode_from_string(const
{ {
if (mode == "full") if (mode == "full")
return libvgcode::EReducedDetailMode::Off; return libvgcode::EReducedDetailMode::Off;
if (mode == "solid")
return libvgcode::EReducedDetailMode::EndLayersOnly;
if (mode == "layers") if (mode == "layers")
return libvgcode::EReducedDetailMode::LayersOnly; return libvgcode::EReducedDetailMode::LayersOnly;
if (mode == "shell") if (mode == "shell")
@@ -2415,6 +2426,19 @@ void GCodeViewer::load_shells(const Print& print, bool initialized, bool force_p
object_count++; object_count++;
} }
// the prime tower as it was sliced, so that the solid model shows what the print shows; it
// keeps its opaque colour and so never appears among the translucent shells
if (print.is_step_done(psWipeTower) && print.wipe_tower_data().wipe_tower_mesh_data) {
const PrintConfig& config = print.config();
const int plate_idx = print.get_plate_index();
const Vec3d plate_origin = print.get_plate_origin();
const float x = static_cast<float>(config.wipe_tower_x.get_at(plate_idx) + plate_origin.x());
const float y = static_cast<float>(config.wipe_tower_y.get_at(plate_idx) + plate_origin.y());
m_shells.volumes.load_real_wipe_tower_preview(1000, x, y, print.wipe_tower_data().wipe_tower_mesh_data->real_wipe_tower_mesh,
print.wipe_tower_data().wipe_tower_mesh_data->real_brim_mesh, true,
static_cast<float>(config.wipe_tower_rotation_angle), false, initialized);
}
// Orca: disable wipe tower shell // Orca: disable wipe tower shell
// if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) { // if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptFFF) {
// // BBS: adds wipe tower's volume // // BBS: adds wipe tower's volume
@@ -2665,6 +2689,47 @@ void GCodeViewer::render_shells(int canvas_width, int canvas_height)
glsafe(::glDepthMask(GL_TRUE)); glsafe(::glDepthMask(GL_TRUE));
} }
// The sliced objects and the prime tower drawn opaque, in their filament colours, cut to the
// visible layer range by the shader's z range. The toolpaths of the range's bottom and top layers
// are drawn afterwards and cap the cut.
void GCodeViewer::render_solid_model(int canvas_width, int canvas_height)
{
if (m_shells.volumes.empty())
return;
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
if (shader == nullptr)
return;
const libvgcode::Interval& layers = m_viewer.get_layers_view_range();
const float z_top = m_viewer.get_layer_z(layers[1]) - m_z_offset + 0.001f;
const float z_bottom = (layers[0] > 0) ? m_viewer.get_layer_z(layers[0] - 1) - m_z_offset - 0.001f : -FLT_MAX;
std::vector<float> alphas;
alphas.reserve(m_shells.volumes.volumes.size());
for (GLVolume* volume : m_shells.volumes.volumes) {
alphas.push_back(volume->color.a());
volume->color.a(1.0f);
volume->set_render_color();
}
m_shells.volumes.set_z_range(z_bottom, z_top);
shader->start_using();
shader->set_uniform("emission_factor", 0.1f);
const Camera& camera = wxGetApp().plater()->get_camera();
shader->set_uniform("z_far", camera.get_far_z());
shader->set_uniform("z_near", camera.get_near_z());
m_shells.volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix(), {canvas_width, canvas_height});
shader->set_uniform("emission_factor", 0.0f);
shader->stop_using();
m_shells.volumes.set_z_range(-FLT_MAX, FLT_MAX);
size_t k = 0;
for (GLVolume* volume : m_shells.volumes.volumes) {
volume->color.a(alphas[k++]);
volume->set_render_color();
}
}
//BBS //BBS
void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessorResult*>& gcode_result_list, bool show /*= true*/) const { void GCodeViewer::render_all_plates_stats(const std::vector<const GCodeProcessorResult*>& gcode_result_list, bool show /*= true*/) const {
if (!show) if (!show)

View File

@@ -235,6 +235,9 @@ private:
libvgcode::EReducedDetailMode m_reduced_detail_mode{ libvgcode::EReducedDetailMode::NoInternalInfill }; libvgcode::EReducedDetailMode m_reduced_detail_mode{ libvgcode::EReducedDetailMode::NoInternalInfill };
unsigned int m_reduced_detail_layer_stride{ 4 }; unsigned int m_reduced_detail_layer_stride{ 4 };
libvgcode::EReducedDetailMode m_rest_detail_mode{ libvgcode::EReducedDetailMode::Off }; libvgcode::EReducedDetailMode m_rest_detail_mode{ libvgcode::EReducedDetailMode::Off };
// ORCA: draw the sliced objects as solid shapes instead of toolpaths while dragging
bool m_solid_model_while_dragging{ false };
void render_solid_model(int canvas_width, int canvas_height);
void apply_reduced_detail_settings(); void apply_reduced_detail_settings();
// whether the user is dragging or a wheel burst is settling, as told by set_interacting() // whether the user is dragging or a wheel burst is settling, as told by set_interacting()
bool m_interacting{ false }; bool m_interacting{ false };

View File

@@ -1977,10 +1977,12 @@ void PreferencesDialog::create_items()
"Skip layers only: every toolpath of the drawn layers is kept.\n" "Skip layers only: every toolpath of the drawn layers is kept.\n"
"Skip internal infill: sparse and solid infill hidden inside the walls is left out.\n" "Skip internal infill: sparse and solid infill hidden inside the walls is left out.\n"
"Shell only: only the toolpaths on the visible surface of the print are drawn, including the outside of the prime tower. " "Shell only: only the toolpaths on the visible surface of the print are drawn, including the outside of the prime tower. "
"Removes the most, and holes narrower than 5 mm are treated as solid."), "Removes the most of the toolpath modes, and holes narrower than 5 mm are treated as solid.\n"
"Solid model: the sliced objects and the prime tower are drawn as solid shapes in their filament colours instead of toolpaths, "
"cut to the visible layer range with the range's bottom and top layers drawn on top. Cheapest of all; supports are not shown, and the layer setting below does not apply."),
"preview_reduced_detail_mode", "preview_reduced_detail_mode",
{_L("Skip layers only"), _L("Skip internal infill"), _L("Shell only")}, {_L("Skip layers only"), _L("Skip internal infill"), _L("Shell only"), _L("Solid model")},
{"layers", "no_infill", "shell"}, {"layers", "no_infill", "shell", "solid"},
// ORCA: apply the new mode immediately to the currently loaded preview // ORCA: apply the new mode immediately to the currently loaded preview
[](std::string value) { [](std::string value) {
if (Plater* plater = wxGetApp().plater()) { if (Plater* plater = wxGetApp().plater()) {