NEW:add "select triangle" mode in "lay on face" gizmo

jira: STUDIO-10200
Change-Id: I7ce594a527ef220ef9dec56d370b9de2616ad92a
(cherry picked from commit ab89fa6ea1bb3345182b41d64acde27ec3e3c24a)
This commit is contained in:
zhou.xu 2025-02-08 10:03:32 +08:00 committed by lane.wei
parent 6781a874b5
commit fcfe5648ca
6 changed files with 193 additions and 47 deletions

View File

@ -11376,6 +11376,19 @@ GLVolume *get_selected_gl_volume(const GLCanvas3D &canvas)
return nullptr;
}
ModelObject *get_selected_model_object(GLCanvas3D &canvas) {
auto v = get_selected_gl_volume(canvas);
if (v) {
auto mo = get_model_object(*v, canvas.get_model()->objects);
return mo;
}
else {
int out_object_idx;
return canvas.get_selection().get_selected_single_object(out_object_idx);
}
return nullptr;
}
ModelObject *get_model_object(const GLVolume &gl_volume, const Model &model) { return get_model_object(gl_volume, model.objects); }
ModelObject *get_model_object(const GLVolume &gl_volume, const ModelObjectPtrs &objects)

View File

@ -1351,6 +1351,7 @@ ModelVolume *get_model_volume(const GLVolume &v, const ModelObject &object);
GLVolume *get_first_hovered_gl_volume(const GLCanvas3D &canvas);
GLVolume *get_selected_gl_volume(const GLCanvas3D &canvas);
ModelObject *get_selected_model_object(GLCanvas3D &canvas);
ModelObject *get_model_object(const GLVolume &gl_volume, const Model &model);
ModelObject *get_model_object(const GLVolume &gl_volume, const ModelObjectPtrs &objects);

View File

