Cherry-picking 118f4859c472ccbc30b43101c6674dadc81d7b12

And resolve conflicts
This commit is contained in:
tamasmeszaros 2022-11-04 12:42:02 +01:00
parent ce5d242f76
commit f100a59688
19 changed files with 674 additions and 735 deletions

View File

@ -0,0 +1,17 @@
#version 110
uniform vec4 uniform_color;
uniform float emission_factor;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
if (clipping_planes_dot < 0.0)
discard;
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@ -0,0 +1,54 @@
#version 110
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
attribute vec3 v_position;
attribute vec3 v_normal;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 eye_normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 eye_position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * eye_position;
// Fill in the scalar for fragment shader clipping. Fragments with this value lower than zero are discarded.
clipping_planes_dot = dot(volume_world_matrix * vec4(v_position, 1.0), clipping_plane);
}

View File

@ -0,0 +1,19 @@
#version 140
uniform vec4 uniform_color;
uniform float emission_factor;
// x = tainted, y = specular;
in vec2 intensity;
in float clipping_planes_dot;
out vec4 out_color;
void main()
{
if (clipping_planes_dot < 0.0)
discard;
out_color = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@ -0,0 +1,54 @@
#version 140
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
in vec3 v_position;
in vec3 v_normal;
// x = tainted, y = specular;
out vec2 intensity;
out float clipping_planes_dot;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 eye_normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 eye_position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * eye_position;
// Fill in the scalar for fragment shader clipping. Fragments with this value lower than zero are discarded.
clipping_planes_dot = dot(volume_world_matrix * vec4(v_position, 1.0), clipping_plane);
}

View File

@ -0,0 +1,19 @@
#version 100
precision highp float;
uniform vec4 uniform_color;
uniform float emission_factor;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
if (clipping_planes_dot < 0.0)
discard;
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * (intensity.x + emission_factor), uniform_color.a);
}

View File

