diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
index cbbe279346..6a4aa40955 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp
@@ -167,6 +167,19 @@ static void start_create_volume_job(const ModelObject *object,
static GLVolume *get_hovered_gl_volume(const GLCanvas3D &canvas);
+///
+/// Unproject on mesh by Mesh raycasters
+///
+/// Position of mouse on screen
+/// Projection params
+/// Define which caster will be skipped, null mean no skip
+/// Position on surface, normal direction in world coorinate
+/// + key, to know hitted instance and volume
+static std::optional ray_from_camera(const RaycastManager &raycaster,
+ const Vec2d &mouse_pos,
+ const Camera &camera,
+ const RaycastManager::ISkip *skip);
+
///
/// Start job for add new volume on surface of object defined by screen coor
///
@@ -175,12 +188,14 @@ static GLVolume *get_hovered_gl_volume(const GLCanvas3D &canvas);
/// Mouse position which define position
/// Volume to find surface for create
/// Ability to ray cast to model
+/// Contain already used scene RayCasters
/// True when start creation, False when there is no hit surface by screen coor
static bool start_create_volume_on_surface_job(DataBase &emboss_data,
ModelVolumeType volume_type,
const Vec2d &screen_coor,
const GLVolume *gl_volume,
- RaycastManager &raycaster);
+ RaycastManager &raycaster,
+ GLCanvas3D &canvas);
///
/// Find volume in selected object with closest convex hull to screen center.
@@ -235,7 +250,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
DataBase emboss_data = priv::create_emboss_data_base(m_text, m_style_manager, m_job_cancel);
if (gl_volume != nullptr) {
// Try to cast ray into scene and find object for add volume
- if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, mouse_pos, gl_volume, m_raycast_manager)) {
+ if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, mouse_pos, gl_volume, m_raycast_manager, m_parent)) {
// When model is broken. It could appear that hit miss the object.
// So add part near by in simmilar manner as right panel do
create_volume(volume_type);
@@ -276,7 +291,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type)
priv::find_closest_volume(selection, screen_center, camera, objects, &coor, &vol);
if (vol == nullptr) {
priv::start_create_object_job(emboss_data, screen_center);
- } else if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, coor, vol, m_raycast_manager)) {
+ } else if (!priv::start_create_volume_on_surface_job(emboss_data, volume_type, coor, vol, m_raycast_manager, m_parent)) {
// in centroid of convex hull is not hit with object
// soo create transfomation on border of object
@@ -499,6 +514,29 @@ static std::optional calc_scale(const Matrix3d &from, const Matrix3d &to
return {}; // no scale
return sqrt(from_scale_sq / to_scale_sq);
};
+
+RaycastManager::Meshes create_meshes(GLCanvas3D &canvas, const RaycastManager::AllowVolumes& condition)
+{
+ SceneRaycaster::EType type = SceneRaycaster::EType::Volume;
+ auto scene_casters = canvas.get_raycasters_for_picking(type);
+ const std::vector> &casters = *scene_casters;
+ const GLVolumePtrs &gl_volumes = canvas.get_volumes().volumes;
+ const ModelObjectPtrs &objects = canvas.get_model()->objects;
+
+ RaycastManager::Meshes meshes;
+ for (const std::shared_ptr &caster : casters) {
+ int index = SceneRaycaster::decode_id(type, caster->get_id());
+ if (index < 0 || index >= gl_volumes.size()) continue;
+ const GLVolume *gl_volume = gl_volumes[index];
+ const ModelVolume *volume = priv::get_model_volume(gl_volume, objects);
+ size_t id = volume->id().id;
+ if (condition.skip(id))
+ continue;
+ auto mesh = std::make_unique(caster->get_raycaster()->get_aabb_mesh());
+ meshes.emplace_back(std::make_pair(id, std::move(mesh)));
+ }
+ return meshes;
+}
}
bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
@@ -568,12 +606,12 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
allowed_volumes_id.emplace_back(v->id().id);
}
}
- RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
-
+ RaycastManager::AllowVolumes condition(std::move(allowed_volumes_id));
+ RaycastManager::Meshes meshes = priv::create_meshes(m_parent, condition);
// initialize raycasters
// INFO: It could slows down for big objects
// (may be move to thread and do not show drag until it finish)
- m_raycast_manager.actualize(instance, &condition);
+ m_raycast_manager.actualize(instance, &condition, &meshes);
// wxCoord == int --> wx/types.h
Vec2i mouse_coord(mouse_event.GetX(), mouse_event.GetY());
@@ -609,7 +647,7 @@ bool GLGizmoEmboss::on_mouse_for_translate(const wxMouseEvent &mouse_event)
Vec2d mouse_pos = mouse_coord.cast();
Vec2d offseted_mouse = mouse_pos + m_surface_drag->mouse_offset;
const Camera &camera = wxGetApp().plater()->get_camera();
- auto hit = m_raycast_manager.ray_from_camera(offseted_mouse, camera, &m_surface_drag->condition);
+ auto hit = priv::ray_from_camera(m_raycast_manager, offseted_mouse, camera, &m_surface_drag->condition);
m_surface_drag->exist_hit = hit.has_value();
if (!hit.has_value()) {
// cross hair need redraw
@@ -3255,7 +3293,7 @@ std::optional priv::calc_surface_offset(const ModelVolume &volume, Raycas
Vec3d direction = to_world.linear() * (-Vec3d::UnitZ());
// ray in direction of text projection(from volume zero to z-dir)
- std::optional hit_opt = raycast_manager.unproject(point, direction, &cond);
+ std::optional hit_opt = raycast_manager.closest_hit(point, direction, &cond);
// Try to find closest point when no hit object in emboss direction
if (!hit_opt.has_value()) {
@@ -3981,8 +4019,19 @@ GLVolume * priv::get_hovered_gl_volume(const GLCanvas3D &canvas) {
return volumes[hovered_id];
}
+std::optional priv::ray_from_camera(const RaycastManager &raycaster,
+ const Vec2d &mouse_pos,
+ const Camera &camera,
+ const RaycastManager::ISkip *skip)
+{
+ Vec3d point;
+ Vec3d direction;
+ CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction);
+ return raycaster.first_hit(point, direction, skip);
+}
+
bool priv::start_create_volume_on_surface_job(
- DataBase &emboss_data, ModelVolumeType volume_type, const Vec2d &screen_coor, const GLVolume *gl_volume, RaycastManager &raycaster)
+ DataBase &emboss_data, ModelVolumeType volume_type, const Vec2d &screen_coor, const GLVolume *gl_volume, RaycastManager &raycaster, GLCanvas3D& canvas)
{
assert(gl_volume != nullptr);
if (gl_volume == nullptr) return false;
@@ -3995,10 +4044,12 @@ bool priv::start_create_volume_on_surface_job(
ModelObject *obj = objects[object_idx];
size_t vol_id = obj->volumes[gl_volume->volume_idx()]->id().id;
auto cond = RaycastManager::AllowVolumes({vol_id});
- raycaster.actualize(obj, &cond);
+
+ RaycastManager::Meshes meshes = priv::create_meshes(canvas, cond);
+ raycaster.actualize(obj, &cond, &meshes);
const Camera &camera = plater->get_camera();
- std::optional hit = raycaster.ray_from_camera(screen_coor, camera, &cond);
+ std::optional hit = priv::ray_from_camera(raycaster, screen_coor, camera, &cond);
// context menu for add text could be open only by right click on an
// object. After right click, object is selected and object_idx is set
diff --git a/src/slic3r/Utils/RaycastManager.cpp b/src/slic3r/Utils/RaycastManager.cpp
index 3f34c37fcd..3b0ace2a34 100644
--- a/src/slic3r/Utils/RaycastManager.cpp
+++ b/src/slic3r/Utils/RaycastManager.cpp
@@ -1,16 +1,11 @@
#include "RaycastManager.hpp"
#include
-// include for earn camera
-#include "slic3r/GUI/GUI_App.hpp"
-#include "slic3r/GUI/Plater.hpp"
-#include "slic3r/GUI/CameraUtils.hpp"
-
using namespace Slic3r::GUI;
namespace priv {
using namespace Slic3r;
-static void actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip);
+static void actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip, RaycastManager::Meshes *input = nullptr);
static const AABBMesh * get_mesh(const RaycastManager::Meshes &meshes, size_t volume_id);
static RaycastManager::TrKey create_key(const ModelVolume* volume, const ModelInstance* instance){
return std::make_pair(instance->id().id, volume->id().id); }
@@ -21,10 +16,10 @@ static bool is_lower(const RaycastManager::TrItem &i1, const RaycastManager::TrI
return is_lower_key(i1.first, i2.first); };
}
-void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
+void RaycastManager::actualize(const ModelObject *object, const ISkip *skip, Meshes *meshes)
{
// actualize MeshRaycaster
- priv::actualize(m_meshes, object->volumes, skip);
+ priv::actualize(m_meshes, object->volumes, skip, meshes);
// check if inscance was removed
std::vector removed_transf(m_transformations.size(), {true});
@@ -61,11 +56,12 @@ void RaycastManager::actualize(const ModelObject *object, const ISkip *skip)
std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower);
}
-void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip) {
+void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip, Meshes *meshes)
+{
const ModelVolumePtrs &volumes = instance->get_object()->volumes;
// actualize MeshRaycaster
- priv::actualize(m_meshes, volumes, skip);
+ priv::actualize(m_meshes, volumes, skip, meshes);
// check if inscance was removed
std::vector removed_transf(m_transformations.size(), {true});
@@ -101,11 +97,9 @@ void RaycastManager::actualize(const ModelInstance *instance, const ISkip *skip)
std::sort(m_transformations.begin(), m_transformations.end(), priv::is_lower);
}
-std::optional RaycastManager::ray_from_camera(
- const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip) const
+std::optional RaycastManager::first_hit(const Vec3d& point, const Vec3d& direction, const ISkip *skip) const
{
- // Improve it is not neccessaru to use AABBMesh and calc normal in
-
+ // Improve: it is not neccessaru to use AABBMesh and calc normal for every hit
struct Result
{
const AABBMesh *mesh = nullptr;
@@ -115,6 +109,7 @@ std::optional RaycastManager::ray_from_camera(
const Transform3d *tramsformation;
const TrKey *key;
}result;
+
for (const auto &item : m_transformations) {
const TrKey &key = item.first;
size_t volume_id = key.second;
@@ -122,24 +117,23 @@ std::optional RaycastManager::ray_from_camera(
const AABBMesh *mesh = priv::get_mesh(m_meshes, volume_id);
if (mesh == nullptr) continue;
const Transform3d &transformation = item.second;
-
- Vec3d point;
- Vec3d direction;
- CameraUtils::ray_from_screen_pos(camera, mouse_pos, point, direction);
Transform3d inv = transformation.inverse();
- point = inv * point;
- direction = inv.linear() * direction;
- std::vector hits = mesh->query_ray_hits(point, direction);
+
+ // transform input into mesh world
+ Vec3d point_ = inv * point;
+ Vec3d direction_= inv.linear() * direction;
+
+ std::vector hits = mesh->query_ray_hits(point_, direction_);
if (hits.empty()) continue; // no intersection found
const AABBMesh::hit_result &hit = hits.front();
// convert to world
Vec3d hit_world = transformation * hit.position();
- double squared_distance = (camera.get_position() - hit_world).squaredNorm();
+ double squared_distance = (point - hit_world).squaredNorm();
if (result.mesh != nullptr &&
result.squared_distance < squared_distance)
- continue;
+ continue; // exist closer one
result.mesh = mesh;
result.squared_distance = squared_distance;
@@ -152,6 +146,8 @@ std::optional RaycastManager::ray_from_camera(
if (result.mesh == nullptr)
return {};
+ // Calculate normal from transformed triangle
+ // NOTE: Anisotropic transformation of normal is not perpendiculat to triangle
const Vec3i tri = result.mesh->indices(result.face);
Vec3d pts[3];
auto tr = result.tramsformation->linear();
@@ -164,7 +160,7 @@ std::optional RaycastManager::ray_from_camera(
return RaycastManager::Hit{point_world, *result.key, result.squared_distance};
}
-std::optional RaycastManager::unproject(const Vec3d &point, const Vec3d &direction, const ISkip *skip) const
+std::optional RaycastManager::closest_hit(const Vec3d &point, const Vec3d &direction, const ISkip *skip) const
{
std::optional closest;
for (const auto &item : m_transformations) {
@@ -236,7 +232,7 @@ Slic3r::Transform3d RaycastManager::get_transformation(const TrKey &tr_key) cons
return item->second;
}
-void priv::actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip)
+void priv::actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volumes, const RaycastManager::ISkip *skip, RaycastManager::Meshes* inputs)
{
// check if volume was removed
std::vector removed_meshes(meshes.size(), {true});
@@ -248,6 +244,16 @@ void priv::actualize(RaycastManager::Meshes &meshes, const ModelVolumePtrs &volu
continue;
auto item = std::find_if(meshes.begin(), meshes.end(), [oid](const RaycastManager::Mesh &it) -> bool { return oid == it.first; });
if (item == meshes.end()) {
+ // exist AABB in inputs ?
+ if (inputs != nullptr) {
+ auto input = std::find_if(inputs->begin(), inputs->end(),
+ [oid](const RaycastManager::Mesh &it) -> bool { return oid == it.first; });
+ if (input != inputs->end()) {
+ meshes.emplace_back(std::move(*input));
+ continue;
+ }
+ }
+
// add new raycaster
bool calculate_epsilon = true;
auto mesh = std::make_unique(volume->mesh(), calculate_epsilon);
diff --git a/src/slic3r/Utils/RaycastManager.hpp b/src/slic3r/Utils/RaycastManager.hpp
index 5bd28d00a6..4ef9b7ca76 100644
--- a/src/slic3r/Utils/RaycastManager.hpp
+++ b/src/slic3r/Utils/RaycastManager.hpp
@@ -7,7 +7,6 @@
#include "libslic3r/Point.hpp" // Transform3d
#include "libslic3r/ObjectID.hpp"
#include "libslic3r/Model.hpp" // ModelObjectPtrs, ModelObject, ModelInstance, ModelVolume
-#include "slic3r/GUI/Camera.hpp"
namespace Slic3r::GUI{
@@ -86,8 +85,9 @@ public:
///
/// Model representation
/// Condifiton for skip actualization
- void actualize(const ModelObject *object, const ISkip *skip = nullptr);
- void actualize(const ModelInstance *instance, const ISkip *skip = nullptr);
+ /// Speed up for already created AABBtrees
+ void actualize(const ModelObject *object, const ISkip *skip = nullptr, Meshes *meshes = nullptr);
+ void actualize(const ModelInstance *instance, const ISkip *skip = nullptr, Meshes* meshes = nullptr);
class SkipVolume: public ISkip
{
@@ -109,24 +109,24 @@ public:
};
///
- /// Unproject on mesh by Mesh raycasters
+ /// Unproject on mesh and return closest hit to point in given direction
///
- /// Position of mouse on screen
- /// Projection params
+ /// Position in space
+ /// Casted ray direction
/// Define which caster will be skipped, null mean no skip
/// Position on surface, normal direction in world coorinate
/// + key, to know hitted instance and volume
- std::optional ray_from_camera(const Vec2d &mouse_pos, const Camera &camera, const ISkip *skip = nullptr) const;
+ std::optional first_hit(const Vec3d &point, const Vec3d &direction, const ISkip *skip = nullptr) const;
///
- /// Unproject Ray(point direction) on mesh by MeshRaycasters
+ /// Unproject Ray(point direction) on mesh to find closest hit of surface in given direction
/// NOTE: It inspect also oposit direction of ray !!
///
/// Start point for ray
- /// Direction of ray
+ /// Direction of ray, orientation doesn't matter, both are used
/// Define which caster will be skipped, null mean no skip
/// Position on surface, normal direction and transformation key, which define hitted object instance
- std::optional unproject(const Vec3d &point, const Vec3d &direction, const ISkip *skip = nullptr) const;
+ std::optional closest_hit(const Vec3d &point, const Vec3d &direction, const ISkip *skip = nullptr) const;
///
/// Search of closest point