Tech ENABLE_RAYCAST_PICKING - Refactoring to allow for easier update of raycasters transform

(cherry picked from commit prusa3d/PrusaSlicer@9ac5ab857b)
This commit is contained in:
enricoturri1966 2023-10-29 00:06:43 +08:00 committed by Noisyfox
parent 29be4cc9a3
commit ab090bf20d
6 changed files with 64 additions and 73 deletions

View File

@ -729,8 +729,8 @@ public:
bool init();
void post_event(wxEvent &&event);
void add_raycaster_for_picking(SceneRaycaster::EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) {
m_scene_raycaster.add_raycaster(type, id, raycaster, trafo);
std::shared_ptr<SceneRaycasterItem> add_raycaster_for_picking(SceneRaycaster::EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo) {
return m_scene_raycaster.add_raycaster(type, id, raycaster, trafo);
}
void remove_raycasters_for_picking(SceneRaycaster::EType type, PickingId id) {
m_scene_raycaster.remove_raycasters(type, id);

View File

@ -104,17 +104,17 @@ PickingModel &GLGizmoBase::Grabber::get_cube()
return s_cube;
}
void GLGizmoBase::Grabber::register_raycasters_for_picking(int id)
void GLGizmoBase::Grabber::register_raycasters_for_picking(PickingId id)
{
picking_id = id;
assert(elements_registered_for_picking == false);
// registration will happen on next call to render()
}
void GLGizmoBase::Grabber::unregister_raycasters_for_picking()
{
wxGetApp().plater()->canvas3D()->remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, picking_id);
picking_id = -1;
elements_registered_for_picking = false;
raycasters = { nullptr };
}
void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color)
@ -150,48 +150,48 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color)
const Transform3d& view_matrix = camera.get_view_matrix();
const Matrix3d view_matrix_no_offset = view_matrix.matrix().block(0, 0, 3, 3);
auto render_extension = [&view_matrix, &view_matrix_no_offset, shader, register_for_picking = !elements_registered_for_picking, picking_id = picking_id](PickingModel &model, const Transform3d &model_matrix) {
auto render_extension = [&view_matrix, &view_matrix_no_offset, shader, this](int idx, PickingModel &model, const Transform3d &model_matrix) {
shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
const Matrix3d view_normal_matrix = view_matrix_no_offset * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
shader->set_uniform("view_normal_matrix", view_normal_matrix);
model.model.render();
if (register_for_picking) {
if (raycasters[idx] == nullptr) {
GLCanvas3D &canvas = *wxGetApp().plater()->canvas3D();
canvas.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, picking_id, *model.mesh_raycaster, model_matrix);
raycasters[idx] = canvas.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, picking_id, *model.mesh_raycaster, model_matrix);
} else {
raycasters[idx]->set_transform(model_matrix);
}
};
if (extensions == EGrabberExtension::PosZ) {
const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, Vec3d(0.75 * extension_size, 0.75 * extension_size, 2.0 * extension_size));
render_extension(s_cone, model_matrix);
render_extension(0, s_cone, model_matrix);
} else {
const Transform3d model_matrix = matrix * Geometry::assemble_transform(center, angles, grabber_size * Vec3d::Ones());
render_extension(s_cube, model_matrix);
render_extension(0, s_cube, model_matrix);
const Transform3d extension_model_matrix_base = matrix * Geometry::assemble_transform(center, angles);
const Vec3d extension_scale(0.75 * extension_size, 0.75 * extension_size, 3.0 * extension_size);
if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosX)) != 0) {
render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, 0.5 * double(PI), 0.0), extension_scale));
render_extension(1, s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, 0.5 * double(PI), 0.0), extension_scale));
}
if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegX)) != 0) {
render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, -0.5 * double(PI), 0.0), extension_scale));
render_extension(2, s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitX(), Vec3d(0.0, -0.5 * double(PI), 0.0), extension_scale));
}
if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosY)) != 0) {
render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitY(), Vec3d(-0.5 * double(PI), 0.0, 0.0), extension_scale));
render_extension(3, s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitY(), Vec3d(-0.5 * double(PI), 0.0, 0.0), extension_scale));
}
if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegY)) != 0) {
render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitY(), Vec3d(0.5 * double(PI), 0.0, 0.0), extension_scale));
render_extension(4, s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitY(), Vec3d(0.5 * double(PI), 0.0, 0.0), extension_scale));
}
if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::PosZ)) != 0) {
render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitZ(), Vec3d::Zero(), extension_scale));
render_extension(5, s_cone, extension_model_matrix_base * Geometry::assemble_transform(2.0 * extension_size * Vec3d::UnitZ(), Vec3d::Zero(), extension_scale));
}
if ((int(extensions) & int(GLGizmoBase::EGrabberExtension::NegZ)) != 0) {
render_extension(s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitZ(), Vec3d(double(PI), 0.0, 0.0), extension_scale));
render_extension(6, s_cone, extension_model_matrix_base * Geometry::assemble_transform(-2.0 * extension_size * Vec3d::UnitZ(), Vec3d(double(PI), 0.0, 0.0), extension_scale));
}
}
elements_registered_for_picking = true;
}
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
@ -299,10 +299,10 @@ void GLGizmoBase::GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float
m_imgui->set_next_window_pos(x, y, flag, pivot_x, pivot_y);
}
void GLGizmoBase::register_grabbers_for_picking(bool use_group_id)
void GLGizmoBase::register_grabbers_for_picking()
{
for (size_t i = 0; i < m_grabbers.size(); ++i) {
m_grabbers[i].register_raycasters_for_picking(use_group_id ? m_group_id : i);
m_grabbers[i].register_raycasters_for_picking((m_group_id >= 0) ? m_group_id : i);
}
}

