Fix overhang preview ignoring support threshold fallbacks when angle set to 0 (#12650)
* Fix overhang preview not using fallbacks when angle is 0
The overhang visualization in Preview ("show overhangs based on support settings")
used the raw `support_threshold_angle` value from the configuration.
When `support_threshold_angle` was set to 0, Orca internally falls back to:
- 30° for tree supports
- an angle derived from `support_threshold_overlap` for normal supports
However, the preview logic ignored these fallbacks and used the raw value (0°),
leading to incorrect overhang highlighting that did not match the actual
support generation behavior.
This patch computes the effective overhang threshold used for preview:
• If `support_threshold_angle > 0`, use it directly
• If `support_threshold_angle == 0` and tree supports are used, fall back to 30°
• If `support_threshold_angle == 0` and normal supports are used, derive the
equivalent angle from `support_threshold_overlap`, `layer_height`, and the
external perimeter width.
The function now returns `normal_z` directly so the preview uses the same
effective slope threshold as the support generator.
As a result, the overhang highlight in Preview now correctly matches the
supports that will actually be generated.
* Apply Copilot suggestions
This commit is contained in:
@@ -978,12 +978,51 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
|
||||
return list;
|
||||
}
|
||||
|
||||
int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_support) const
|
||||
// ORCA: Compute slope.normal_z for 3D overhang highlight directly from support settings.
|
||||
// If support_threshold_angle is 0, use tree fallback angle (30 deg) for tree supports,
|
||||
// and derive an equivalent angle from threshold overlap for normal supports.
|
||||
float GLVolumeCollection::get_selection_support_normal_z() const
|
||||
{
|
||||
const DynamicPrintConfig& glb_cfg = GUI::wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
enable_support = glb_cfg.opt_bool("enable_support");
|
||||
int support_threshold_angle = glb_cfg.opt_int("support_threshold_angle");
|
||||
return support_threshold_angle ;
|
||||
const DynamicPrintConfig& glb_cfg = GUI::wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
const auto& full_cfg = GUI::wxGetApp().preset_bundle->full_config();
|
||||
const auto support_type = glb_cfg.opt_enum<SupportType>("support_type");
|
||||
const int support_threshold_angle = glb_cfg.opt_int("support_threshold_angle");
|
||||
double angle_rad;
|
||||
|
||||
if (support_threshold_angle > 0) {
|
||||
// Match support generation: explicit threshold angles are treated as inclusive.
|
||||
const int effective_support_threshold_angle = std::min(support_threshold_angle + 1, 89);
|
||||
angle_rad = Geometry::deg2rad(static_cast<double>(effective_support_threshold_angle));
|
||||
} else if (is_tree(support_type)) {
|
||||
angle_rad = Geometry::deg2rad(30.0); // fallback value for tree supports
|
||||
} else { // For normal supports, if the angle is set to 0, calculate normal_z from overlap.
|
||||
const double layer_height = full_cfg.opt_float("layer_height");
|
||||
const auto* nozzle_diameter_opt = full_cfg.option<ConfigOptionFloats>("nozzle_diameter");
|
||||
const int wall_filament = full_cfg.opt_int("wall_filament");
|
||||
const size_t nozzle_count = nozzle_diameter_opt->values.size();
|
||||
const size_t wall_extruder_idx = (wall_filament > 0 && wall_filament <= static_cast<int>(nozzle_count))
|
||||
? static_cast<size_t>(wall_filament - 1)
|
||||
: 0; // Invalid extruder index falls back to extruder 1.
|
||||
|
||||
// Use wall extruder's nozzle diameter for better estimation of external perimeter width,
|
||||
// which is more relevant to overhang printing than the default nozzle diameter.
|
||||
const double nozzle_diameter = nozzle_diameter_opt->values[wall_extruder_idx];
|
||||
|
||||
double external_perimeter_width = full_cfg.get_abs_value("outer_wall_line_width", nozzle_diameter);
|
||||
if (external_perimeter_width <= 0.0) {
|
||||
external_perimeter_width = full_cfg.get_abs_value("line_width", nozzle_diameter);
|
||||
|
||||
if (external_perimeter_width <= 0.0)
|
||||
external_perimeter_width = nozzle_diameter;
|
||||
}
|
||||
|
||||
const double overlap_width = full_cfg.get_abs_value("support_threshold_overlap", external_perimeter_width);
|
||||
const double lower_layer_offset = std::max(0.0, external_perimeter_width - overlap_width);
|
||||
|
||||
angle_rad = lower_layer_offset <= EPSILON ? Geometry::deg2rad(89.0) : std::atan(layer_height / lower_layer_offset);
|
||||
}
|
||||
|
||||
return static_cast<float>(-std::cos(std::clamp(angle_rad, 0.0, Geometry::deg2rad(89.0))));
|
||||
}
|
||||
|
||||
//BBS: add outline drawing logic
|
||||
@@ -1019,6 +1058,8 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
|
||||
if (disable_cullface)
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
|
||||
const float support_normal_z = get_selection_support_normal_z();
|
||||
|
||||
for (GLVolumeWithIdAndZ& volume : to_render) {
|
||||
#if ENABLE_MODIFIERS_ALWAYS_TRANSPARENT
|
||||
if (type == ERenderType::Transparent) {
|
||||
@@ -1075,16 +1116,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
|
||||
//use -1 ad a invalid type
|
||||
shader->set_uniform("print_volume.type", -1);
|
||||
}
|
||||
|
||||
bool enable_support;
|
||||
int support_threshold_angle = get_selection_support_threshold_angle(enable_support);
|
||||
|
||||
float normal_z = -::cos(Geometry::deg2rad((float) support_threshold_angle));
|
||||
|
||||
shader->set_uniform("volume_world_matrix", volume.first->world_matrix());
|
||||
shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower);
|
||||
shader->set_uniform("slope.volume_world_normal_matrix", static_cast<Matrix3f>(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast<float>()));
|
||||
shader->set_uniform("slope.normal_z", normal_z);
|
||||
shader->set_uniform("slope.normal_z", support_normal_z);
|
||||
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id();
|
||||
|
||||
@@ -488,7 +488,7 @@ public:
|
||||
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
|
||||
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
|
||||
|
||||
int get_selection_support_threshold_angle(bool&) const;
|
||||
float get_selection_support_normal_z() const;
|
||||
// Render the volumes by OpenGL.
|
||||
//BBS: add outline drawing logic
|
||||
void render(ERenderType type,
|
||||
|
||||
Reference in New Issue
Block a user