@ -0,0 +1,54 @@
#version 100
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
uniform mat4 view_model_matrix;
uniform mat4 projection_matrix;
uniform mat3 view_normal_matrix;
uniform mat4 volume_world_matrix;
// Clipping plane - general orientation. Used by the SLA gizmo.
uniform vec4 clipping_plane;
attribute vec3 v_position;
attribute vec3 v_normal;
// x = tainted, y = specular;
varying vec2 intensity;
varying float clipping_planes_dot;
void main()
{
// First transform the normal into camera space and normalize the result.
vec3 eye_normal = normalize(view_normal_matrix * v_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec4 eye_position = view_model_matrix * vec4(v_position, 1.0);
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(eye_position.xyz), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
gl_Position = projection_matrix * eye_position;
// Fill in the scalar for fragment shader clipping. Fragments with this value lower than zero are discarded.
clipping_planes_dot = dot(volume_world_matrix * vec4(v_position, 1.0), clipping_plane);
}

View File

@ -476,6 +476,11 @@ public:
const PrintObjects& objects() const { return m_objects; }
// PrintObject by its ObjectID, to be used to uniquely bind slicing warnings to their source PrintObjects
// in the notification center.
const SLAPrintObject* get_print_object_by_model_object_id(ObjectID object_id) const {
auto it = std::find_if(m_objects.begin(), m_objects.end(),
[object_id](const SLAPrintObject* obj) { return obj->model_object()->id() == object_id; });
return (it == m_objects.end()) ? nullptr : *it;
}
const SLAPrintObject* get_object(ObjectID object_id) const {
auto it = std::find_if(m_objects.begin(), m_objects.end(),
[object_id](const SLAPrintObject *obj) { return obj->id() == object_id; });

View File

@ -852,74 +852,6 @@ int GLVolumeCollection::load_object_volume(
return int(this->volumes.size() - 1);
}
//// Load SLA auxiliary GLVolumes (for support trees or pad).
//// This function produces volumes for multiple instances in a single shot,
//// as some object specific mesh conversions may be expensive.
//#if ENABLE_LEGACY_OPENGL_REMOVAL
//void GLVolumeCollection::load_object_auxiliary(
// const SLAPrintObject* print_object,
// int obj_idx,
// // pairs of <instance_idx, print_instance_idx>
// const std::vector<std::pair<size_t, size_t>>& instances,
// SLAPrintObjectStep milestone,
// // Timestamp of the last change of the milestone
// size_t timestamp)
//#else
//void GLVolumeCollection::load_object_auxiliary(
// const SLAPrintObject *print_object,
// int obj_idx,
// // pairs of <instance_idx, print_instance_idx>
// const std::vector<std::pair<size_t, size_t>>& instances,
// SLAPrintObjectStep milestone,
// // Timestamp of the last change of the milestone
// size_t timestamp,
// bool opengl_initialized)
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
//{
// assert(print_object->is_step_done(milestone));
// Transform3d mesh_trafo_inv = print_object->trafo().inverse();
// // Get the support mesh.
// TriangleMesh mesh = print_object->get_mesh(milestone);
// mesh.transform(mesh_trafo_inv);
// // Convex hull is required for out of print bed detection.
// TriangleMesh convex_hull = mesh.convex_hull_3d();
// for (const std::pair<size_t, size_t>& instance_idx : instances) {
// const ModelInstance& model_instance = *print_object->model_object()->instances[instance_idx.first];
// this->volumes.emplace_back(new GLVolume((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
// GLVolume& v = *this->volumes.back();
//#if ENABLE_LEGACY_OPENGL_REMOVAL
//#if ENABLE_SMOOTH_NORMALS
// v.model.init_from(mesh, true);
//#else
// v.model.init_from(mesh);
// v.model.set_color((milestone == slaposPad) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR);
//#if ENABLE_RAYCAST_PICKING
// v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(mesh));
//#endif // ENABLE_RAYCAST_PICKING
//#endif // ENABLE_SMOOTH_NORMALS
//#else
//#if ENABLE_SMOOTH_NORMALS
// v.indexed_vertex_array.load_mesh(mesh, true);
//#else
// v.indexed_vertex_array.load_mesh(mesh);
//#endif // ENABLE_SMOOTH_NORMALS
// v.indexed_vertex_array.finalize_geometry(opengl_initialized);
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
// v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
// // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
// if (&instance_idx == &instances.back())
// v.set_convex_hull(std::move(convex_hull));
// else
// v.set_convex_hull(convex_hull);
// v.is_modifier = false;
// v.shader_outside_printer_detection_enabled = (milestone == slaposSupportTree);
// v.set_instance_transformation(model_instance.get_transformation());
// // Leave the volume transformation at identity.
// // v.set_volume_transformation(model_volume->get_transformation());
// }
//}
#if ENABLE_LEGACY_OPENGL_REMOVAL
#if ENABLE_OPENGL_ES
int GLVolumeCollection::load_wipe_tower_preview(

View File

@ -658,16 +658,6 @@ public:
int volume_idx,
int instance_idx);
// Load SLA auxiliary GLVolumes (for support trees or pad).
// void load_object_auxiliary(
// const SLAPrintObject* print_object,
// int obj_idx,
// // pairs of <instance_idx, print_instance_idx>
// const std::vector<std::pair<size_t, size_t>>& instances,
// SLAPrintObjectStep milestone,
// // Timestamp of the last change of the milestone
// size_t timestamp);
#if ENABLE_OPENGL_ES
int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr);
@ -689,17 +679,6 @@ public:
int instance_idx,
bool opengl_initialized);
// Load SLA auxiliary GLVolumes (for support trees or pad).
void load_object_auxiliary(
const SLAPrintObject *print_object,
int obj_idx,
// pairs of <instance_idx, print_instance_idx>
const std::vector<std::pair<size_t, size_t>>& instances,
SLAPrintObjectStep milestone,
// Timestamp of the last change of the milestone
size_t timestamp,
bool opengl_initialized);
int load_wipe_tower_preview(
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
#endif // ENABLE_LEGACY_OPENGL_REMOVAL

View File

@ -2011,15 +2011,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
size_t volume_idx;
};
// // SLA steps to pull the preview meshes for.
// typedef std::array<SLAPrintObjectStep, 3> SLASteps;
// SLASteps sla_steps = { slaposDrillHoles, slaposSupportTree, slaposPad };
// struct SLASupportState {
// std::array<PrintStateBase::StateWithTimeStamp, std::tuple_size<SLASteps>::value> step;
// };
// // State of the sla_steps for all SLAPrintObjects.
// std::vector<SLASupportState> sla_support_state;
std::vector<size_t> instance_ids_selected;
std::vector<size_t> map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1));
std::vector<GLVolumeState> deleted_volumes;
@ -2044,33 +2035,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
}
}
}
// if (printer_technology == ptSLA) {
// const SLAPrint* sla_print = this->sla_print();
//#ifndef NDEBUG
// // Verify that the SLAPrint object is synchronized with m_model.
// check_model_ids_equal(*m_model, sla_print->model());
//#endif /* NDEBUG */
// sla_support_state.reserve(sla_print->objects().size());
// for (const SLAPrintObject* print_object : sla_print->objects()) {
// SLASupportState state;
// for (size_t istep = 0; istep < sla_steps.size(); ++istep) {
// state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]);
// if (state.step[istep].state == PrintStateBase::DONE) {
// if (!print_object->has_mesh(sla_steps[istep]))
// // Consider the DONE step without a valid mesh as invalid for the purpose
// // of mesh visualization.
// state.step[istep].state = PrintStateBase::INVALID;
// else if (sla_steps[istep] != slaposDrillHoles)
// for (const ModelInstance* model_instance : print_object->model_object()->instances)
// // Only the instances, which are currently printable, will have the SLA support structures kept.
// // The instances outside the print bed will have the GLVolumes of their support structures released.
// if (model_instance->is_printable())
// aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id());
// }
// }
// sla_support_state.emplace_back(state);
// }
// }
std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower);
std::sort(aux_volume_state.begin(), aux_volume_state.end(), model_volume_state_lower);
// Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh.
@ -2190,139 +2155,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
}
if (printer_technology == ptSLA) {
// size_t idx = 0;
// const SLAPrint *sla_print = this->sla_print();
// std::vector<double> shift_zs(m_model->objects.size(), 0);
// double relative_correction_z = sla_print->relative_correction().z();
// if (relative_correction_z <= EPSILON)
// relative_correction_z = 1.;
// for (const SLAPrintObject *print_object : sla_print->objects()) {
// SLASupportState &state = sla_support_state[idx ++];
// const ModelObject *model_object = print_object->model_object();
// // Find an index of the ModelObject
// int object_idx;
// // There may be new SLA volumes added to the scene for this print_object.
// // Find the object index of this print_object in the Model::objects list.
// auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
// assert(it != sla_print->model().objects.end());
// object_idx = it - sla_print->model().objects.begin();
// // Cache the Z offset to be applied to all volumes with this object_idx.
// shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
// // Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
// // pairs of <instance_idx, print_instance_idx>
// std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
// for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) {
// const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx];
// // Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
// auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
// [&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; });
// assert(it != model_object->instances.end());
// int instance_idx = it - model_object->instances.begin();
// for (size_t istep = 0; istep < sla_steps.size(); ++ istep)
// if (sla_steps[istep] == slaposDrillHoles) {
// // Hollowing is a special case, where the mesh from the backend is being loaded into the 1st volume of an instance,
// // not into its own GLVolume.
// // There shall always be such a GLVolume allocated.
// ModelVolumeState key(model_object->volumes.front()->id(), instance.instance_id);
// auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
// assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
// assert(!it->new_geometry());
// GLVolume &volume = *m_volumes.volumes[it->volume_idx];
// if (! volume.offsets.empty() && state.step[istep].timestamp != volume.offsets.front()) {
// // The backend either produced a new hollowed mesh, or it invalidated the one that the front end has seen.
//#if ENABLE_LEGACY_OPENGL_REMOVAL
// volume.model.reset();
//#else
// volume.indexed_vertex_array.release_geometry();
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// if (state.step[istep].state == PrintStateBase::DONE) {
// TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles);
// assert(! mesh.empty());
// // sla_trafo does not contain volume trafo. To get a mesh to create
// // a new volume from, we have to apply vol trafo inverse separately.
// const ModelObject& mo = *m_model->objects[volume.object_idx()];
// Transform3d trafo = sla_print->sla_trafo(mo)
// * mo.volumes.front()->get_transformation().get_matrix();
// mesh.transform(trafo.inverse());
//#if ENABLE_SMOOTH_NORMALS
//#if ENABLE_LEGACY_OPENGL_REMOVAL
// volume.model.init_from(mesh, true);
//#else
// volume.indexed_vertex_array.load_mesh(mesh, true);
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
//#else
//#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));
//#endif // ENABLE_RAYCAST_PICKING
//#else
// volume.indexed_vertex_array.load_mesh(mesh);
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
//#endif // ENABLE_SMOOTH_NORMALS
// }
// else {
// // Reload the original volume.
//#if ENABLE_SMOOTH_NORMALS
//#if ENABLE_LEGACY_OPENGL_REMOVAL
// volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
//#else
// volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
//#else
//#if ENABLE_LEGACY_OPENGL_REMOVAL
//#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));
//#else
// volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
//#endif // ENABLE_RAYCAST_PICKING
//#else
// volume.indexed_vertex_array.load_mesh(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh());
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
//#endif // ENABLE_SMOOTH_NORMALS
// }
//#if !ENABLE_LEGACY_OPENGL_REMOVAL
// volume.finalize_geometry(true);
//#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
// }
// //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable
// // to the GLVolume. We should refactor GLVolume significantly, so that the GLVolume will not contain member variables
// // of various concenrs (model vs. 3D print path).
// volume.offsets = { state.step[istep].timestamp };
// }
// else if (state.step[istep].state == PrintStateBase::DONE) {
// // Check whether there is an existing auxiliary volume to be updated, or a new auxiliary volume to be created.
// ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
// auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
// assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
// if (it->new_geometry()) {
// // This can be an SLA support structure that should not be rendered (in case someone used undo
// // to revert to before it was generated). If that's the case, we should not generate anything.
// if (model_object->sla_points_status != sla::PointsStatus::NoPoints)
// instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
// else
// shift_zs[object_idx] = 0.;
// }
// else {
// // Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
// m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
// m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
// }
// }
// }
// for (size_t istep = 0; istep < sla_steps.size(); ++istep)
// if (!instances[istep].empty())
//#if ENABLE_LEGACY_OPENGL_REMOVAL
// m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
//#else
// m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
//#endif // ENABLE_LEGACY_OPENGL_REMOVAL
// }
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
for (GLVolume* volume : m_volumes.volumes)
if (volume->object_idx() < (int)m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable()) {
@ -7638,25 +7470,24 @@ void GLCanvas3D::_load_sla_shells()
};
// adds objects' volumes
for (const SLAPrintObject* obj : print->objects())
/*if (obj->is_step_done(slaposSliceSupports))*/ {
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
for (const SLAPrintObject::Instance& instance : obj->instances()) {
add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true);
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
// through the update_volumes_colors_by_extruder() call.
m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id();
if (auto &tree_mesh = obj->support_mesh(); !tree_mesh.empty())
add_volume(*obj, -int(slaposSupportTree), instance, tree_mesh, GLVolume::SLA_SUPPORT_COLOR, true);
if (auto &pad_mesh = obj->pad_mesh(); !pad_mesh.empty())
add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false);
}
double shift_z = obj->get_current_elevation();
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
// apply shift z
m_volumes.volumes[i]->set_sla_shift_z(shift_z);
}
for (const SLAPrintObject* obj : print->objects()) {
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
for (const SLAPrintObject::Instance& instance : obj->instances()) {
add_volume(*obj, 0, instance, obj->get_mesh_to_print(), GLVolume::MODEL_COLOR[0], true);
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
// through the update_volumes_colors_by_extruder() call.
m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id();
if (auto &tree_mesh = obj->support_mesh(); !tree_mesh.empty())
add_volume(*obj, -int(slaposSupportTree), instance, tree_mesh, GLVolume::SLA_SUPPORT_COLOR, true);
if (auto &pad_mesh = obj->pad_mesh(); !pad_mesh.empty())
add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false);
}
double shift_z = obj->get_current_elevation();
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
// apply shift z
m_volumes.volumes[i]->set_sla_shift_z(shift_z);
}
}
update_volumes_colors_by_extruder();
}

View File

@ -688,8 +688,6 @@ public:
void set_raycaster_gizmos_on_top(bool value) {
m_scene_raycaster.set_gizmos_on_top(value);
}
const SceneRaycaster & raycaster() const { return m_scene_raycaster; }
#endif // ENABLE_RAYCAST_PICKING
void set_as_dirty();

View File

@ -72,6 +72,8 @@ std::pair<bool, std::string> GLShadersManager::init()
#if ENABLE_LEGACY_OPENGL_REMOVAL
// used to render bed axes and model, selection hints, gcode sequential view marker model, preview shells, options in gcode preview
valid &= append_shader("gouraud_light", { prefix + "gouraud_light.vs", prefix + "gouraud_light.fs" });
// extend "gouraud_light" by adding clipping, used in sla gizmos
valid &= append_shader("gouraud_light_clip", { prefix + "gouraud_light_clip.vs", prefix + "gouraud_light_clip.fs" });
// used to render printbed
valid &= append_shader("printbed", { prefix + "printbed.vs", prefix + "printbed.fs" });
#else

