Measuring: Measure gizmo features registered for raycasted picking
This commit is contained in:
parent
aeb8dec463
commit
6c0aff0d23
10 changed files with 160 additions and 29 deletions
|
@ -49,6 +49,16 @@ public:
|
|||
// For anything, return an extra point that should also be considered a part of this.
|
||||
std::optional<Vec3d> get_extra_point() const { assert(m_type != SurfaceFeatureType::Undef); return m_pt3; }
|
||||
|
||||
bool operator == (const SurfaceFeature& other) const {
|
||||
if (this->m_type != other.m_type) return false;
|
||||
if (!this->m_pt1.isApprox(other.m_pt1)) return false;
|
||||
if (!this->m_pt2.isApprox(other.m_pt2)) return false;
|
||||
if (this->m_pt3.has_value() && !other.m_pt3.has_value()) return false;
|
||||
if (!this->m_pt3.has_value() && other.m_pt3.has_value()) return false;
|
||||
if (this->m_pt3.has_value() && other.m_pt3.has_value() && !(*this->m_pt3).isApprox(*other.m_pt3)) return false;
|
||||
return this->m_value == other.m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
SurfaceFeatureType m_type = SurfaceFeatureType::Undef;
|
||||
Vec3d m_pt1;
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
#define ENABLE_RAYCAST_PICKING (1 && ENABLE_LEGACY_OPENGL_REMOVAL)
|
||||
#define ENABLE_RAYCAST_PICKING_DEBUG (0 && ENABLE_RAYCAST_PICKING)
|
||||
// Enable Measure Gizmo
|
||||
#define ENABLE_MEASURE_GIZMO (1 && ENABLE_LEGACY_OPENGL_REMOVAL)
|
||||
#define ENABLE_MEASURE_GIZMO (1 && ENABLE_RAYCAST_PICKING)
|
||||
// Enable debug code for Measure Gizmo
|
||||
#define ENABLE_MEASURE_GIZMO_DEBUG (0 && ENABLE_MEASURE_GIZMO)
|
||||
|
||||
|
|
|
@ -2252,7 +2252,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
#if ENABLE_LEGACY_OPENGL_REMOVAL
|
||||
volume.model.init_from(mesh);
|
||||
#if ENABLE_RAYCAST_PICKING
|
||||
volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(mesh));
|
||||
volume.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<TriangleMesh>(mesh));
|
||||
#endif // ENABLE_RAYCAST_PICKING
|
||||
#else
|
||||
volume.indexed_vertex_array.load_mesh(mesh);
|
||||
|
@ -2272,7 +2272,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
#if ENABLE_RAYCAST_PICKING
|
||||
const TriangleMesh& new_mesh = m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh();
|
||||
volume.model.init_from(new_mesh);
|
||||
volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(new_mesh));
|
||||
volume.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<TriangleMesh>(new_mesh));
|
||||
#else
|
||||
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
|
||||
#endif // ENABLE_RAYCAST_PICKING
|
||||
|
|
|
@ -680,7 +680,7 @@ public:
|
|||
|
||||
#if ENABLE_RAYCAST_PICKING
|
||||
std::shared_ptr<SceneRaycasterItem> add_raycaster_for_picking(SceneRaycaster::EType type, int id, const MeshRaycaster& raycaster,
|
||||
const Transform3d& trafo, bool use_back_faces = false) {
|
||||
const Transform3d& trafo = Transform3d::Identity(), bool use_back_faces = false) {
|
||||
return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo, use_back_faces);
|
||||
}
|
||||
void remove_raycasters_for_picking(SceneRaycaster::EType type, int id) {
|
||||
|
|
|
@ -257,6 +257,21 @@ void GLModel::Geometry::remove_vertex(size_t id)
|
|||
}
|
||||
}
|
||||
|
||||
indexed_triangle_set GLModel::Geometry::get_as_indexed_triangle_set() const
|
||||
{
|
||||
indexed_triangle_set its;
|
||||
its.vertices.reserve(vertices_count());
|
||||
for (size_t i = 0; i < vertices_count(); ++i) {
|
||||
its.vertices.emplace_back(extract_position_3(i));
|
||||
}
|
||||
its.indices.reserve(indices_count() / 3);
|
||||
for (size_t i = 0; i < indices_count() / 3; ++i) {
|
||||
const size_t tri_id = i * 3;
|
||||
its.indices.emplace_back(extract_index(tri_id), extract_index(tri_id + 1), extract_index(tri_id + 2));
|
||||
}
|
||||
return its;
|
||||
}
|
||||
|
||||
size_t GLModel::Geometry::vertex_stride_floats(const Format& format)
|
||||
{
|
||||
switch (format.vertex_layout)
|
||||
|
|
|
@ -140,6 +140,8 @@ namespace GUI {
|
|||
size_t vertices_size_bytes() const { return vertices_size_floats() * sizeof(float); }
|
||||
size_t indices_size_bytes() const { return indices.size() * index_stride_bytes(*this); }
|
||||
|
||||
indexed_triangle_set get_as_indexed_triangle_set() const;
|
||||
|
||||
static size_t vertex_stride_floats(const Format& format);
|
||||
static size_t vertex_stride_bytes(const Format& format) { return vertex_stride_floats(format) * sizeof(float); }
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ void GLGizmoHollow::on_register_raycasters_for_picking()
|
|||
if (info != nullptr && !info->model_object()->sla_drain_holes.empty()) {
|
||||
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()));
|
||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster));
|
||||
}
|
||||
update_raycasters_for_picking_transform();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp"
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Measure.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
@ -20,12 +19,22 @@ namespace Slic3r {
|
|||
namespace GUI {
|
||||
|
||||
static const Slic3r::ColorRGBA HOVER_COLOR = { 0.8f, 0.2f, 0.2f, 1.0f };
|
||||
static const int POINT_ID = 100;
|
||||
static const int EDGE_ID = 200;
|
||||
static const int CIRCLE_ID = 300;
|
||||
static const int CIRCLE_CENTER_ID = 301;
|
||||
static const int PLANE_ID = 400;
|
||||
|
||||
GLGizmoMeasure::GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
{
|
||||
m_sphere.init_from(smooth_sphere(16, 7.5f));
|
||||
m_cylinder.init_from(smooth_cylinder(16, 5.0f, 1.0f));
|
||||
GLModel::Geometry sphere_geometry = smooth_sphere(16, 7.5f);
|
||||
m_sphere.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(sphere_geometry.get_as_indexed_triangle_set())));
|
||||
m_sphere.model.init_from(std::move(sphere_geometry));
|
||||
|
||||
GLModel::Geometry cylinder_geometry = smooth_cylinder(16, 5.0f, 1.0f);
|
||||
m_cylinder.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(cylinder_geometry.get_as_indexed_triangle_set())));
|
||||
m_cylinder.model.init_from(std::move(cylinder_geometry));
|
||||
}
|
||||
|
||||
bool GLGizmoMeasure::on_mouse(const wxMouseEvent &mouse_event)
|
||||
|
@ -130,6 +139,7 @@ void GLGizmoMeasure::on_render()
|
|||
|
||||
const Transform3d& model_matrix = selection.get_first_volume()->world_matrix();
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
const float inv_zoom = (float)camera.get_inv_zoom();
|
||||
|
||||
Vec3f pos;
|
||||
Vec3f normal;
|
||||
|
@ -174,8 +184,70 @@ void GLGizmoMeasure::on_render()
|
|||
}
|
||||
#endif // ENABLE_MEASURE_GIZMO_DEBUG
|
||||
|
||||
if (features.empty())
|
||||
return;
|
||||
if (m_features != features) {
|
||||
GLGizmoMeasure::on_unregister_raycasters_for_picking();
|
||||
m_features = features;
|
||||
if (m_features.empty())
|
||||
return;
|
||||
|
||||
#if !ENABLE_MEASURE_GIZMO_DEBUG
|
||||
for (const Measure::SurfaceFeature& feature : m_features) {
|
||||
switch (feature.get_type()) {
|
||||
case Measure::SurfaceFeatureType::Point:
|
||||
{
|
||||
m_raycasters.insert({ POINT_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, POINT_ID, *m_sphere.mesh_raycaster) });
|
||||
break;
|
||||
}
|
||||
case Measure::SurfaceFeatureType::Edge:
|
||||
{
|
||||
m_raycasters.insert({ EDGE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, EDGE_ID, *m_cylinder.mesh_raycaster) });
|
||||
break;
|
||||
}
|
||||
case Measure::SurfaceFeatureType::Circle:
|
||||
{
|
||||
const auto& [center, radius, n] = feature.get_circle();
|
||||
m_circle.reset();
|
||||
GLModel::Geometry circle_geometry = smooth_torus(64, 16, float(radius), 5.0f * inv_zoom);
|
||||
m_circle.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(circle_geometry.get_as_indexed_triangle_set())));
|
||||
m_circle.model.init_from(std::move(circle_geometry));
|
||||
|
||||
m_raycasters.insert({ CIRCLE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_ID, *m_circle.mesh_raycaster) });
|
||||
m_raycasters.insert({ CIRCLE_CENTER_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, CIRCLE_CENTER_ID, *m_sphere.mesh_raycaster) });
|
||||
break;
|
||||
}
|
||||
case Measure::SurfaceFeatureType::Plane:
|
||||
{
|
||||
const auto& [idx, normal, pt] = feature.get_plane();
|
||||
const std::vector<std::vector<int>> planes_triangles = m_measuring->get_planes_triangle_indices();
|
||||
const std::vector<int>& triangle_indices = planes_triangles[idx];
|
||||
|
||||
const indexed_triangle_set its = (m_old_model_volume != nullptr) ? m_old_model_volume->mesh().its : m_old_model_object->volumes.front()->mesh().its;
|
||||
GLModel::Geometry init_data;
|
||||
init_data.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3N3 };
|
||||
unsigned int i = 0;
|
||||
for (int idx : triangle_indices) {
|
||||
const Vec3f& v0 = its.vertices[its.indices[idx][0]];
|
||||
const Vec3f& v1 = its.vertices[its.indices[idx][1]];
|
||||
const Vec3f& v2 = its.vertices[its.indices[idx][2]];
|
||||
|
||||
const Vec3f n = (v1 - v0).cross(v2 - v0).normalized();
|
||||
init_data.add_vertex(v0, n);
|
||||
init_data.add_vertex(v1, n);
|
||||
init_data.add_vertex(v2, n);
|
||||
init_data.add_triangle(i, i + 1, i + 2);
|
||||
i += 3;
|
||||
}
|
||||
|
||||
m_plane.reset();
|
||||
m_plane.mesh_raycaster = std::make_unique<MeshRaycaster>(std::make_shared<const TriangleMesh>(std::move(init_data.get_as_indexed_triangle_set())));
|
||||
m_plane.model.init_from(std::move(init_data));
|
||||
m_raycasters.insert({ PLANE_ID, m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, PLANE_ID, *m_plane.mesh_raycaster) });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_MEASURE_GIZMO_DEBUG
|
||||
}
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
|
@ -189,9 +261,8 @@ void GLGizmoMeasure::on_render()
|
|||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
const Transform3d& view_matrix = camera.get_view_matrix();
|
||||
const float inv_zoom = camera.get_inv_zoom();
|
||||
|
||||
for (const Measure::SurfaceFeature& feature : features) {
|
||||
for (const Measure::SurfaceFeature& feature : m_features) {
|
||||
switch (feature.get_type()) {
|
||||
case Measure::SurfaceFeatureType::Point:
|
||||
{
|
||||
|
@ -201,8 +272,11 @@ void GLGizmoMeasure::on_render()
|
|||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", view_normal_matrix);
|
||||
m_sphere.set_color(HOVER_COLOR);
|
||||
m_sphere.render();
|
||||
m_sphere.model.set_color(HOVER_COLOR);
|
||||
m_sphere.model.render();
|
||||
auto it = m_raycasters.find(POINT_ID);
|
||||
if (it != m_raycasters.end() && it->second != nullptr)
|
||||
it->second->set_transform(feature_matrix);
|
||||
break;
|
||||
}
|
||||
case Measure::SurfaceFeatureType::Circle:
|
||||
|
@ -214,19 +288,22 @@ void GLGizmoMeasure::on_render()
|
|||
shader->set_uniform("view_model_matrix", center_view_model_matrix);
|
||||
const Matrix3d center_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * center_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", center_view_normal_matrix);
|
||||
m_sphere.set_color(HOVER_COLOR);
|
||||
m_sphere.render();
|
||||
|
||||
m_circle.reset();
|
||||
m_circle.init_from(smooth_torus(64, 16, float(radius), 5.0f * inv_zoom));
|
||||
m_sphere.model.set_color(HOVER_COLOR);
|
||||
m_sphere.model.render();
|
||||
auto it = m_raycasters.find(CIRCLE_CENTER_ID);
|
||||
if (it != m_raycasters.end() && it->second != nullptr)
|
||||
it->second->set_transform(center_matrix);
|
||||
|
||||
const Transform3d circle_matrix = model_matrix * Geometry::translation_transform(center);
|
||||
const Transform3d circle_view_model_matrix = view_matrix * circle_matrix;
|
||||
shader->set_uniform("view_model_matrix", circle_view_model_matrix);
|
||||
const Matrix3d circle_view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * circle_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", circle_view_normal_matrix);
|
||||
m_circle.set_color(HOVER_COLOR);
|
||||
m_circle.render();
|
||||
m_circle.model.set_color(HOVER_COLOR);
|
||||
m_circle.model.render();
|
||||
it = m_raycasters.find(CIRCLE_ID);
|
||||
if (it != m_raycasters.end() && it->second != nullptr)
|
||||
it->second->set_transform(circle_matrix);
|
||||
break;
|
||||
}
|
||||
case Measure::SurfaceFeatureType::Edge:
|
||||
|
@ -239,8 +316,11 @@ void GLGizmoMeasure::on_render()
|
|||
shader->set_uniform("view_model_matrix", view_model_matrix);
|
||||
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * feature_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
shader->set_uniform("view_normal_matrix", view_normal_matrix);
|
||||
m_cylinder.set_color(HOVER_COLOR);
|
||||
m_cylinder.render();
|
||||
m_cylinder.model.set_color(HOVER_COLOR);
|
||||
m_cylinder.model.render();
|
||||
auto it = m_raycasters.find(EDGE_ID);
|
||||
if (it != m_raycasters.end() && it->second != nullptr)
|
||||
it->second->set_transform(feature_matrix);
|
||||
break;
|
||||
}
|
||||
case Measure::SurfaceFeatureType::Plane:
|
||||
|
@ -253,6 +333,9 @@ void GLGizmoMeasure::on_render()
|
|||
shader->set_uniform("view_normal_matrix", view_normal_matrix);
|
||||
m_plane_models_cache[idx].set_color(HOVER_COLOR);
|
||||
m_plane_models_cache[idx].render();
|
||||
auto it = m_raycasters.find(PLANE_ID);
|
||||
if (it != m_raycasters.end() && it->second != nullptr)
|
||||
it->second->set_transform(model_matrix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -340,6 +423,19 @@ void GLGizmoMeasure::update_if_needed()
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::on_register_raycasters_for_picking()
|
||||
{
|
||||
// the features are rendered on top of the scene, so the raytraced picker should take it into account
|
||||
m_parent.set_raycaster_gizmos_on_top(true);
|
||||
}
|
||||
|
||||
void GLGizmoMeasure::on_unregister_raycasters_for_picking()
|
||||
{
|
||||
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo);
|
||||
m_parent.set_raycaster_gizmos_on_top(false);
|
||||
m_raycasters.clear();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "slic3r/GUI/GLModel.hpp"
|
||||
#include "libslic3r/Measure.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
@ -25,10 +26,14 @@ class GLGizmoMeasure : public GLGizmoBase
|
|||
private:
|
||||
std::unique_ptr<Measure::Measuring> m_measuring;
|
||||
|
||||
GLModel m_sphere;
|
||||
GLModel m_cylinder;
|
||||
GLModel m_circle;
|
||||
PickingModel m_sphere;
|
||||
PickingModel m_cylinder;
|
||||
PickingModel m_circle;
|
||||
PickingModel m_plane;
|
||||
|
||||
std::vector<GLModel> m_plane_models_cache;
|
||||
std::map<int, std::shared_ptr<SceneRaycasterItem>> m_raycasters;
|
||||
std::vector<Measure::SurfaceFeature> m_features;
|
||||
|
||||
// This holds information to decide whether recalculation is necessary:
|
||||
std::vector<Transform3d> m_volumes_matrices;
|
||||
|
@ -53,7 +58,7 @@ private:
|
|||
|
||||
public:
|
||||
GLGizmoMeasure(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Apply rotation on select plane
|
||||
/// </summary>
|
||||
|
@ -71,6 +76,9 @@ protected:
|
|||
void on_render_for_picking() override;
|
||||
void on_set_state() override;
|
||||
CommonGizmosDataID on_get_requirements() const override;
|
||||
|
||||
virtual void on_register_raycasters_for_picking() override;
|
||||
virtual void on_unregister_raycasters_for_picking() override;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -148,8 +148,8 @@ void GLGizmoSlaSupports::on_register_raycasters_for_picking()
|
|||
|
||||
if (m_editing_mode && !m_editing_cache.empty()) {
|
||||
for (size_t i = 0; i < m_editing_cache.size(); ++i) {
|
||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster, Transform3d::Identity()),
|
||||
m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster, Transform3d::Identity()));
|
||||
m_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_sphere.mesh_raycaster),
|
||||
m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster));
|
||||
}
|
||||
update_raycasters_for_picking_transform();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue