ENH:Add sinking render in the paint gizmo

jira: STUDIO-11649
Change-Id: I5edadc0107dd6ab8fc4e28d478135796463ee64b
This commit is contained in:
zhou.xu 2025-05-12 16:18:09 +08:00 committed by lane.wei
parent fa642e8d66
commit 255ada5ff2
11 changed files with 155 additions and 13 deletions

View File

@ -1624,6 +1624,36 @@ GLVolumeWithIdAndZList volumes_to_render(const GLVolumePtrs& volumes, GLVolumeCo
return list;
}
GLVolumeWithIdAndZList volumes_to_render_for_sinking(const GLVolumePtrs & volumes,
GLVolumeCollection::ERenderType type,
const Transform3d & view_matrix)
{
GLVolumeWithIdAndZList list;
list.reserve(volumes.size());
for (unsigned int i = 0; i < (unsigned int) volumes.size(); ++i) {
GLVolume *volume = volumes[i];
bool is_transparent = (volume->render_color[3] < 1.0f);
auto tempGlwipeTowerVolume = dynamic_cast<GLWipeTowerVolume *>(volume);
if (tempGlwipeTowerVolume) {
continue;
}
if (!volume->selected)
continue;
list.emplace_back(std::make_pair(volume, std::make_pair(i, 0.0)));
}
if (type == GLVolumeCollection::ERenderType::Transparent && list.size() > 1) {
for (GLVolumeWithIdAndZ &volume : list) { volume.second.second = volume.first->bounding_box().transformed(view_matrix * volume.first->world_matrix()).max(2); }
std::sort(list.begin(), list.end(), [](const GLVolumeWithIdAndZ &v1, const GLVolumeWithIdAndZ &v2) -> bool { return v1.second.second < v2.second.second; });
} else if (type == GLVolumeCollection::ERenderType::Opaque && list.size() > 1) {
std::sort(list.begin(), list.end(), [](const GLVolumeWithIdAndZ &v1, const GLVolumeWithIdAndZ &v2) -> bool { return v1.first->selected && !v2.first->selected; });
}
return list;
}
int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_support) const
{
const DynamicPrintConfig& glb_cfg = GUI::wxGetApp().preset_bundle->prints.get_edited_preset().config;
@ -1805,6 +1835,55 @@ void GLVolumeCollection::render(GUI::ERenderPipelineStage render_pip
glsafe(::glDisable(GL_BLEND));
}
void GLVolumeCollection::only_render_sinking(GUI::ERenderPipelineStage render_pipeline_stage,
ERenderType type,
bool disable_cullface,
const GUI::Camera & camera,
const std::vector<std::array<float, 4>> &colors,
Model & model,
std::function<bool(const GLVolume &)> filter_func,
bool with_outline,
const std::array<float, 4> & body_color,
bool partly_inside_enable,
std::vector<double> * printable_heights)
{
auto view_matrix = camera.get_view_matrix();
auto projection_matrix = camera.get_projection_matrix();
GLVolumeWithIdAndZList to_render = volumes_to_render_for_sinking(volumes, type, view_matrix);
if (to_render.empty())
return;
const auto shader = GUI::wxGetApp().get_current_shader();
if (shader == nullptr)
return;
if (type == ERenderType::Transparent) {
glsafe(::glEnable(GL_BLEND));
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
}
glsafe(::glDisable(GL_CULL_FACE));
if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) {
if (m_show_sinking_contours) {
for (GLVolumeWithIdAndZ &volume : to_render) {
if (volume.first->is_sinking() && !volume.first->is_below_printbed()) {
GUI::wxGetApp().unbind_shader();
glsafe(::glDepthFunc(GL_ALWAYS));
volume.first->render_sinking_contours(camera, model);
glsafe(::glDepthFunc(GL_LESS));
GUI::wxGetApp().bind_shader(shader);
}
}
}
}
if (disable_cullface)
glsafe(::glEnable(GL_CULL_FACE));
if (type == ERenderType::Transparent)
glsafe(::glDisable(GL_BLEND));
}
bool GLVolumeCollection::check_outside_state(const BuildVolume &build_volume, ModelInstanceEPrintVolumeState *out_state, ObjectFilamentResults *object_results, Model &model) const
{
if (GUI::wxGetApp().plater() == NULL)

View File

@ -747,7 +747,17 @@ public:
const std::array<float, 4> & body_color = {1.0f, 1.0f, 1.0f, 1.0f},
bool partly_inside_enable = true,
std::vector<double> * printable_heights = nullptr);
void only_render_sinking(GUI::ERenderPipelineStage render_pipeline_stage,
ERenderType type,
bool disable_cullface,
const GUI::Camera & camera,
const std::vector<std::array<float, 4>> &colors,
Model & model,
std::function<bool(const GLVolume &)> filter_func = std::function<bool(const GLVolume &)>(),
bool with_outline = true,
const std::array<float, 4> & body_color = {1.0f, 1.0f, 1.0f, 1.0f},
bool partly_inside_enable = true,
std::vector<double> * printable_heights = nullptr);
// Finalize the initialization of the geometry & indices,
// upload the geometry and indices to OpenGL VBO objects
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.