View File

@ -10,6 +10,7 @@
#include "slic3r/GUI/GUI_ObjectList.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "libslic3r/SLAPrint.hpp"
#include "libslic3r/Model.hpp"
@ -53,14 +54,21 @@ void GLGizmoHollow::data_changed()
reload_cache();
m_old_mo_id = mo->id();
}
// if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh())
// m_holes_in_drilled_mesh = mo->sla_drain_holes;
const SLAPrintObject* po = m_c->selection_info()->print_object();
if (po != nullptr && po->get_mesh_to_print().empty())
process_mesh(slaposAssembly);
update_volumes();
#if ENABLE_RAYCAST_PICKING
if (m_raycasters.empty())
on_register_raycasters_for_picking();
if (m_hole_raycasters.empty())
register_hole_raycasters_for_picking();
else
update_raycasters_for_picking_transform();
update_hole_raycasters_for_picking_transform();
#endif // ENABLE_RAYCAST_PICKING
m_c->instances_hider()->set_hide_full_scene(true);
}
}
@ -87,16 +95,15 @@ void GLGizmoHollow::on_render()
glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST));
if (selection.is_from_single_instance())
#if ENABLE_RAYCAST_PICKING
render_points(selection);
render_volumes();
render_points(selection);
#else
render_points(selection, false);
render_points(selection, false);
#endif // ENABLE_RAYCAST_PICKING
m_selection_rectangle.render(m_parent);
m_c->object_clipper()->render_cut();
m_c->supports_clipper()->render_cut();
glsafe(::glDisable(GL_BLEND));
}
@ -104,27 +111,14 @@ void GLGizmoHollow::on_render()
#if ENABLE_RAYCAST_PICKING
void GLGizmoHollow::on_register_raycasters_for_picking()
{
assert(m_raycasters.empty());
init_cylinder_model();
set_sla_auxiliary_volumes_picking_state(false);
const CommonGizmosDataObjects::SelectionInfo* info = m_c->selection_info();
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));
}
update_raycasters_for_picking_transform();
}
register_hole_raycasters_for_picking();
register_volume_raycasters_for_picking();
}
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);
unregister_hole_raycasters_for_picking();
unregister_volume_raycasters_for_picking();
}
#else
void GLGizmoHollow::on_render_for_picking()
@ -190,7 +184,7 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
#if ENABLE_RAYCAST_PICKING
const bool clipped = is_mesh_point_clipped(drain_hole.pos.cast<double>());
m_raycasters[i]->set_active(!clipped);
m_hole_raycasters[i]->set_active(!clipped);
if (clipped)
continue;
#else
@ -270,6 +264,25 @@ void GLGizmoHollow::render_points(const Selection& selection, bool picking)
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
}
void GLGizmoHollow::render_volumes()
{
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_clip");
if (shader == nullptr)
return;
shader->start_using();
shader->set_uniform("emission_factor", 0.0f);
const Camera& camera = wxGetApp().plater()->get_camera();
ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane();
clipping_plane.set_normal(-clipping_plane.get_normal());
m_volumes.set_clipping_plane(clipping_plane.get_data());
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix());
shader->stop_using();
}
bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const
{
if (m_c->object_clipper()->get_position() == 0.)
@ -291,48 +304,26 @@ bool GLGizmoHollow::is_mesh_point_clipped(const Vec3d& point) const
// Return false if no intersection was found, true otherwise.
bool GLGizmoHollow::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
{
if (m_c->raycaster()->raycasters().size() != 1)
return false;
if (! m_c->raycaster()->raycaster())
return false;
const Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_first_volume();
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));
double clp_dist = m_c->object_clipper()->get_position();
const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane();
// The raycaster query
Vec3f hit;
Vec3f normal;
if (m_c->raycaster()->raycaster()->unproject_on_mesh(
mouse_pos,
trafo.get_matrix(),
camera,
m_volumes.volumes.front()->world_matrix(),
wxGetApp().plater()->get_camera(),
hit,
normal,
clp_dist != 0. ? clp : nullptr))
{
// if (m_c->hollowed_mesh() && m_c->hollowed_mesh()->get_hollowed_mesh()) {
// // in this case the raycaster sees the hollowed and drilled mesh.
// // if the point lies on the surface created by the hole, we want
// // to ignore it.
// for (const sla::DrainHole& hole : m_holes_in_drilled_mesh) {
// sla::DrainHole outer(hole);
// outer.radius *= 1.001f;
// outer.height *= 1.001f;
// if (outer.is_inside(hit))
// return false;
// }
// }
m_c->object_clipper()->get_position() != 0.0 ? m_c->object_clipper()->get_clipping_plane() : nullptr)) {
// Return both the point and the facet normal.
pos_and_normal = std::make_pair(hit, normal);
return true;
}
else
return false;
return false;
}
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
@ -348,9 +339,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
// left down with shift - show the selection rectangle:
if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) {
if (m_hover_id == -1) {
if (shift_down || alt_down) {
if (shift_down || alt_down)
m_selection_rectangle.start_dragging(mouse_position, shift_down ? GLSelectionRectangle::EState::Select : GLSelectionRectangle::EState::Deselect);
}
}
else {
if (m_selected[m_hover_id])
@ -383,8 +373,8 @@ bool GLGizmoHollow::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_pos
m_parent.set_as_dirty();
m_wait_for_up_event = true;
#if ENABLE_RAYCAST_PICKING
on_unregister_raycasters_for_picking();
on_register_raycasters_for_picking();
unregister_hole_raycasters_for_picking();
register_hole_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
}
else
@ -510,8 +500,8 @@ void GLGizmoHollow::delete_selected_points()
}
#if ENABLE_RAYCAST_PICKING
on_unregister_raycasters_for_picking();
on_register_raycasters_for_picking();
unregister_hole_raycasters_for_picking();
register_hole_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
select_point(NoPoints);
}
@ -580,39 +570,61 @@ bool GLGizmoHollow::on_mouse(const wxMouseEvent &mouse_event)
return false;
}
void GLGizmoHollow::hollow_mesh(bool postpone_error_messages)
void GLGizmoHollow::process_mesh(SLAPrintObjectStep step, bool postpone_error_messages)
{
wxGetApp().CallAfter([this, postpone_error_messages]() {
wxGetApp().plater()->reslice_SLA_hollowing(
*m_c->selection_info()->model_object(), postpone_error_messages);
});
wxGetApp().CallAfter([this, step, postpone_error_messages]() {
wxGetApp().plater()->reslice_SLA_until_step(step, *m_c->selection_info()->model_object(), postpone_error_messages);
});
}
#if ENABLE_RAYCAST_PICKING
void GLGizmoHollow::set_sla_auxiliary_volumes_picking_state(bool state)
void GLGizmoHollow::register_hole_raycasters_for_picking()
{
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);
}
assert(m_hole_raycasters.empty());
init_cylinder_model();
const CommonGizmosDataObjects::SelectionInfo* info = m_c->selection_info();
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_hole_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cylinder.mesh_raycaster, Transform3d::Identity()));
}
update_hole_raycasters_for_picking_transform();
}
}
void GLGizmoHollow::update_raycasters_for_picking_transform()
void GLGizmoHollow::unregister_hole_raycasters_for_picking()
{
for (size_t i = 0; i < m_hole_raycasters.size(); ++i) {
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, i);
}
m_hole_raycasters.clear();
}
void GLGizmoHollow::register_volume_raycasters_for_picking()
{
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
const GLVolume* v = m_volumes.volumes[i];
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i, *v->mesh_raycaster, v->world_matrix()));
}
}
void GLGizmoHollow::unregister_volume_raycasters_for_picking()
{
for (size_t i = 0; i < m_volume_raycasters.size(); ++i) {
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i);
}
m_volume_raycasters.clear();
}
void GLGizmoHollow::update_hole_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()) {
assert(!m_raycasters.empty());
assert(!m_hole_raycasters.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();
@ -625,13 +637,62 @@ void GLGizmoHollow::update_raycasters_for_picking_transform()
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);
m_hole_raycasters[i]->set_transform(matrix);
}
}
}
}
#endif // ENABLE_RAYCAST_PICKING
void GLGizmoHollow::update_volumes()
{
m_volumes.clear();
unregister_volume_raycasters_for_picking();
const ModelObject* mo = m_c->selection_info()->model_object();
if (mo == nullptr)
return;
const SLAPrintObject* po = m_c->selection_info()->print_object();
if (po == nullptr)
return;
TriangleMesh backend_mesh = po->get_mesh_to_print();
if (!backend_mesh.empty()) {
// The backend has generated a valid mesh. Use it
backend_mesh.transform(po->trafo().inverse());
m_volumes.volumes.emplace_back(new GLVolume());
GLVolume* new_volume = m_volumes.volumes.back();
new_volume->model.init_from(backend_mesh);
new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation());
new_volume->set_sla_shift_z(po->get_current_elevation());
new_volume->selected = true; // to set the proper color
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(backend_mesh);
}
if (m_volumes.volumes.empty()) {
// No valid mesh found in the backend. Use the selection to duplicate the volumes
const Selection& selection = m_parent.get_selection();
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) {
const GLVolume* v = selection.get_volume(idx);
if (!v->is_modifier) {
m_volumes.volumes.emplace_back(new GLVolume());
GLVolume* new_volume = m_volumes.volumes.back();
const TriangleMesh& mesh = mo->volumes[v->volume_idx()]->mesh();
new_volume->model.init_from(mesh);
new_volume->set_instance_transformation(v->get_instance_transformation());
new_volume->set_volume_transformation(v->get_volume_transformation());
new_volume->set_sla_shift_z(v->get_sla_shift_z());
new_volume->selected = true; // to set the proper color
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
}
}
}
register_volume_raycasters_for_picking();
}
std::vector<std::pair<const ConfigOption*, const ConfigOptionDef*>>
GLGizmoHollow::get_config_options(const std::vector<std::string>& keys) const
{
@ -724,8 +785,8 @@ RENDER_AGAIN:
window_width = std::max(window_width, button_preview_width);
if (m_imgui->button(m_desc["preview"]))
hollow_mesh();
process_mesh(slaposDrillHoles);
bool config_changed = false;
ImGui::Separator();
@ -896,13 +957,6 @@ RENDER_AGAIN:
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
// make sure supports are shown/hidden as appropriate
bool show_sups = m_c->instances_hider()->are_supports_shown();
if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) {
m_c->instances_hider()->show_supports(show_sups);
force_refresh = true;
}
m_imgui->end();
@ -935,7 +989,7 @@ bool GLGizmoHollow::on_is_activable() const
const Selection& selection = m_parent.get_selection();
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA
|| !selection.is_from_single_instance())
|| !selection.is_single_full_instance())
return false;
// Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside.
@ -964,9 +1018,7 @@ CommonGizmosDataID GLGizmoHollow::on_get_requirements() const
int(CommonGizmosDataID::SelectionInfo)
| int(CommonGizmosDataID::InstancesHider)
| int(CommonGizmosDataID::Raycaster)
| int(CommonGizmosDataID::HollowedMesh)
| int(CommonGizmosDataID::ObjectClipper)
| int(CommonGizmosDataID::SupportsClipper));
| int(CommonGizmosDataID::ObjectClipper));
}
@ -975,8 +1027,12 @@ void GLGizmoHollow::on_set_state()
if (m_state == m_old_state)
return;
if (m_state == Off && m_old_state != Off) // the gizmo was just turned Off
if (m_state == Off && m_old_state != Off) {
// the gizmo was just turned Off
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_FORCE_UPDATE));
m_c->instances_hider()->set_hide_full_scene(false);
}
m_old_state = m_state;
}
@ -1091,6 +1147,9 @@ void GLGizmoHollow::reload_cache()
void GLGizmoHollow::on_set_hover_id()
{
if (m_c->selection_info()->model_object() == nullptr)
return;
if (int(m_c->selection_info()->model_object()->sla_drain_holes.size()) <= m_hover_id)
m_hover_id = -1;
}