View File

@ -37,6 +37,7 @@ public:
// Starting value for ids to avoid clashing with ids used by GLVolumes
// (254 is choosen to leave some space for forward compatibility)
static const unsigned int BASE_ID = 255 * 255 * 254;
static const unsigned int GRABBER_ELEMENTS_MAX_COUNT = 7;
static float INV_ZOOM;
@ -86,8 +87,8 @@ protected:
ColorRGBA hover_color{GRABBER_HOVER_COL};
EGrabberExtension extensions{ EGrabberExtension::None };
// the picking id shared by all the elements
int picking_id{ -1 };
bool elements_registered_for_picking{ false };
PickingId picking_id{ -1 };
std::array<std::shared_ptr<SceneRaycasterItem>, GRABBER_ELEMENTS_MAX_COUNT> raycasters = { nullptr };
Grabber() = default;
~Grabber();
@ -98,7 +99,7 @@ protected:
float get_dragging_half_size(float size) const;
PickingModel &get_cube();
void register_raycasters_for_picking(int id);
void register_raycasters_for_picking(PickingId id);
void unregister_raycasters_for_picking();
private:
@ -212,7 +213,7 @@ public:
int get_count() { return ++count; }
std::string get_gizmo_name() { return on_get_name(); }
void register_raycasters_for_picking(bool use_group_id = false) { register_grabbers_for_picking(use_group_id); on_register_raycasters_for_picking(); }
void register_raycasters_for_picking() { register_grabbers_for_picking(); on_register_raycasters_for_picking(); }
void unregister_raycasters_for_picking() { unregister_grabbers_for_picking(); on_unregister_raycasters_for_picking(); }
protected:
@ -238,7 +239,7 @@ protected:
void GizmoImguiEnd();
void GizmoImguiSetNextWIndowPos(float &x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
void register_grabbers_for_picking(bool use_group_id = false);
void register_grabbers_for_picking();
void unregister_grabbers_for_picking();
virtual void on_register_raycasters_for_picking() {}
virtual void on_unregister_raycasters_for_picking() {}

View File

@ -515,7 +515,7 @@ void GLGizmoRotate3D::on_register_raycasters_for_picking()
// the gizmo grabbers are rendered on top of the scene, so the raytraced picker should take it into account
m_parent.set_raycaster_gizmos_on_top(true);
for (GLGizmoRotate& g : m_gizmos) {
g.register_raycasters_for_picking(true);
g.register_raycasters_for_picking();
}
}

View File

