Tech ENABLE_RAYCAST_PICKING - Raytraced picking of Gizmo Hollow

This commit is contained in:
enricoturri1966 2022-06-15 09:01:13 +02:00
parent f5e68a6ac6
commit c5c5c23ed2
5 changed files with 144 additions and 16 deletions

View File

@ -1958,12 +1958,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
m_hover_volume_idxs.clear(); m_hover_volume_idxs.clear();
#if ENABLE_RAYCAST_PICKING
GLGizmoBase* curr_gizmo = m_gizmos.get_current();
if (curr_gizmo != nullptr)
curr_gizmo->unregister_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
struct ModelVolumeState { struct ModelVolumeState {
ModelVolumeState(const GLVolume* volume) : ModelVolumeState(const GLVolume* volume) :
model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {} model_volume(nullptr), geometry_id(volume->geometry_id), volume_idx(-1) {}
@ -2416,6 +2410,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
} }
// refresh gizmo elements raycasters for picking // refresh gizmo elements raycasters for picking
GLGizmoBase* curr_gizmo = m_gizmos.get_current();
if (curr_gizmo != nullptr)
curr_gizmo->unregister_raycasters_for_picking();
m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Gizmo); m_scene_raycaster.remove_raycasters(SceneRaycaster::EType::Gizmo);
if (curr_gizmo != nullptr && !m_selection.is_empty()) if (curr_gizmo != nullptr && !m_selection.is_empty())
curr_gizmo->register_raycasters_for_picking(); curr_gizmo->register_raycasters_for_picking();

View File

@ -673,6 +673,10 @@ public:
m_scene_raycaster.remove_raycasters(type); m_scene_raycaster.remove_raycasters(type);
} }
std::vector<std::shared_ptr<SceneRaycasterItem>>* get_raycasters_for_picking(SceneRaycaster::EType type) {
return m_scene_raycaster.get_raycasters(type);
}
void set_raycaster_gizmos_on_top(bool value) { void set_raycaster_gizmos_on_top(bool value) {
m_scene_raycaster.set_gizmos_on_top(value); m_scene_raycaster.set_gizmos_on_top(value);
} }

View File