@ -33,17 +33,17 @@ bool GLGizmoFlatten::on_init()
void GLGizmoFlatten::on_set_state()
{
m_hit_facet = -1;
m_last_hit_facet = -1;
}
CommonGizmosDataID GLGizmoFlatten::on_get_requirements() const
{
return CommonGizmosDataID::SelectionInfo;
return CommonGizmosDataID(int(CommonGizmosDataID::SelectionInfo) | int(CommonGizmosDataID::InstancesHider) | int(CommonGizmosDataID::Raycaster) |
int(CommonGizmosDataID::ObjectClipper));
}
void GLGizmoFlatten::on_render_input_window(float x, float y, float bottom_limit) {
if (!m_show_warning) {
return;
}
double screen_scale = wxDisplay(wxGetApp().plater()).GetScaleFactor();
static float last_y = 0.0f;
static float last_h = 0.0f;
@ -59,6 +59,31 @@ void GLGizmoFlatten::on_render_input_window(float x, float y, float bottom_limit
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
GizmoImguiBegin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
float space_size = m_imgui->get_style_scaling() * 8;
float mode_cap = m_imgui->calc_text_size(_L("Mode") + ":").x;
float caption_size = mode_cap + space_size + ImGui::GetStyle().WindowPadding.x;
ImGui::AlignTextToFramePadding();
m_imgui->text(_L("Mode") + ":");
ImGui::SameLine();//ImGui::SameLine(caption_size);
bool faltten_type_defult = m_faltten_type == FlattenType::Default;
auto first_mode_str = _L("Convex hull");
if (m_imgui->bbl_checkbox(first_mode_str, faltten_type_defult)) {
if (faltten_type_defult) {
m_faltten_type = FlattenType::Default;
} else {
m_faltten_type = FlattenType::Triangle;
}
}
ImGui::SameLine();//ImGui::SameLine(new_label_width);
bool faltten_type_tri = m_faltten_type == FlattenType::Triangle;
if (m_imgui->bbl_checkbox(_L("Triangular facet"), faltten_type_tri)) {
if (!faltten_type_tri) {
m_faltten_type = FlattenType::Default;
} else {
m_faltten_type = FlattenType::Triangle;
}
}
if (m_show_warning) {
m_imgui->warning_text(_L("Warning: All triangle areas are too small,The current function is not working."));
}
@ -87,11 +112,59 @@ void GLGizmoFlatten::on_start_dragging()
{
if (m_hover_id != -1) {
assert(m_planes_valid);
m_normal = m_planes[m_hover_id].normal;
if (m_faltten_type == FlattenType::Default) {
m_normal = m_planes[m_hover_id].normal;
}
else {
m_normal = m_hit_object_normal.cast<double>();
}
m_starting_center = m_parent.get_selection().get_bounding_box().center();
}
}
bool GLGizmoFlatten::update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector<Transform3d> &trafo_matrices, int &cur_facet)
{
/*if (m_rr.mouse_position == mouse_position) {
return false;
}*/
Vec3f normal = Vec3f::Zero();
Vec3f hit = Vec3f::Zero();
Vec3f closest_hit = Vec3f::Zero();
Vec3f closest_nromal = Vec3f::Zero();
double closest_hit_squared_distance = std::numeric_limits<double>::max();
int closest_hit_mesh_id = -1;
size_t facet = 0;
// Cast a ray on all meshes, pick the closest hit and save it for the respective mesh
for (int mesh_id = 0; mesh_id < int(trafo_matrices.size()); ++mesh_id) {
if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(mouse_position, trafo_matrices[mesh_id], camera, hit, normal, m_c->object_clipper()->get_clipping_plane(),
&facet)) {
// In case this hit is clipped, skip it.
//if (is_mesh_point_clipped(hit.cast<double>(), trafo_matrices[mesh_id])) continue;
double hit_squared_distance = (camera.get_position() - trafo_matrices[mesh_id] * hit.cast<double>()).squaredNorm();
if (hit_squared_distance < closest_hit_squared_distance) {
closest_hit_squared_distance = hit_squared_distance;
closest_hit_mesh_id = mesh_id;
closest_hit = hit;
closest_nromal = normal;
if (m_faltten_type == FlattenType::Triangle) {
auto mo = m_c->selection_info()->model_object();
auto mv = mo->volumes[mesh_id];
m_hit_object_normal = mv->get_matrix().cast<float>() * closest_nromal;
}
}
}
}
if (closest_hit_mesh_id >= 0) {
m_rr = {mouse_position, closest_hit_mesh_id, closest_hit, closest_nromal}; // update_raycast_cache berfor click down
cur_facet = (int)facet;
return true;
}
cur_facet = -1;
return false;
}
void GLGizmoFlatten::on_render()
{
const auto& p_flat_shader = wxGetApp().get_shader("flat");
@ -105,21 +178,66 @@ void GLGizmoFlatten::on_render()
glsafe(::glEnable(GL_DEPTH_TEST));
glsafe(::glEnable(GL_BLEND));
wxGetApp().bind_shader(p_flat_shader);
const Camera &camera = wxGetApp().plater()->get_camera();
p_flat_shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (selection.is_single_full_instance()) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
const Camera& camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
if (m_faltten_type == FlattenType::Default) {
const Transform3d &m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
p_flat_shader->set_uniform("view_model_matrix", view_model_matrix);
p_flat_shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (this->is_plane_update_necessary())
update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) {
p_flat_shader->set_uniform("uniform_color", i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR);
m_planes[i].vbo.render(p_flat_shader);
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) *
m;
p_flat_shader->set_uniform("view_model_matrix", view_model_matrix);
if (this->is_plane_update_necessary()) update_planes();
for (int i = 0; i < (int) m_planes.size(); ++i) {
p_flat_shader->set_uniform("uniform_color", i == m_hover_id ? GLGizmoBase::FLATTEN_HOVER_COLOR : GLGizmoBase::FLATTEN_COLOR);
m_planes[i].vbo.render(p_flat_shader);
}
}
else {
Vec2d mouse_pos = m_parent.get_local_mouse_position();
const Camera &camera = wxGetApp().plater()->get_camera();
const Transform3d view_model_matrix = camera.get_view_matrix();
p_flat_shader->set_uniform("view_model_matrix", view_model_matrix);
const Selection & selection = m_parent.get_selection();
auto mo = get_selected_model_object(m_parent);
if (mo) {
const ModelInstance * mi = mo->instances[selection.get_instance_idx()];
std::vector<Transform3d> trafo_matrices;
for (const ModelVolume *mv : mo->volumes) {
if (mv->is_model_part())
trafo_matrices.emplace_back(mi->get_transformation().get_matrix() * mv->get_matrix());
}
update_raycast_cache(mouse_pos, camera, trafo_matrices,m_hit_facet);
if (m_hit_facet >= 0) {
if (m_last_hit_facet != m_hit_facet) {
m_last_hit_facet = m_hit_facet;
m_one_tri_model.reset();
auto mv = mo->volumes[m_rr.mesh_id];
auto world_tran = (mo->instances[selection.get_instance_idx()]->get_transformation().get_matrix() * mv->get_matrix()).cast<float>();
auto &vertices = mv->mesh().its.vertices;
auto &cur_faces = mv->mesh().its.indices;
if (m_hit_facet < cur_faces.size()) {
auto v0 = world_tran * vertices[cur_faces[m_hit_facet][0]] + m_rr.normal * 0.05;
auto v1 = world_tran * vertices[cur_faces[m_hit_facet][1]] + m_rr.normal * 0.05;
auto v2 = world_tran * vertices[cur_faces[m_hit_facet][2]] + m_rr.normal * 0.05;
indexed_triangle_set temp_its;
temp_its.indices.push_back({0, 1, 2});
temp_its.vertices.push_back(v0);
temp_its.vertices.push_back(v1);
temp_its.vertices.push_back(v2);
m_one_tri_model.init_from(temp_its);
}
}
if (m_one_tri_model.is_initialized()) {
glsafe(::glDisable(GL_CULL_FACE));
m_one_tri_model.set_color(GLGizmoBase::FLATTEN_HOVER_COLOR);
m_one_tri_model.render_geometry();
}
}
}
}
}
@ -142,26 +260,35 @@ void GLGizmoFlatten::on_render_for_picking()
glsafe(::glDisable(GL_BLEND));
wxGetApp().bind_shader(p_flat_shader);
const Camera &camera = wxGetApp().plater()->get_picking_camera();
p_flat_shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (selection.is_single_full_instance() && !wxGetKeyState(WXK_CONTROL)) {
const Transform3d& m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
const Camera& camera = wxGetApp().plater()->get_picking_camera();
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) * m;
if (m_faltten_type == FlattenType::Default) {
const Transform3d &m = selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_transformation().get_matrix();
p_flat_shader->set_uniform("view_model_matrix", view_model_matrix);
p_flat_shader->set_uniform("projection_matrix", camera.get_projection_matrix());
if (this->is_plane_update_necessary())
update_planes();
for (int i = 0; i < (int)m_planes.size(); ++i) {
p_flat_shader->set_uniform("uniform_color", picking_color_component(i));
m_planes[i].vbo.render(p_flat_shader);
const Transform3d view_model_matrix = camera.get_view_matrix() *
Geometry::assemble_transform(selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z() * Vec3d::UnitZ()) *
m;
p_flat_shader->set_uniform("view_model_matrix", view_model_matrix);
if (this->is_plane_update_necessary()) update_planes();
for (int i = 0; i < (int) m_planes.size(); ++i) {
p_flat_shader->set_uniform("uniform_color", picking_color_component(i));
m_planes[i].vbo.render(p_flat_shader);
}
}
else {
if (m_one_tri_model.is_initialized()) {
glsafe(::glDisable(GL_CULL_FACE));
const Transform3d view_model_matrix = camera.get_view_matrix();
p_flat_shader->set_uniform("view_model_matrix", view_model_matrix);
m_one_tri_model.set_color(picking_color_component(0));
m_one_tri_model.render_geometry();
}
}
}
wxGetApp().unbind_shader();
glsafe(::glEnable(GL_CULL_FACE));
}
@ -374,7 +501,7 @@ void GLGizmoFlatten::update_planes()
planes.pop_back();
}
};
const int plane_count = 20;
const int plane_count = 30;
for (size_t i = 0; i < m_planes.size(); i++) {
if (m_planes[i].area < experted_minimal_area) {
if (i + 1 >= plane_count) {

View File

@ -3,16 +3,12 @@
#include "GLGizmoBase.hpp"
#include "slic3r/GUI/3DScene.hpp"
#include "libslic3r/Model.hpp"
namespace Slic3r {
enum class ModelVolumeType : int;
namespace GUI {
class GLGizmoFlatten : public GLGizmoBase
{
// This gizmo does not use grabbers. The m_hover_id relates to polygon managed by the class itself.
@ -42,6 +38,12 @@ private:
void update_planes();
bool is_plane_update_necessary() const;
enum FlattenType {
Default,
Triangle,
};
FlattenType m_faltten_type{FlattenType::Default};
public:
GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
@ -61,6 +63,14 @@ protected:
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
private:
bool m_show_warning{false};
mutable RaycastResult m_rr;
mutable int m_hit_facet;
mutable int m_last_hit_facet;
mutable GLModel m_one_tri_model;
Vec3f m_hit_object_normal;
private:
bool update_raycast_cache(const Vec2d &mouse_position, const Camera &camera, const std::vector<Transform3d> &trafo_matrices, int &facet);
};
} // namespace GUI

View File

@ -1411,16 +1411,11 @@ void Selection::flattening_rotate(const Vec3d& normal)
for (unsigned int i : m_list) {
GLVolume& v = *(*m_volumes)[i];
// Normal transformed from the object coordinate space to the world coordinate space.
const auto &voldata = m_cache.volumes_data[i];
Vec3d tnormal = (Geometry::assemble_transform(
Vec3d::Zero(), voldata.get_instance_rotation(),
voldata.get_instance_scaling_factor().cwiseInverse(), voldata.get_instance_mirror()) * normal).normalized();
const Geometry::Transformation &old_inst_trafo = v.get_instance_transformation();
const Vec3d tnormal = old_inst_trafo.get_matrix_no_offset() * normal;
// Additional rotation to align tnormal with the down vector in the world coordinate space.
auto extra_rotation = Eigen::Quaterniond().setFromTwoVectors(tnormal, - Vec3d::UnitZ());
v.set_instance_rotation(Geometry::extract_euler_angles(extra_rotation.toRotationMatrix() * m_cache.volumes_data[i].get_instance_rotation_matrix()));
BOOST_LOG_TRIVIAL(debug) << "flattening_rotate " << (*m_volumes)[i]->name << std::fixed << std::setprecision(4) << ": tnormal=" << tnormal.transpose() << "; extra_rotation=" << Geometry::extract_euler_angles(extra_rotation.toRotationMatrix()).transpose();
flush_logs();
const Transform3d rotation_matrix = Transform3d(Eigen::Quaterniond().setFromTwoVectors(tnormal, -Vec3d::UnitZ()));
v.set_instance_transformation(old_inst_trafo.get_offset_matrix() * rotation_matrix * old_inst_trafo.get_matrix_no_offset());
}
#if !DISABLE_INSTANCES_SYNCH

View File

@ -616,7 +616,7 @@ void SyncAmsInfoDialog::add_two_image_control()
void SyncAmsInfoDialog::to_next_plate(wxCommandEvent &event) {
auto cobox_idx = m_combobox_plate->GetSelection();
cobox_idx++;
if (cobox_idx >= m_combobox_plate->GetCount()) {
if (cobox_idx >= (int)m_combobox_plate->GetCount()) {
return;
}
m_combobox_plate->SetSelection(cobox_idx);