View File

@ -3,6 +3,7 @@
#include "GLGizmoBase.hpp"
#include "slic3r/GUI/GLSelectionRectangle.hpp"
#include "slic3r/GUI/3DScene.hpp"
#include <libslic3r/SLA/Hollowing.hpp>
#include <libslic3r/ObjectID.hpp>
@ -25,7 +26,6 @@ class GLGizmoHollow : public GLGizmoBase
private:
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
public:
GLGizmoHollow(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
void data_changed() override;
@ -59,21 +59,29 @@ private:
#else
void render_points(const Selection& selection, bool picking = false);
#endif // ENABLE_RAYCAST_PICKING
void hollow_mesh(bool postpone_error_messages = false);
void render_volumes();
void process_mesh(SLAPrintObjectStep step, bool postpone_error_messages = false);
#if ENABLE_RAYCAST_PICKING
void set_sla_auxiliary_volumes_picking_state(bool state);
void update_raycasters_for_picking_transform();
void register_hole_raycasters_for_picking();
void unregister_hole_raycasters_for_picking();
void register_volume_raycasters_for_picking();
void unregister_volume_raycasters_for_picking();
void update_hole_raycasters_for_picking_transform();
#endif // ENABLE_RAYCAST_PICKING
void update_volumes();
ObjectID m_old_mo_id = -1;
#if ENABLE_RAYCAST_PICKING
PickingModel m_cylinder;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_raycasters;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_hole_raycasters;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_volume_raycasters;
#else
GLModel m_cylinder;
#endif // ENABLE_RAYCAST_PICKING
GLVolumeCollection m_volumes;
float m_new_hole_radius = 2.f; // Size of a new hole.
float m_new_hole_height = 6.f;
mutable std::vector<bool> m_selected; // which holes are currently selected

View File

@ -60,6 +60,16 @@ bool GLGizmoSlaSupports::on_init()
return true;
}
static int last_completed_step(const SLAPrint& sla)
{
int step = -1;
for (int i = 0; i < (int)SLAPrintObjectStep::slaposCount; ++i) {
if (sla.is_step_done((SLAPrintObjectStep)i))
++step;
}
return step;
}
void GLGizmoSlaSupports::data_changed()
{
if (! m_c->selection_info())
@ -71,19 +81,25 @@ void GLGizmoSlaSupports::data_changed()
disable_editing_mode();
reload_cache();
m_old_mo_id = mo->id();
m_c->instances_hider()->show_supports(true);
}
// If we triggered autogeneration before, check backend and fetch results if they are there
if (mo) {
m_c->instances_hider()->set_hide_full_scene(true);
const SLAPrintObject* po = m_c->selection_info()->print_object();
if (po != nullptr && last_completed_step(*po->print()) < (int)slaposDrillHoles)
process_mesh(slaposDrillHoles, false);
update_volumes();
if (mo->sla_points_status == sla::PointsStatus::Generating)
get_data_from_backend();
#if ENABLE_RAYCAST_PICKING
if (m_raycasters.empty())
on_register_raycasters_for_picking();
if (m_point_raycasters.empty())
register_point_raycasters_for_picking();
else
update_raycasters_for_picking_transform();
update_point_raycasters_for_picking_transform();
#endif // ENABLE_RAYCAST_PICKING
}
@ -111,8 +127,6 @@ void GLGizmoSlaSupports::on_render()
if (!m_sphere.is_initialized())
m_sphere.init_from(its_make_sphere(1.0, double(PI) / 12.0));
#endif // ENABLE_RAYCAST_PICKING
if (!m_cylinder.is_initialized())
m_cylinder.init_from(its_make_cylinder(1.0, 1.0, double(PI) / 12.0));
ModelObject* mo = m_c->selection_info()->model_object();
const Selection& selection = m_parent.get_selection();
@ -128,16 +142,15 @@ void GLGizmoSlaSupports::on_render()
glsafe(::glEnable(GL_BLEND));
glsafe(::glEnable(GL_DEPTH_TEST));
if (selection.is_from_single_instance())
#if ENABLE_RAYCAST_PICKING
render_points(selection);
render_volumes();
render_points(selection);
#else
render_points(selection, false);
render_points(selection, false);
#endif // ENABLE_RAYCAST_PICKING
m_selection_rectangle.render(m_parent);
m_c->object_clipper()->render_cut();
m_c->supports_clipper()->render_cut();
glsafe(::glDisable(GL_BLEND));
}
@ -145,23 +158,14 @@ void GLGizmoSlaSupports::on_render()
#if ENABLE_RAYCAST_PICKING
void GLGizmoSlaSupports::on_register_raycasters_for_picking()
{
assert(m_raycasters.empty());
set_sla_auxiliary_volumes_picking_state(false);
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),
m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, i, *m_cone.mesh_raycaster));
}
update_raycasters_for_picking_transform();
}
register_point_raycasters_for_picking();
register_volume_raycasters_for_picking();
}
void GLGizmoSlaSupports::on_unregister_raycasters_for_picking()
{
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo);
m_raycasters.clear();
set_sla_auxiliary_volumes_picking_state(true);
unregister_point_raycasters_for_picking();
unregister_volume_raycasters_for_picking();
}
#else
void GLGizmoSlaSupports::on_render_for_picking()
@ -181,10 +185,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
const size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size();
const bool has_points = (cache_size != 0);
const bool has_holes = (/*! m_c->hollowed_mesh()->get_hollowed_mesh()
&&*/ ! m_c->selection_info()->model_object()->sla_drain_holes.empty());
if (! has_points && ! has_holes)
if (!has_points)
return;
#if ENABLE_LEGACY_OPENGL_REMOVAL
@ -234,9 +235,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
#if ENABLE_RAYCAST_PICKING
const bool clipped = is_mesh_point_clipped(support_point.pos.cast<double>());
if (!m_raycasters.empty()) {
m_raycasters[i].first->set_active(!clipped);
m_raycasters[i].second->set_active(!clipped);
if (i < m_point_raycasters.size()) {
m_point_raycasters[i].first->set_active(!clipped);
m_point_raycasters[i].second->set_active(!clipped);
}
if (clipped)
continue;
@ -306,8 +307,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
if (m_editing_mode) {
// in case the normal is not yet cached, find and cache it
if (m_editing_cache[i].normal == Vec3f::Zero())
m_parent.raycaster().get_raycasters(SceneRaycaster::EType::Volume)->front()->get_raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
//m_c->raycaster()->raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
m_c->raycaster()->raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>());
@ -373,67 +373,28 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
}
// Now render the drain holes:
#if ENABLE_RAYCAST_PICKING
if (has_holes) {
#else
if (has_holes && ! picking) {
#endif // ENABLE_RAYCAST_PICKING
render_color = { 0.7f, 0.7f, 0.7f, 0.7f };
#if ENABLE_LEGACY_OPENGL_REMOVAL
m_cylinder.set_color(render_color);
#else
m_cylinder.set_color(-1, render_color);
if (shader != nullptr)
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
shader->set_uniform("emission_factor", 0.5f);
for (const sla::DrainHole& drain_hole : m_c->selection_info()->model_object()->sla_drain_holes) {
if (is_mesh_point_clipped(drain_hole.pos.cast<double>()))
continue;
#if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d hole_matrix = Geometry::translation_transform(drain_hole.pos.cast<double>()) * instance_scaling_matrix_inverse;
#else
// Inverse matrix of the instance scaling is applied so that the mark does not scale with the object.
glsafe(::glPushMatrix());
glsafe(::glTranslatef(drain_hole.pos.x(), drain_hole.pos.y(), drain_hole.pos.z()));
glsafe(::glMultMatrixd(instance_scaling_matrix_inverse.data()));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
if (vol->is_left_handed())
glsafe(::glFrontFace(GL_CW));
// Matrices set, we can render the point mark now.
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * (-drain_hole.normal).cast<double>());
const Eigen::AngleAxisd aa(q);
#if ENABLE_LEGACY_OPENGL_REMOVAL
const Transform3d model_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));
shader->set_uniform("view_model_matrix", view_matrix * model_matrix);
const Matrix3d view_normal_matrix = view_matrix.matrix().block(0, 0, 3, 3) * model_matrix.matrix().block(0, 0, 3, 3).inverse().transpose();
shader->set_uniform("view_normal_matrix", view_normal_matrix);
#else
glsafe(::glRotated(aa.angle() * (180. / M_PI), aa.axis().x(), aa.axis().y(), aa.axis().z()));
glsafe(::glTranslated(0., 0., -drain_hole.height));
glsafe(::glScaled(drain_hole.radius, drain_hole.radius, drain_hole.height + sla::HoleStickOutLength));
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
m_cylinder.render();
if (vol->is_left_handed())
glsafe(::glFrontFace(GL_CCW));
#if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
}
}
#if !ENABLE_LEGACY_OPENGL_REMOVAL
glsafe(::glPopMatrix());
#endif // !ENABLE_LEGACY_OPENGL_REMOVAL
}
void GLGizmoSlaSupports::render_volumes()
{
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light_clip");
if (shader == nullptr)
return;
shader->start_using();
shader->set_uniform("emission_factor", 0.0f);
const Camera& camera = wxGetApp().plater()->get_camera();
ClippingPlane clipping_plane = (m_c->object_clipper()->get_position() == 0.0) ? ClippingPlane::ClipsNothing() : *m_c->object_clipper()->get_clipping_plane();
clipping_plane.set_normal(-clipping_plane.get_normal());
m_volumes.set_clipping_plane(clipping_plane.get_data());
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix());
shader->stop_using();
}
bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const
{
@ -456,48 +417,22 @@ bool GLGizmoSlaSupports::is_mesh_point_clipped(const Vec3d& point) const
// Return false if no intersection was found, true otherwise.
bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
{
if (m_parent.raycaster().get_raycasters(SceneRaycaster::EType::Volume)->empty())
if (!m_c->raycaster()->raycaster())
return false;
const Camera& camera = wxGetApp().plater()->get_camera();
const Selection& selection = m_parent.get_selection();
const GLVolume* volume = selection.get_first_volume();
Geometry::Transformation trafo = volume->get_instance_transformation() * volume->get_volume_transformation();
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_c->selection_info()->get_sla_shift()));
double clp_dist = m_c->object_clipper()->get_position();
const ClippingPlane* clp = m_c->object_clipper()->get_clipping_plane();
// The raycaster query
Vec3f hit;
Vec3f normal;
if (m_parent.raycaster().get_raycasters(SceneRaycaster::EType::Volume)->front()->get_raycaster()->unproject_on_mesh(
if (m_c->raycaster()->raycaster()->unproject_on_mesh(
mouse_pos,
trafo.get_matrix(),
camera,
m_volumes.volumes.front()->world_matrix(),
wxGetApp().plater()->get_camera(),
hit,
normal,
clp_dist != 0. ? clp : nullptr))
{
// Check whether the hit is in a hole
// bool in_hole = false;
// In case the hollowed and drilled mesh is available, we can allow
// placing points in holes, because they should never end up
// on surface that's been drilled away.
// if (! m_c->hollowed_mesh()->get_hollowed_mesh()) {
// sla::DrainHoles drain_holes = m_c->selection_info()->model_object()->sla_drain_holes;
// for (const sla::DrainHole& hole : drain_holes) {
// if (hole.is_inside(hit)) {
// in_hole = true;
// break;
// }
// }
// }
// if (! in_hole) {
// Return both the point and the facet normal.
pos_and_normal = std::make_pair(hit, normal);
return true;
// }
m_c->object_clipper()->get_position() != 0.0 ? m_c->object_clipper()->get_clipping_plane() : nullptr)) {
// Return both the point and the facet normal.
pos_and_normal = std::make_pair(hit, normal);
return true;
}
return false;
@ -548,8 +483,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_parent.set_as_dirty();
m_wait_for_up_event = true;
#if ENABLE_RAYCAST_PICKING
on_unregister_raycasters_for_picking();
on_register_raycasters_for_picking();
unregister_point_raycasters_for_picking();
register_point_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
}
else
@ -592,9 +527,8 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
for (size_t idx : points_idxs)
points_inside.emplace_back((trafo.get_matrix().cast<float>() * (m_editing_cache[idx].support_point.pos + m_editing_cache[idx].normal)).cast<float>());
assert(!m_parent.raycaster().get_raycasters(SceneRaycaster::EType::Volume).emtpy());
for (size_t idx : m_parent.raycaster().get_raycasters(SceneRaycaster::EType::Volume)->front()->get_raycaster()->get_unobscured_idxs(
trafo, wxGetApp().plater()->get_camera(), points_inside,
for (size_t idx : m_c->raycaster()->raycaster()->get_unobscured_idxs(
trafo, wxGetApp().plater()->get_camera(), points_inside,
m_c->object_clipper()->get_clipping_plane()))
{
if (idx >= orig_pts_num) // this is a cone-base, get index of point it belongs to
@ -712,8 +646,8 @@ void GLGizmoSlaSupports::delete_selected_points(bool force)
}
#if ENABLE_RAYCAST_PICKING
on_unregister_raycasters_for_picking();
on_register_raycasters_for_picking();
unregister_point_raycasters_for_picking();
register_point_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
select_point(NoPoints);
@ -1027,7 +961,7 @@ bool GLGizmoSlaSupports::on_is_activable() const
const Selection& selection = m_parent.get_selection();
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA
|| !selection.is_from_single_instance())
|| !selection.is_single_full_instance())
return false;
// Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside.
@ -1055,9 +989,7 @@ CommonGizmosDataID GLGizmoSlaSupports::on_get_requirements() const
int(CommonGizmosDataID::SelectionInfo)
| int(CommonGizmosDataID::InstancesHider)
| int(CommonGizmosDataID::Raycaster)
| int(CommonGizmosDataID::HollowedMesh)
| int(CommonGizmosDataID::ObjectClipper)
| int(CommonGizmosDataID::SupportsClipper));
| int(CommonGizmosDataID::ObjectClipper));
}
@ -1101,6 +1033,9 @@ void GLGizmoSlaSupports::on_set_state()
disable_editing_mode(); // so it is not active next time the gizmo opens
m_old_mo_id = -1;
}
if (m_state == Off)
m_c->instances_hider()->set_hide_full_scene(false);
}
m_old_state = m_state;
}
@ -1395,10 +1330,8 @@ void GLGizmoSlaSupports::switch_to_editing_mode()
m_editing_cache.emplace_back(sp);
select_point(NoPoints);
#if ENABLE_RAYCAST_PICKING
on_register_raycasters_for_picking();
register_point_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
m_c->instances_hider()->show_supports(false);
m_parent.set_as_dirty();
}
@ -1408,10 +1341,9 @@ void GLGizmoSlaSupports::disable_editing_mode()
if (m_editing_mode) {
m_editing_mode = false;
wxGetApp().plater()->leave_gizmos_stack();
m_c->instances_hider()->show_supports(true);
m_parent.set_as_dirty();
#if ENABLE_RAYCAST_PICKING
on_unregister_raycasters_for_picking();
unregister_point_raycasters_for_picking();
#endif // ENABLE_RAYCAST_PICKING
}
wxGetApp().plater()->get_notification_manager()->close_notification_of_type(NotificationType::QuitSLAManualMode);
@ -1432,53 +1364,130 @@ bool GLGizmoSlaSupports::unsaved_changes() const
}
#if ENABLE_RAYCAST_PICKING
void GLGizmoSlaSupports::set_sla_auxiliary_volumes_picking_state(bool state)
void GLGizmoSlaSupports::register_point_raycasters_for_picking()
{
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);
}
assert(m_point_raycasters.empty());
if (m_editing_mode && !m_editing_cache.empty()) {
for (size_t i = 0; i < m_editing_cache.size(); ++i) {
m_point_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()));
}
update_point_raycasters_for_picking_transform();
}
}
void GLGizmoSlaSupports::update_raycasters_for_picking_transform()
void GLGizmoSlaSupports::unregister_point_raycasters_for_picking()
{
if (!m_editing_cache.empty()) {
assert(!m_raycasters.empty());
for (size_t i = 0; i < m_point_raycasters.size(); ++i) {
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, i);
}
m_point_raycasters.clear();
}
const GLVolume* vol = m_parent.get_selection().get_first_volume();
const Geometry::Transformation transformation(vol->world_matrix());
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
for (size_t i = 0; i < m_editing_cache.size(); ++i) {
const Transform3d support_matrix = Geometry::translation_transform(m_editing_cache[i].support_point.pos.cast<double>()) * instance_scaling_matrix_inverse;
void GLGizmoSlaSupports::register_volume_raycasters_for_picking()
{
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
const GLVolume* v = m_volumes.volumes[i];
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i, *v->mesh_raycaster, v->world_matrix()));
}
}
if (m_editing_cache[i].normal == Vec3f::Zero())
m_parent.raycaster().get_raycasters(SceneRaycaster::EType::Volume)->front()->get_raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
void GLGizmoSlaSupports::unregister_volume_raycasters_for_picking()
{
for (size_t i = 0; i < m_volume_raycasters.size(); ++i) {
m_parent.remove_raycasters_for_picking(SceneRaycaster::EType::Gizmo, (int)SceneRaycaster::EIdBase::Gizmo + (int)i);
}
m_volume_raycasters.clear();
}
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>());
const Eigen::AngleAxisd aa(q);
const Transform3d cone_matrix = vol->world_matrix() * support_matrix * Transform3d(aa.toRotationMatrix()) *
Geometry::translation_transform((CONE_HEIGHT + m_editing_cache[i].support_point.head_front_radius * RenderPointScale) * Vec3d::UnitZ()) *
Geometry::rotation_transform({ double(PI), 0.0, 0.0 }) * Geometry::scale_transform({ CONE_RADIUS, CONE_RADIUS, CONE_HEIGHT });
m_raycasters[i].second->set_transform(cone_matrix);
void GLGizmoSlaSupports::update_point_raycasters_for_picking_transform()
{
if (m_editing_cache.empty())
return;
const double radius = (double)m_editing_cache[i].support_point.head_front_radius * RenderPointScale;
const Transform3d sphere_matrix = vol->world_matrix() * support_matrix * Geometry::scale_transform(radius);
m_raycasters[i].first->set_transform(sphere_matrix);
}
assert(!m_point_raycasters.empty());
const GLVolume* vol = m_parent.get_selection().get_first_volume();
const Geometry::Transformation transformation(vol->world_matrix());
const Transform3d instance_scaling_matrix_inverse = transformation.get_scaling_factor_matrix().inverse();
for (size_t i = 0; i < m_editing_cache.size(); ++i) {
const Transform3d support_matrix = Geometry::translation_transform(m_editing_cache[i].support_point.pos.cast<double>()) * instance_scaling_matrix_inverse;
if (m_editing_cache[i].normal == Vec3f::Zero())
m_c->raycaster()->raycaster()->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal);
Eigen::Quaterniond q;
q.setFromTwoVectors(Vec3d::UnitZ(), instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>());
const Eigen::AngleAxisd aa(q);
const Transform3d cone_matrix = vol->world_matrix() * support_matrix * Transform3d(aa.toRotationMatrix()) *
Geometry::assemble_transform((CONE_HEIGHT + m_editing_cache[i].support_point.head_front_radius * RenderPointScale) * Vec3d::UnitZ(),
Vec3d(PI, 0.0, 0.0), Vec3d(CONE_RADIUS, CONE_RADIUS, CONE_HEIGHT));
m_point_raycasters[i].second->set_transform(cone_matrix);
const double radius = (double)m_editing_cache[i].support_point.head_front_radius * RenderPointScale;
const Transform3d sphere_matrix = vol->world_matrix() * support_matrix * Geometry::scale_transform(radius);
m_point_raycasters[i].first->set_transform(sphere_matrix);
}
}
#endif // ENABLE_RAYCAST_PICKING
void GLGizmoSlaSupports::update_volumes()
{
m_volumes.clear();
unregister_volume_raycasters_for_picking();
const ModelObject* mo = m_c->selection_info()->model_object();
if (mo == nullptr)
return;
const SLAPrintObject* po = m_c->selection_info()->print_object();
if (po == nullptr)
return;
TriangleMesh backend_mesh = po->get_mesh_to_print();
if (!backend_mesh.empty()) {
// The backend has generated a valid mesh. Use it
backend_mesh.transform(po->trafo().inverse());
m_volumes.volumes.emplace_back(new GLVolume());
GLVolume* new_volume = m_volumes.volumes.back();
new_volume->model.init_from(backend_mesh);
new_volume->set_instance_transformation(po->model_object()->instances[m_parent.get_selection().get_instance_idx()]->get_transformation());
new_volume->set_sla_shift_z(po->get_current_elevation());
new_volume->selected = true; // to set the proper color
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(backend_mesh);
}
if (m_volumes.volumes.empty()) {
// No valid mesh found in the backend. Use the selection to duplicate the volumes
const Selection& selection = m_parent.get_selection();
const Selection::IndicesList& idxs = selection.get_volume_idxs();
for (unsigned int idx : idxs) {
const GLVolume* v = selection.get_volume(idx);
if (!v->is_modifier) {
m_volumes.volumes.emplace_back(new GLVolume());
GLVolume* new_volume = m_volumes.volumes.back();
const TriangleMesh& mesh = mo->volumes[v->volume_idx()]->mesh();
new_volume->model.init_from(mesh);
new_volume->set_instance_transformation(v->get_instance_transformation());
new_volume->set_volume_transformation(v->get_volume_transformation());
new_volume->set_sla_shift_z(v->get_sla_shift_z());
new_volume->selected = true; // to set the proper color
new_volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
}
}
}
register_volume_raycasters_for_picking();
}
void GLGizmoSlaSupports::process_mesh(SLAPrintObjectStep step, bool postpone_error_messages)
{
wxGetApp().CallAfter([this, step, postpone_error_messages]() {
wxGetApp().plater()->reslice_SLA_until_step(step, *m_c->selection_info()->model_object(), postpone_error_messages);
});
}
SlaGizmoHelpDialog::SlaGizmoHelpDialog()
: wxDialog(nullptr, wxID_ANY, _L("SLA gizmo keyboard shortcuts"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{

View File

@ -3,6 +3,7 @@
#include "GLGizmoBase.hpp"
#include "slic3r/GUI/GLSelectionRectangle.hpp"
#include "slic3r/GUI/3DScene.hpp"
#include "libslic3r/SLA/SupportPoint.hpp"
#include "libslic3r/ObjectID.hpp"
@ -22,7 +23,6 @@ enum class SLAGizmoEventType : unsigned char;
class GLGizmoSlaSupports : public GLGizmoBase
{
private:
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
static constexpr float RenderPointScale = 1.f;
@ -93,11 +93,17 @@ private:
#else
void render_points(const Selection& selection, bool picking = false);
#endif // ENABLE_RAYCAST_PICKING
void render_volumes();
bool unsaved_changes() const;
#if ENABLE_RAYCAST_PICKING
void set_sla_auxiliary_volumes_picking_state(bool state);
void update_raycasters_for_picking_transform();
void register_point_raycasters_for_picking();
void unregister_point_raycasters_for_picking();
void register_volume_raycasters_for_picking();
void unregister_volume_raycasters_for_picking();
void update_point_raycasters_for_picking_transform();
#endif // ENABLE_RAYCAST_PICKING
void update_volumes();
void process_mesh(SLAPrintObjectStep step, bool postpone_error_messages = false);
bool m_lock_unique_islands = false;
bool m_editing_mode = false; // Is editing mode active?
@ -113,12 +119,14 @@ private:
#if ENABLE_RAYCAST_PICKING
PickingModel m_sphere;
PickingModel m_cone;
std::vector<std::pair<std::shared_ptr<SceneRaycasterItem>, std::shared_ptr<SceneRaycasterItem>>> m_raycasters;
std::vector<std::pair<std::shared_ptr<SceneRaycasterItem>, std::shared_ptr<SceneRaycasterItem>>> m_point_raycasters;
std::vector<std::shared_ptr<SceneRaycasterItem>> m_volume_raycasters;
#else
GLModel m_cone;
GLModel m_sphere;
#endif // ENABLE_RAYCAST_PICKING
GLModel m_cylinder;
GLVolumeCollection m_volumes;
// This map holds all translated description texts, so they can be easily referenced during layout calculations
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.

View File

@ -59,13 +59,6 @@ InstancesHider* CommonGizmosDataPool::instances_hider() const
return inst_hider->is_valid() ? inst_hider : nullptr;
}
//HollowedMesh* CommonGizmosDataPool::hollowed_mesh() const
//{
// HollowedMesh* hol_mesh = dynamic_cast<HollowedMesh*>(m_data.at(CommonGizmosDataID::HollowedMesh).get());
// assert(hol_mesh);
// return hol_mesh->is_valid() ? hol_mesh : nullptr;
//}
Raycaster* CommonGizmosDataPool::raycaster() const
{
Raycaster* rc = dynamic_cast<Raycaster*>(m_data.at(CommonGizmosDataID::Raycaster).get());
@ -123,9 +116,8 @@ void SelectionInfo::on_update()
if (selection.is_single_full_instance()) {
m_model_object = selection.get_model()->objects[selection.get_object_idx()];
if (m_model_object)
m_print_object = get_pool()->get_canvas()->sla_print()->get_object(m_model_object->id());
m_print_object = get_pool()->get_canvas()->sla_print()->get_print_object_by_model_object_id(m_model_object->id());
m_z_shift = selection.get_first_volume()->get_sla_shift_z();
}
@ -154,8 +146,10 @@ void InstancesHider::on_update()
if (mo && active_inst != -1) {
canvas->toggle_model_objects_visibility(false);
canvas->toggle_model_objects_visibility(true, mo, active_inst);
canvas->toggle_sla_auxiliaries_visibility(m_show_supports, mo, active_inst);
if (!m_hide_full_scene) {
canvas->toggle_model_objects_visibility(true, mo, active_inst);
canvas->toggle_sla_auxiliaries_visibility(false, mo, active_inst);
}
canvas->set_use_clipping_planes(true);
// Some objects may be sinking, do not show whatever is below the bed.
canvas->set_clipping_plane(0, ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
@ -188,9 +182,10 @@ void InstancesHider::on_release()
m_clippers.clear();
}
void InstancesHider::show_supports(bool show) {
if (m_show_supports != show) {
m_show_supports = show;
void InstancesHider::set_hide_full_scene(bool hide)
{
if (m_hide_full_scene != hide) {
m_hide_full_scene = hide;
on_update();
}
}
@ -255,81 +250,6 @@ void InstancesHider::render_cut() const
//void HollowedMesh::on_update()
//{
// const ModelObject* mo = get_pool()->selection_info()->model_object();
// bool is_sla = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA;
// if (! mo || ! is_sla)
// return;
// const GLCanvas3D* canvas = get_pool()->get_canvas();
// const PrintObjects& print_objects = canvas->sla_print()->objects();
// const SLAPrintObject* print_object = (m_print_object_idx >= 0 && m_print_object_idx < int(print_objects.size()))
// ? print_objects[m_print_object_idx]
// : nullptr;
// // Find the respective SLAPrintObject.
// if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) {
// m_print_objects_count = print_objects.size();
// m_print_object_idx = -1;
// for (const SLAPrintObject* po : print_objects) {
// ++m_print_object_idx;
// if (po->model_object()->id() == mo->id()) {
// print_object = po;
// break;
// }
// }
// }
// // If there is a valid SLAPrintObject, check state of Hollowing step.
// if (print_object) {
// if (print_object->is_step_done(slaposDrillHoles) && !print_object->get_mesh_to_print().empty()) {
// size_t timestamp = print_object->step_state_with_timestamp(slaposDrillHoles).timestamp;
// if (timestamp > m_old_hollowing_timestamp) {
// const TriangleMesh& backend_mesh = print_object->get_mesh_to_print();
// if (! backend_mesh.empty()) {
// m_hollowed_mesh_transformed.reset(new TriangleMesh(backend_mesh));
// Transform3d trafo_inv = (canvas->sla_print()->sla_trafo(*mo) * print_object->model_object()->volumes.front()->get_transformation().get_matrix()).inverse();
// m_hollowed_mesh_transformed->transform(trafo_inv);
// m_drainholes = print_object->model_object()->sla_drain_holes;
// m_old_hollowing_timestamp = timestamp;
//// indexed_triangle_set interior = print_object->hollowed_interior_mesh();
//// its_flip_triangles(interior);
//// m_hollowed_interior_transformed = std::make_unique<TriangleMesh>(std::move(interior));
//// m_hollowed_interior_transformed->transform(trafo_inv);
// }
// else {
// m_hollowed_mesh_transformed.reset(nullptr);
// }
// }
// }
// else
// m_hollowed_mesh_transformed.reset(nullptr);
// }
//}
//void HollowedMesh::on_release()
//{
// m_hollowed_mesh_transformed.reset();
// m_old_hollowing_timestamp = 0;
// m_print_object_idx = -1;
//}
//const TriangleMesh* HollowedMesh::get_hollowed_mesh() const
//{
// return m_hollowed_mesh_transformed.get();
//}
//const TriangleMesh* HollowedMesh::get_hollowed_interior() const
//{
// return m_hollowed_interior_transformed.get();
//}
void Raycaster::on_update()
{
@ -347,21 +267,28 @@ void Raycaster::on_update()
mvs = mo->volumes;
std::vector<const TriangleMesh*> meshes;
const std::vector<ModelVolume*>& mvs = mo->volumes;
// if (mvs.size() == 1) {
// assert(mvs.front()->is_model_part());
// const HollowedMesh* hollowed_mesh_tracker = get_pool()->hollowed_mesh();
// if (hollowed_mesh_tracker && hollowed_mesh_tracker->get_hollowed_mesh())
// meshes.push_back(hollowed_mesh_tracker->get_hollowed_mesh());
// }
if (meshes.empty()) {
for (const ModelVolume* v : mvs) {
if (v->is_model_part())
meshes.push_back(&v->mesh());
bool force_raycaster_regeneration = false;
if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) {
// For sla printers we use the mesh generated by the backend
const SLAPrintObject* po = get_pool()->selection_info()->print_object();
assert(po != nullptr);
m_sla_mesh_cache = po->get_mesh_to_print();
if (!m_sla_mesh_cache.empty()) {
m_sla_mesh_cache.transform(po->trafo().inverse());
meshes.emplace_back(&m_sla_mesh_cache);
force_raycaster_regeneration = true;
}
}
if (meshes != m_old_meshes) {
if (meshes.empty()) {
const std::vector<ModelVolume*>& mvs = mo->volumes;
for (const ModelVolume* mv : mvs) {
if (mv->is_model_part())
meshes.push_back(&mv->mesh());
}
}
if (force_raycaster_regeneration || meshes != m_old_meshes) {
m_raycasters.clear();
for (const TriangleMesh* mesh : meshes)
#if ENABLE_RAYCAST_PICKING
@ -399,25 +326,36 @@ void ObjectClipper::on_update()
// which mesh should be cut?
std::vector<const TriangleMesh*> meshes;
// bool has_hollowed = get_pool()->hollowed_mesh() && get_pool()->hollowed_mesh()->get_hollowed_mesh();
// if (has_hollowed)
// meshes.push_back(get_pool()->hollowed_mesh()->get_hollowed_mesh());
std::vector<Geometry::Transformation> trafos;
bool force_clipper_regeneration = false;
if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) {
// For sla printers we use the mesh generated by the backend
const SLAPrintObject* po = get_pool()->selection_info()->print_object();
assert(po != nullptr);
m_sla_mesh_cache = po->get_mesh_to_print();
if (!m_sla_mesh_cache.empty()) {
m_sla_mesh_cache.transform(po->trafo().inverse());
meshes.emplace_back(&m_sla_mesh_cache);
trafos.emplace_back(Geometry::Transformation());
force_clipper_regeneration = true;
}
}
if (meshes.empty())
for (const ModelVolume* mv : mo->volumes)
meshes.push_back(&mv->mesh());
if (meshes.empty()) {
for (const ModelVolume* mv : mo->volumes) {
meshes.emplace_back(&mv->mesh());
trafos.emplace_back(mv->get_transformation());
}
}
if (meshes != m_old_meshes) {
if (force_clipper_regeneration || meshes != m_old_meshes) {
m_clippers.clear();
for (const TriangleMesh* mesh : meshes) {
m_clippers.emplace_back(new MeshClipper);
m_clippers.back()->set_mesh(*mesh);
for (size_t i = 0; i < meshes.size(); ++i) {
m_clippers.emplace_back(new MeshClipper, trafos[i]);
m_clippers.back().first->set_mesh(*meshes[i]);
}
m_old_meshes = meshes;
// if (has_hollowed)
// m_clippers.front()->set_negative_mesh(*get_pool()->hollowed_mesh()->get_hollowed_interior());
m_active_inst_bb_radius =
mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius();
}
@ -437,46 +375,27 @@ void ObjectClipper::render_cut() const
{
if (m_clp_ratio == 0.)
return;
const SelectionInfo* sel_info = get_pool()->selection_info();
int sel_instance_idx = sel_info->get_active_instance();
if (sel_instance_idx < 0)
return;
const ModelObject* mo = sel_info->model_object();
const Geometry::Transformation inst_trafo = mo->instances[sel_instance_idx]->get_transformation();
size_t clipper_id = 0;
for (const ModelVolume* mv : mo->volumes) {
const Geometry::Transformation vol_trafo = mv->get_transformation();
Geometry::Transformation trafo = inst_trafo * vol_trafo;
const Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation();
for (auto& clipper : m_clippers) {
Geometry::Transformation trafo = inst_trafo * clipper.second;
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
auto& clipper = m_clippers[clipper_id];
clipper->set_plane(*m_clp);
clipper->set_transformation(trafo);
clipper->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
#if ENABLE_LEGACY_OPENGL_REMOVAL
clipper->render_cut({ 1.0f, 0.37f, 0.0f, 1.0f });
clipper->render_contour({ 1.f, 1.f, 1.f, 1.f});
#else
glsafe(::glPushMatrix());
glsafe(::glColor3f(1.0f, 0.37f, 0.0f));
clipper->render_cut();
glsafe(::glColor3f(1.f, 1.f, 1.f));
clipper->render_contour();
#endif // ENABLE_LEGACY_OPENGL_REMOVAL
++clipper_id;
clipper.first->set_plane(*m_clp);
clipper.first->set_transformation(trafo);
clipper.first->set_limiting_plane(ClippingPlane(Vec3d::UnitZ(), -SINKING_Z_THRESHOLD));
clipper.first->render_cut({ 1.0f, 0.37f, 0.0f, 1.0f });
}
}
bool ObjectClipper::is_projection_inside_cut(const Vec3d& point) const
{
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [point](const std::unique_ptr<MeshClipper>& cl) { return cl->is_projection_inside_cut(point); });
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [point](const auto& cl) { return cl.first->is_projection_inside_cut(point); });
}
bool ObjectClipper::has_valid_contour() const
{
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const std::unique_ptr<MeshClipper>& cl) { return cl->has_valid_contour(); });
return m_clp_ratio != 0. && std::any_of(m_clippers.begin(), m_clippers.end(), [](const auto& cl) { return cl.first->has_valid_contour(); });
}
void ObjectClipper::set_position_by_ratio(double pos, bool keep_normal)
@ -514,13 +433,13 @@ void ObjectClipper::set_behavior(bool hide_clipped, bool fill_cut, double contou
{
m_hide_clipped = hide_clipped;
for (auto& clipper : m_clippers)
clipper->set_behaviour(fill_cut, contour_width);
clipper.first->set_behaviour(fill_cut, contour_width);
}
void ObjectClipper::pass_mouse_click(const Vec3d& pt)
{
for (auto& clipper : m_clippers)
clipper->pass_mouse_click(pt);
clipper.first->pass_mouse_click(pt);
}
std::vector<Vec3d> ObjectClipper::get_disabled_contours() const
@ -586,7 +505,6 @@ void SupportsClipper::render_cut() const
{
const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper();
if (ocl->get_position() == 0.
|| ! get_pool()->instances_hider()->are_supports_shown()
|| ! m_clipper)
return;

View File

@ -63,7 +63,6 @@ enum class CommonGizmosDataID {
None = 0,
SelectionInfo = 1 << 0,
InstancesHider = 1 << 1,
HollowedMesh = 1 << 2,
Raycaster = 1 << 3,
ObjectClipper = 1 << 4,
SupportsClipper = 1 << 5,
@ -187,8 +186,7 @@ public:
CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; }
#endif // NDEBUG
void show_supports(bool show);
bool are_supports_shown() const { return m_show_supports; }
void set_hide_full_scene(bool hide);
void render_cut() const;
protected:
@ -196,42 +194,13 @@ protected:
void on_release() override;
private:
bool m_show_supports = false;
bool m_hide_full_scene{ false };
std::vector<const TriangleMesh*> m_old_meshes;
std::vector<std::unique_ptr<MeshClipper>> m_clippers;
};
//class HollowedMesh : public CommonGizmosDataBase
//{
//public:
// explicit HollowedMesh(CommonGizmosDataPool* cgdp)
// : CommonGizmosDataBase(cgdp) {}
//#ifndef NDEBUG
// CommonGizmosDataID get_dependencies() const override { return CommonGizmosDataID::SelectionInfo; }
//#endif // NDEBUG
// const sla::DrainHoles &get_drainholes() const { return m_drainholes; }
// const TriangleMesh* get_hollowed_mesh() const;
// const TriangleMesh* get_hollowed_interior() const;
//protected:
// void on_update() override;
// void on_release() override;
//private:
// std::unique_ptr<TriangleMesh> m_hollowed_mesh_transformed;
// std::unique_ptr<TriangleMesh> m_hollowed_interior_transformed;
// size_t m_old_hollowing_timestamp = 0;
// int m_print_object_idx = -1;
// int m_print_objects_count = 0;
// sla::DrainHoles m_drainholes;
//};
class Raycaster : public CommonGizmosDataBase
{
public:
@ -251,6 +220,8 @@ protected:
private:
std::vector<std::unique_ptr<MeshRaycaster>> m_raycasters;
std::vector<const TriangleMesh*> m_old_meshes;
// Used to store the sla mesh coming from the backend
TriangleMesh m_sla_mesh_cache;
};
@ -285,7 +256,9 @@ protected:
private:
std::vector<const TriangleMesh*> m_old_meshes;
std::vector<std::unique_ptr<MeshClipper>> m_clippers;
// Used to store the sla mesh coming from the backend
TriangleMesh m_sla_mesh_cache;
std::vector<std::pair<std::unique_ptr<MeshClipper>, Geometry::Transformation>> m_clippers;
std::unique_ptr<ClippingPlane> m_clp;
double m_clp_ratio = 0.;
double m_active_inst_bb_radius = 0.;

View File

@ -100,7 +100,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came
};
#if ENABLE_RAYCAST_PICKING_DEBUG
m_last_hit.reset();
const_cast<std::optional<HitResult>*>(&m_last_hit)->reset();
#endif // ENABLE_RAYCAST_PICKING_DEBUG
HitResult ret;
@ -142,7 +142,7 @@ SceneRaycaster::HitResult SceneRaycaster::hit(const Vec2d& mouse_pos, const Came
ret.raycaster_id = decode_id(ret.type, ret.raycaster_id);
#if ENABLE_RAYCAST_PICKING_DEBUG
m_last_hit = ret;
*const_cast<std::optional<HitResult>*>(&m_last_hit) = ret;
#endif // ENABLE_RAYCAST_PICKING_DEBUG
return ret;
}