@ -55,6 +55,12 @@ void GLGizmoHollow::data_changed()
} }
if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh())
m_holes_in_drilled_mesh = mo->sla_drain_holes; m_holes_in_drilled_mesh = mo->sla_drain_holes;
#if ENABLE_RAYCAST_PICKING
if (m_raycasters.empty())
on_register_raycasters_for_picking();
else
update_raycasters_for_picking_transform();
#endif // ENABLE_RAYCAST_PICKING
} }
} }
@ -62,8 +68,16 @@ void GLGizmoHollow::data_changed()
void GLGizmoHollow::on_render() void GLGizmoHollow::on_render()
{ {
#if ENABLE_RAYCAST_PICKING
if (!m_cylinder.model.is_initialized()) {
indexed_triangle_set its = its_make_cylinder(1.0, 1.0);
m_cylinder.model.init_from(its);
m_cylinder.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(its)));
}
#else
if (!m_cylinder.is_initialized()) if (!m_cylinder.is_initialized())
m_cylinder.init_from(its_make_cylinder(1.0, 1.0)); m_cylinder.init_from(its_make_cylinder(1.0, 1.0));
#endif // ENABLE_RAYCAST_PICKING
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info(); const CommonGizmosDataObjects::SelectionInfo* sel_info = m_c->selection_info();
@ -80,7 +94,11 @@ void GLGizmoHollow::on_render()
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
if (selection.is_from_single_instance()) if (selection.is_from_single_instance())
#if ENABLE_RAYCAST_PICKING
render_points(selection);
#else
render_points(selection, false); render_points(selection, false);
#endif // ENABLE_RAYCAST_PICKING
m_selection_rectangle.render(m_parent); m_selection_rectangle.render(m_parent);
m_c->object_clipper()->render_cut(); m_c->object_clipper()->render_cut();
@ -89,8 +107,29 @@ void GLGizmoHollow::on_render()
glsafe(::glDisable(GL_BLEND)); glsafe(::glDisable(GL_BLEND));
} }
#if ENABLE_RAYCAST_PICKING
void GLGizmoHollow::on_register_raycasters_for_picking()
{
assert(m_raycasters.empty());
#if !ENABLE_RAYCAST_PICKING set_sla_auxiliary_volumes_picking_state(false);
const CommonGizmosDataObjects::SelectionInfo* info = m_c->selection_info();
if (info != nullptr && info->model_object()->sla_drain_holes.size() > 0) {
const sla::DrainHoles& drain_holes = info->model_object()->sla_drain_holes;
for (int i = 0; i < (int)drain_holes.size(); ++i) {
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster, Transform3d::Identity()));
}
update_raycasters_for_picking_transform();
}
}
void GLGizmoHollow::on_unregister_raycasters_for_picking()
{
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo);
m_raycasters.clear();
set_sla_auxiliary_volumes_picking_state(true);
}
#else
void GLGizmoHollow::on_render_for_picking() void GLGizmoHollow::on_render_for_picking()
{ {
const Selection& selection = m_parent.get_selection(); const Selection& selection = m_parent.get_selection();
@ -101,12 +140,20 @@ void GLGizmoHollow::on_render_for_picking()
glsafe(::glEnable(GL_DEPTH_TEST)); glsafe(::glEnable(GL_DEPTH_TEST));
render_points(selection, true); render_points(selection, true);
} }
#endif // !ENABLE_RAYCAST_PICKING #endif // ENABLE_RAYCAST_PICKING
#if ENABLE_RAYCAST_PICKING
void GLGizmoHollow::render_points(const Selection& selection)
#else
void GLGizmoHollow::render_points(const Selection& selection, bool picking) void GLGizmoHollow::render_points(const Selection& selection, bool picking)
#endif // ENABLE_RAYCAST_PICKING
{ {
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_RAYCAST_PICKING
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
#else
GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light"); GLShaderProgram* shader = picking ? wxGetApp().get_shader("flat") : wxGetApp().get_shader("gouraud_light");
#endif // ENABLE_RAYCAST_PICKING
if (shader == nullptr) if (shader == nullptr)
return; return;
@ -152,13 +199,22 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
const sla::DrainHole& drain_hole = drain_holes[i]; const sla::DrainHole& drain_hole = drain_holes[i];
const bool point_selected = m_selected[i]; const bool point_selected = m_selected[i];
#if ENABLE_RAYCAST_PICKING
const bool clipped = is_mesh_point_clipped(drain_hole.pos.cast<double>());
m_raycasters[i]->set_active(!clipped);
if (clipped)
continue;
#else
if (is_mesh_point_clipped(drain_hole.pos.cast<double>())) if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
continue; continue;
#endif // ENABLE_RAYCAST_PICKING
// First decide about the color of the point. // First decide about the color of the point.
#if !ENABLE_RAYCAST_PICKING
if (picking) if (picking)
render_color = picking_color_component(i); render_color = picking_color_component(i);
else { else {
#endif // !ENABLE_RAYCAST_PICKING
if (size_t(m_hover_id) == i) if (size_t(m_hover_id) == i)
render_color = ColorRGBA::CYAN(); render_color = ColorRGBA::CYAN();
else if (m_c->hollowed_mesh() && else if (m_c->hollowed_mesh() &&
@ -168,10 +224,16 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
} }
else // neither hover nor picking else // neither hover nor picking
render_color = point_selected ? ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f); render_color = point_selected ? ColorRGBA(1.0f, 0.3f, 0.3f, 0.5f) : ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f);
#if !ENABLE_RAYCAST_PICKING
} }
#endif // !ENABLE_RAYCAST_PICKING
#if ENABLE_LEGACY_OPENGL_REMOVAL #if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_RAYCAST_PICKING
m_cylinder.model.set_color(render_color);
#else
m_cylinder.set_color(render_color); m_cylinder.set_color(render_color);
#endif // ENABLE_RAYCAST_PICKING
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object. // Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
const Transform3d hole_matrix = Geometry::assemble_transform(drain_hole.pos.cast<double>()) * instance_scaling_matrix_inverse; const Transform3d hole_matrix = Geometry::assemble_transform(drain_hole.pos.cast<double>()) * instance_scaling_matrix_inverse;
#else #else
@ -200,7 +262,11 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
glsafe(::glTranslated(0., 0., -drain_hole.height)); glsafe(::glTranslated(0., 0., -drain_hole.height));
glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength)); glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL #endif // ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_RAYCAST_PICKING
m_cylinder.model.render();
#else
m_cylinder.render(); m_cylinder.render();
#endif // ENABLE_RAYCAST_PICKING
if (vol->is_left_handed()) if (vol->is_left_handed())
glsafe(::glFrontFace(GL_CCW)); glsafe(::glFrontFace(GL_CCW));
@ -327,6 +393,10 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
assert(m_selected.size() == mo->sla_drain_holes.size()); assert(m_selected.size() == mo->sla_drain_holes.size());
m_parent.set_as_dirty(); m_parent.set_as_dirty();
m_wait_for_up_event = true; m_wait_for_up_event = true;
#if ENABLE_RAYCAST_PICKING
on_unregister_raycasters_for_picking();
on_register_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
} }
else else
return false; return false;
@ -520,6 +590,47 @@ void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
}); });
} }
#if ENABLE_RAYCAST_PICKING
void GLGizmoHollow::set_sla_auxiliary_volumes_picking_state(bool state)
{
std::vector<std::shared_ptr<SceneRaycasterItem>>* raycasters = m_parent.get_raycasters_for_picking(SceneRaycaster::EType::Volume);
if (raycasters != nullptr) {
const Selection& selection = m_parent.get_selection();
const Selection::IndicesList ids = selection.get_volume_idxs();
for (unsigned int id : ids) {
const GLVolume* v = selection.get_volume(id);
if (v->is_sla_pad() || v->is_sla_support()) {
auto it = std::find_if(raycasters->begin(), raycasters->end(), [v](std::shared_ptr<SceneRaycasterItem> item) { return item->get_raycaster() == v->mesh_raycaster.get(); });
if (it != raycasters->end())
(*it)->set_active(state);
}
}
}
}
void GLGizmoHollow::update_raycasters_for_picking_transform()
{
const CommonGizmosDataObjects::SelectionInfo* info = m_c->selection_info();
if (info != nullptr) {
const sla::DrainHoles& drain_holes = info->model_object()->sla_drain_holes;
if (!drain_holes.empty()) {
const GLVolume* vol = m_parent.get_selection().get_first_volume();
const Transform3d instance_scaling_matrix_inverse = vol->get_instance_transformation().get_scaling_factor_matrix().inverse();
for (size_t i = 0; i < drain_holes.size(); ++i) {
const sla::DrainHole& drain_hole = drain_holes[i];
const Transform3d hole_matrix = Geometry::translation_transform(drain_hole.pos.cast<double>()) * instance_scaling_matrix_inverse;
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast<double>());
const Eigen::AngleAxisd aa(q);
const Transform3d matrix = vol->world_matrix() * hole_matrix * Transform3d(aa.toRotationMatrix()) *
Geometry::translation_transform(-drain_hole.height * Vec3d::UnitZ()) * Geometry::scale_transform(Vec3d(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength));
m_raycasters[i]->set_transform(matrix);
}
}
}
}
#endif // ENABLE_RAYCAST_PICKING
std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>> std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>>
GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const