View File

@ -1724,6 +1724,15 @@ ModelInstanceEPrintVolumeState GLCanvas3D::check_volumes_outside_state(ObjectFil
return state;
}
bool GLCanvas3D::is_volumes_selected_and_sinking() const {
for (GLVolume *volume : m_volumes.volumes) {
if (volume->selected && volume->is_sinking() && !volume->is_below_printbed()) {
return true;
}
}
return false;
}
void GLCanvas3D::toggle_selected_volume_visibility(bool selected_visible)
{
m_render_sla_auxiliaries = !selected_visible;
@ -7570,6 +7579,18 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
gm.render_painter_assemble_view();
wxGetApp().bind_shader(shader);
}
if (m_canvas_type == CanvasView3D && m_gizmos.is_paint_gizmo()) {
m_volumes.only_render_sinking(
render_pipeline_stage, type, false, camera, colors, *m_model,
[this, canvas_type](const GLVolume &volume) {
if (canvas_type == ECanvasType::CanvasAssembleView) {
return !volume.is_modifier;
} else {
return true;
}
},
with_outline, body_color, partly_inside_enable, printable_height_option ? &printable_height_option->values : nullptr);
}
break;
}
}

View File

@ -807,6 +807,7 @@ public:
void reset_volumes(bool set_notice = true);
ModelInstanceEPrintVolumeState check_volumes_outside_state(ObjectFilamentResults* object_results = nullptr) const;
bool is_all_plates_selected() { return m_sel_plate_toolbar.m_all_plates_stats_item && m_sel_plate_toolbar.m_all_plates_stats_item->selected; }
bool is_volumes_selected_and_sinking() const;
const float get_scale() const;
//BBS

View File

@ -283,7 +283,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
const float sliders_width = m_imgui->scaled(7.0f);
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_left_width + sliders_width - space_size;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
float drag_pos_times = 0.7;
ImGui::AlignTextToFramePadding();
@ -462,6 +462,11 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
}
ImGui::Separator();
if (m_parent.is_volumes_selected_and_sinking()) {
m_imgui->warning_text_wrapped(_L("Warning") + ":" + _L("Painting below the build plate is not allowed.") +
_L("The white outline indicates the position of the build plate at Z = 0."),
window_width+ m_imgui->scaled(3));
}
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
show_tooltip_information(caption_max, x, get_cur_y);

View File

@ -479,7 +479,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
window_width = std::max(window_width, total_text_max);
window_width = std::max(window_width, buttons_width);
window_width = std::max(window_width, max_filament_items_per_line * filament_item_width + +m_imgui->scaled(0.5f));
window_width = std::max(window_width, max_filament_items_per_line * filament_item_width + m_imgui->scaled(0.5f));
const float sliders_width = m_imgui->scaled(7.0f);
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_width - space_size;
@ -840,7 +840,11 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_imgui->disabled_end();
ImGui::Separator();
}
if (m_parent.is_volumes_selected_and_sinking()) {
m_imgui->warning_text_wrapped(_L("Warning") + ":" + _L("Painting below the build plate is not allowed.") +
_L("The white outline indicates the position of the build plate at Z = 0."),
window_width + m_imgui->scaled(1));
}
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
show_tooltip_information(caption_max, x, get_cur_y);

View File

@ -65,7 +65,7 @@ GLGizmoPainterBase::ClippingPlaneDataWrapper GLGizmoPainterBase::get_clipping_pl
// z_range is calculated in the same way as in GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type)
if (m_c->get_canvas()->get_use_clipping_planes()) {
const std::array<ClippingPlane, 2> &clps = m_c->get_canvas()->get_clipping_planes();
clp_data_out.z_range = {float(-clps[0].get_data()[3]), float(clps[1].get_data()[3])};
clp_data_out.z_range = {-FLT_MAX, float(clps[1].get_data()[3])};
}
return clp_data_out;

View File