@ -31,31 +31,22 @@ SceneRaycaster::SceneRaycaster() {
#endif // ENABLE_RAYCAST_PICKING_DEBUG
}
void SceneRaycaster::add_raycaster(EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo)
std::shared_ptr<SceneRaycasterItem> SceneRaycaster::add_raycaster(EType type, PickingId id, const MeshRaycaster& raycaster, const Transform3d& trafo)
{
switch (type) {
case EType::Bed: {
m_bed.emplace_back(encode_id(type, id), raycaster, trafo);
break;
}
case EType::Volume: {
m_volumes.emplace_back(encode_id(type, id), raycaster, trafo);
break;
}
case EType::Gizmo: {
m_gizmos.emplace_back(encode_id(type, id), raycaster, trafo);
break;
}
default: { break; }
case EType::Bed: { return m_bed.emplace_back(std::make_shared<SceneRaycasterItem>(encode_id(type, id), raycaster, trafo)); }
case EType::Volume: { return m_volumes.emplace_back(std::make_shared<SceneRaycasterItem>(encode_id(type, id), raycaster, trafo)); }
case EType::Gizmo: { return m_gizmos.emplace_back(std::make_shared<SceneRaycasterItem>(encode_id(type, id), raycaster, trafo)); }
default: { assert(false); return nullptr; }
};
}
void SceneRaycaster::remove_raycasters(EType type, PickingId id)
{
std::vector<SceneRaycasterItem>* raycasters = get_raycasters(type);
std::vector<std::shared_ptr<SceneRaycasterItem>>* raycasters = get_raycasters(type);
auto it = raycasters->begin();
while (it != raycasters->end()) {
if (it->get_id() == encode_id(type, id))
if ((*it)->get_id() == encode_id(type, id))
it = raycasters->erase(it);
else
++it;
@ -72,24 +63,24 @@ void SceneRaycaster::remove_raycasters(EType type)
};
}
void SceneRaycaster::set_raycaster_active_state(EType type, PickingId id, bool active)
void SceneRaycaster::remove_raycaster(std::shared_ptr<SceneRaycasterItem> item)
{
std::vector<SceneRaycasterItem>* raycasters = get_raycasters(type);
for (SceneRaycasterItem& item : *raycasters) {
if (item.get_id() == encode_id(type, id)) {
item.set_active(active);
break;
for (auto it = m_bed.begin(); it != m_bed.end(); ++it) {
if (*it == item) {
m_bed.erase(it);
return;
}
}
}
void SceneRaycaster::set_raycaster_transform(EType type, PickingId id, const Transform3d& trafo)
{
std::vector<SceneRaycasterItem>* raycasters = get_raycasters(type);
for (SceneRaycasterItem& item : *raycasters) {
if (item.get_id() == encode_id(type, id)) {
item.set_transform(trafo);
break;
for (auto it = m_volumes.begin(); it != m_volumes.end(); ++it) {
if (*it == item) {
m_volumes.erase(it);
return;
}
}
for (auto it = m_gizmos.begin(); it != m_gizmos.end(); ++it) {
if (*it == item) {
m_gizmos.erase(it);
return;
}
}
}
@ -113,15 +104,15 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came
auto test_raycasters = [&](EType type) {
const ClippingPlane* clip_plane = (clipping_plane != nullptr && type == EType::Volume) ? clipping_plane : nullptr;
const std::vector<SceneRaycasterItem>* raycasters = get_raycasters(type);
std::vector<std::shared_ptr<SceneRaycasterItem>>* raycasters = get_raycasters(type);
HitResult current_hit = { type };
for (const SceneRaycasterItem& item : *raycasters) {
if (!item.is_active())
for (std::shared_ptr<SceneRaycasterItem> item : *raycasters) {
if (!item->is_active())
continue;
current_hit.raycaster_id = item.get_id();
const Transform3d& trafo = item.get_transform();
if (item.get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) {
current_hit.raycaster_id = item->get_id();
const Transform3d& trafo = item->get_transform();
if (item->get_raycaster()->closest_hit(mouse_pos, trafo, camera, current_hit.position, current_hit.normal, clip_plane)) {
current_hit.position = (trafo * current_hit.position.cast<double>()).cast<float>();
if (is_closest(camera, current_hit.position)) {
const Transform3d matrix = camera.get_view_matrix() * trafo;
@ -180,14 +171,15 @@ void SceneRaycaster::render_hit(const Camera& camera)
}
#endif // ENABLE_RAYCAST_PICKING_DEBUG
std::vector<SceneRaycasterItem>* SceneRaycaster::get_raycasters(EType type)
std::vector<std::shared_ptr<SceneRaycasterItem>>* SceneRaycaster::get_raycasters(EType type)
{
std::vector<SceneRaycasterItem>* ret = nullptr;
std::vector<std::shared_ptr<SceneRaycasterItem>>* ret = nullptr;
switch (type)
{
case EType::Bed: { ret = &m_bed; break; }
case EType::Volume: { ret = &m_volumes; break; }
case EType::Gizmo: { ret = &m_gizmos; break; }
default: { break; }
}
assert(ret != nullptr);
return ret;

View File

@ -64,9 +64,9 @@ public:
};
private:
std::vector<SceneRaycasterItem> m_bed;
std::vector<SceneRaycasterItem> m_volumes;
std::vector<SceneRaycasterItem> m_gizmos;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_bed;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_volumes;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_gizmos;
// When set to true, if checking gizmos returns a valid hit,
// the search is not performed on other types
@ -81,12 +81,10 @@ private:
public:
SceneRaycaster();
void add_raycaster(EType type, PickingId picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo);
std::shared_ptr<SceneRaycasterItem> add_raycaster(EType type, PickingId picking_id, const MeshRaycaster& raycaster, const Transform3d& trafo);
void remove_raycasters(EType type, PickingId id);
void remove_raycasters(EType type);
void set_raycaster_active_state(EType type, PickingId picking_id, bool active);
void set_raycaster_transform(EType type, PickingId picking_id, const Transform3d& trafo);
void remove_raycaster(std::shared_ptr<SceneRaycasterItem> item);
void set_gizmos_on_top(bool value) { m_gizmos_on_top = value; }
@ -101,7 +99,7 @@ public:
#endif // ENABLE_RAYCAST_PICKING_DEBUG
private:
std::vector<SceneRaycasterItem>* get_raycasters(EType type);
std::vector<std::shared_ptr<SceneRaycasterItem>>* get_raycasters(EType type);
static PickingId encode_id(EType type, PickingId id);
static PickingId decode_id(EType type, PickingId id);