View File

@ -28,8 +28,7 @@ private:
public: public:
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id); GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
virtual ~GLGizmoHollow() = default; void data_changed() override;
void data_changed() override;
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
void delete_selected_points(); void delete_selected_points();
bool is_selection_rectangle_dragging() const { bool is_selection_rectangle_dragging() const {
@ -43,20 +42,37 @@ public:
/// <param name="mouse_event">Keep information about mouse click</param> /// <param name="mouse_event">Keep information about mouse click</param>
/// <returns>Return True when use the information otherwise False.</returns> /// <returns>Return True when use the information otherwise False.</returns>
bool on_mouse(const wxMouseEvent &mouse_event) override; bool on_mouse(const wxMouseEvent &mouse_event) override;
private:
protected:
bool on_init() override; bool on_init() override;
void on_render() override; void on_render() override;
#if !ENABLE_RAYCAST_PICKING #if ENABLE_RAYCAST_PICKING
virtual void on_register_raycasters_for_picking() override;
virtual void on_unregister_raycasters_for_picking() override;
#else
void on_render_for_picking() override; void on_render_for_picking() override;
#endif // !ENABLE_RAYCAST_PICKING #endif // ENABLE_RAYCAST_PICKING
private:
#if ENABLE_RAYCAST_PICKING
void render_points(const Selection& selection);
#else
void render_points(const Selection& selection, bool picking = false); void render_points(const Selection& selection, bool picking = false);
#endif // ENABLE_RAYCAST_PICKING
void hollow_mesh(bool postpone_error_messages = false); void hollow_mesh(bool postpone_error_messages = false);
bool unsaved_changes() const; #if ENABLE_RAYCAST_PICKING
void set_sla_auxiliary_volumes_picking_state(bool state);
void update_raycasters_for_picking_transform();
#endif // ENABLE_RAYCAST_PICKING
ObjectID m_old_mo_id = -1; ObjectID m_old_mo_id = -1;
#if ENABLE_RAYCAST_PICKING
PickingModel m_cylinder;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_raycasters;
#else
GLModel m_cylinder; GLModel m_cylinder;
#endif // ENABLE_RAYCAST_PICKING
float m_new_hole_radius = 2.f; // Size of a new hole. float m_new_hole_radius = 2.f; // Size of a new hole.
float m_new_hole_height = 6.f; float m_new_hole_height = 6.f;

View File

@ -88,6 +88,8 @@ public:
void remove_raycasters(EType type); void remove_raycasters(EType type);
void remove_raycaster(std::shared_ptr<SceneRaycasterItem> item); void remove_raycaster(std::shared_ptr<SceneRaycasterItem> item);
std::vector<std::shared_ptr<SceneRaycasterItem>>* get_raycasters(EType type);
void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; } void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; }
HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr); HitResult hit(const Vec2d& mouse_pos, const Camera& camera, const ClippingPlane* clipping_plane = nullptr);
@ -101,8 +103,6 @@ public:
#endif // ENABLE_RAYCAST_PICKING_DEBUG #endif // ENABLE_RAYCAST_PICKING_DEBUG
private: private:
std::vector<std::shared_ptr<SceneRaycasterItem>>* get_raycasters(EType type);
static PickingId encode_id(EType type, PickingId id); static PickingId encode_id(EType type, PickingId id);
static PickingId decode_id(EType type, PickingId id); static PickingId decode_id(EType type, PickingId id);
static PickingId base_id(EType type); static PickingId base_id(EType type);