@ -230,10 +230,10 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
const float sliders_left_width = std::max(cursor_size_slider_left, clipping_slider_left);
const float slider_icon_width = m_imgui->get_slider_icon_size().x;
const float minimal_slider_width = m_imgui->scaled(4.f);
const float sliders_width = m_imgui->scaled(7.0f);
const float drag_left_width = ImGui::GetStyle().WindowPadding.x + sliders_left_width + sliders_width - space_size;
float window_width = minimal_slider_width + sliders_left_width + slider_icon_width;
const float max_tooltip_width = ImGui::GetFontSize() * 20.0f;
float textbox_width = 1.5 * slider_icon_width;
@ -353,6 +353,11 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
}
m_imgui->disabled_end();
ImGui::Separator();
if (m_parent.is_volumes_selected_and_sinking()) {
m_imgui->warning_text_wrapped(_L("Warning") + ":" + _L("Painting below the build plate is not allowed.") +
_L("The white outline indicates the position of the build plate at Z = 0."),
window_width + m_imgui->scaled(3));
}
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(6.0f, 10.0f));
float get_cur_y = ImGui::GetContentRegionMax().y + ImGui::GetFrameHeight() + y;
show_tooltip_information(caption_max, x, get_cur_y);

View File

@ -154,8 +154,13 @@ void InstancesHider::on_update()
double z_min;
if (canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView)
z_min = std::numeric_limits<double>::max();
else
else {
if (canvas->get_gizmos_manager().is_paint_gizmo()) {
z_min = -FLT_MAX;
} else {
z_min = -SINKING_Z_THRESHOLD;
}
}
if (mo && active_inst != -1) {
canvas->toggle_model_objects_visibility(false);
@ -420,7 +425,8 @@ void CommonGizmosDataObjects::ObjectClipper::render_cut(const std::vector<size_t
//consider normal view or assemble view
const ModelObject * mo = sel_info->model_object();
Geometry::Transformation inst_trafo;
bool is_assem_cnv = get_pool()->get_canvas()->get_canvas_type() == GLCanvas3D::CanvasAssembleView;
GLCanvas3D * canvas = get_pool()->get_canvas();
bool is_assem_cnv = canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView;
inst_trafo = is_assem_cnv ? mo->instances[sel_info->get_active_instance()]->get_assemble_transformation() :
mo->instances[sel_info->get_active_instance()]->get_transformation();
auto offset_to_assembly = mo->instances[0]->get_offset_to_assembly();
@ -428,6 +434,14 @@ void CommonGizmosDataObjects::ObjectClipper::render_cut(const std::vector<size_t
auto debug = sel_info->get_sla_shift();
std::vector<size_t> ignore_idxs_local = ignore_idxs ? *ignore_idxs : std::vector<size_t>();
double z_min;
if (canvas->get_gizmos_manager().is_paint_gizmo()) {
z_min = -FLT_MAX;
} else {
z_min = -SINKING_Z_THRESHOLD;
}
for (auto &clipper : m_clippers) {
auto vol_trafo = clipper.second;
Geometry::Transformation trafo = inst_trafo * vol_trafo;
@ -438,7 +452,7 @@ void CommonGizmosDataObjects::ObjectClipper::render_cut(const std::vector<size_t
}
clipper.first->set_plane(*m_clp);
clipper.first->set_transformation(trafo);
clipper.first->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
clipper.first->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), z_min));
clipper.first->render_cut(OpenGLManager::get_cut_plane_color(), &ignore_idxs_local);
clipper.first->render_contour({1.f, 1.f, 1.f, 1.f}, &ignore_idxs_local);

View File

@ -727,7 +727,7 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
return false;
}
bool GLGizmosManager::is_paint_gizmo()
bool GLGizmosManager::is_paint_gizmo() const
{
return m_current == EType::FdmSupports ||
m_current == EType::MmuSegmentation ||
@ -1912,6 +1912,9 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const
bool GLGizmosManager::is_hiding_instances() const
{
if (is_paint_gizmo()) {
return false;
}
return (m_common_gizmos_data
&& m_common_gizmos_data->instances_hider()
&& m_common_gizmos_data->instances_hider()->is_valid());

View File

@ -291,7 +291,7 @@ public:
void check_object_located_outside_plate(bool change_plate =true);
bool get_object_located_outside_plate() { return m_object_located_outside_plate; }
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false);
bool is_paint_gizmo();
bool is_paint_gizmo()const;
bool is_allow_select_all();
ClippingPlane get_clipping_plane() const;
ClippingPlane get_assemble_view_clipping_plane() const;