Reintroduced visualization of SLA supports and pad into 3D scene and gizmos Hollow and SLA support as it was in 2.5.0
This commit is contained in:
parent
7a14406902
commit
1b8553c747
@ -564,6 +564,67 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||||||
return int(volumes.size() - 1);
|
return int(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.
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (print_object->get_mesh_to_print() == nullptr)
|
||||||
|
return;
|
||||||
|
const Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
||||||
|
|
||||||
|
auto add_volume = [this, &instances, timestamp](int obj_idx, int inst_idx, const ModelInstance& model_instance, SLAPrintObjectStep step,
|
||||||
|
const TriangleMesh& mesh, const ColorRGBA& color, std::optional<const TriangleMesh> convex_hull = std::nullopt) {
|
||||||
|
if (mesh.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
GLVolume& v = *this->volumes.emplace_back(new GLVolume(color));
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
v.model.init_from(mesh, true);
|
||||||
|
#else
|
||||||
|
v.model.init_from(mesh);
|
||||||
|
v.model.set_color(color);
|
||||||
|
v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<const TriangleMesh>(mesh));
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
v.composite_id = GLVolume::CompositeID(obj_idx, -int(step), inst_idx);
|
||||||
|
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||||
|
if (convex_hull.has_value())
|
||||||
|
v.set_convex_hull(*convex_hull);
|
||||||
|
v.is_modifier = false;
|
||||||
|
v.shader_outside_printer_detection_enabled = (step == slaposSupportTree);
|
||||||
|
v.set_instance_transformation(model_instance.get_transformation());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the support mesh.
|
||||||
|
TriangleMesh supports_mesh = print_object->support_mesh();
|
||||||
|
if (!supports_mesh.empty()) {
|
||||||
|
supports_mesh.transform(mesh_trafo_inv);
|
||||||
|
TriangleMesh convex_hull = supports_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];
|
||||||
|
add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposSupportTree, supports_mesh, GLVolume::SLA_SUPPORT_COLOR, convex_hull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the pad mesh.
|
||||||
|
TriangleMesh pad_mesh = print_object->pad_mesh();
|
||||||
|
if (!pad_mesh.empty()) {
|
||||||
|
pad_mesh.transform(mesh_trafo_inv);
|
||||||
|
TriangleMesh convex_hull = pad_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];
|
||||||
|
add_volume(obj_idx, (int)instance_idx.first, model_instance, slaposPad, pad_mesh, GLVolume::SLA_PAD_COLOR, convex_hull);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
|
GLVolume* GLVolumeCollection::new_toolpath_volume(const ColorRGBA& rgba)
|
||||||
{
|
{
|
||||||
GLVolume* out = new_nontoolpath_volume(rgba);
|
GLVolume* out = new_nontoolpath_volume(rgba);
|
||||||
|
@ -430,6 +430,16 @@ public:
|
|||||||
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||||
#endif // ENABLE_OPENGL_ES
|
#endif // ENABLE_OPENGL_ES
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
|
GLVolume* new_toolpath_volume(const ColorRGBA& rgba);
|
||||||
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
|
GLVolume* new_nontoolpath_volume(const ColorRGBA& rgba);
|
||||||
// Render the volumes by OpenGL.
|
// Render the volumes by OpenGL.
|
||||||
|
@ -1881,6 +1881,15 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||||||
size_t volume_idx;
|
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> instance_ids_selected;
|
||||||
std::vector<size_t> map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1));
|
std::vector<size_t> map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1));
|
||||||
std::vector<GLVolumeState> deleted_volumes;
|
std::vector<GLVolumeState> deleted_volumes;
|
||||||
@ -1906,6 +1915,37 @@ 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::State::Done) {
|
||||||
|
std::shared_ptr<const indexed_triangle_set> m = print_object->get_mesh_to_print();
|
||||||
|
if (m == nullptr || m->empty())
|
||||||
|
// Consider the DONE step without a valid mesh as invalid for the purpose
|
||||||
|
// of mesh visualization.
|
||||||
|
state.step[istep].state = PrintStateBase::State::Invalidated;
|
||||||
|
else {
|
||||||
|
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(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);
|
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.
|
// Release all ModelVolume based GLVolumes not found in the current Model. Find the GLVolume of a hollowed mesh.
|
||||||
@ -2020,6 +2060,118 @@ 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.
|
||||||
|
volume.model.reset();
|
||||||
|
if (state.step[istep].state == PrintStateBase::State::Done) {
|
||||||
|
std::shared_ptr<const indexed_triangle_set> m = print_object->get_mesh_to_print();
|
||||||
|
assert(m != nullptr && !m->empty());
|
||||||
|
TriangleMesh mesh(*m);
|
||||||
|
// 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
|
||||||
|
volume.model.init_from(mesh, true);
|
||||||
|
#else
|
||||||
|
volume.model.init_from(mesh);
|
||||||
|
volume.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(std::make_shared<TriangleMesh>(mesh));
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Reload the original volume.
|
||||||
|
#if ENABLE_SMOOTH_NORMALS
|
||||||
|
volume.model.init_from(m_model->objects[volume.object_idx()]->volumes[volume.volume_idx()]->mesh(), true);
|
||||||
|
#else
|
||||||
|
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));
|
||||||
|
#endif // ENABLE_SMOOTH_NORMALS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//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::State::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())
|
||||||
|
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()) {
|
||||||
|
const SLAPrintObject* po = sla_print->objects()[volume->object_idx()];
|
||||||
|
float zoffs = po->get_current_elevation() / sla_print->relative_correction().z();
|
||||||
|
volume->set_sla_shift_z(zoffs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) {
|
if (printer_technology == ptFFF && m_config->has("nozzle_diameter")) {
|
||||||
// Should the wipe tower be visualized ?
|
// Should the wipe tower be visualized ?
|
||||||
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
|
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
|
||||||
@ -6805,9 +6957,9 @@ void GLCanvas3D::_load_sla_shells()
|
|||||||
// adds objects' volumes
|
// adds objects' volumes
|
||||||
for (const SLAPrintObject* obj : print->objects()) {
|
for (const SLAPrintObject* obj : print->objects()) {
|
||||||
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
|
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
|
||||||
for (const SLAPrintObject::Instance& instance : obj->instances()) {
|
|
||||||
std::shared_ptr<const indexed_triangle_set> m = obj->get_mesh_to_print();
|
std::shared_ptr<const indexed_triangle_set> m = obj->get_mesh_to_print();
|
||||||
if (m && !m->empty()) {
|
if (m && !m->empty()) {
|
||||||
|
for (const SLAPrintObject::Instance& instance : obj->instances()) {
|
||||||
add_volume(*obj, 0, instance, *m, GLVolume::MODEL_COLOR[0], true);
|
add_volume(*obj, 0, instance, *m, GLVolume::MODEL_COLOR[0], true);
|
||||||
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
|
// 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.
|
// through the update_volumes_colors_by_extruder() call.
|
||||||
@ -6818,7 +6970,7 @@ void GLCanvas3D::_load_sla_shells()
|
|||||||
add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false);
|
add_volume(*obj, -int(slaposPad), instance, pad_mesh, GLVolume::SLA_PAD_COLOR, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double shift_z = obj->get_current_elevation();
|
const double shift_z = obj->get_current_elevation();
|
||||||
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
|
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
|
||||||
// apply shift z
|
// apply shift z
|
||||||
m_volumes.volumes[i]->set_sla_shift_z(shift_z);
|
m_volumes.volumes[i]->set_sla_shift_z(shift_z);
|
||||||
|
@ -101,6 +101,7 @@ void GLGizmoHollow::on_render()
|
|||||||
|
|
||||||
m_selection_rectangle.render(m_parent);
|
m_selection_rectangle.render(m_parent);
|
||||||
m_c->object_clipper()->render_cut();
|
m_c->object_clipper()->render_cut();
|
||||||
|
m_c->supports_clipper()->render_cut();
|
||||||
|
|
||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
}
|
}
|
||||||
@ -772,6 +773,14 @@ RENDER_AGAIN:
|
|||||||
if (m_imgui->slider_float("##clp_dist", &clp_dist, 0.f, 1.f, "%.2f"))
|
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);
|
m_c->object_clipper()->set_position_by_ratio(clp_dist, true);
|
||||||
|
|
||||||
|
// make sure supports are shown/hidden as appropriate
|
||||||
|
ImGui::Separator();
|
||||||
|
bool show_sups = are_sla_supports_shown();
|
||||||
|
if (m_imgui->checkbox(m_desc["show_supports"], show_sups)) {
|
||||||
|
show_sla_supports(show_sups);
|
||||||
|
force_refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
m_imgui->disabled_end();
|
m_imgui->disabled_end();
|
||||||
m_imgui->end();
|
m_imgui->end();
|
||||||
|
|
||||||
|
@ -30,7 +30,8 @@ CommonGizmosDataID GLGizmoSlaBase::on_get_requirements() const
|
|||||||
int(CommonGizmosDataID::SelectionInfo)
|
int(CommonGizmosDataID::SelectionInfo)
|
||||||
| int(CommonGizmosDataID::InstancesHider)
|
| int(CommonGizmosDataID::InstancesHider)
|
||||||
| int(CommonGizmosDataID::Raycaster)
|
| int(CommonGizmosDataID::Raycaster)
|
||||||
| int(CommonGizmosDataID::ObjectClipper));
|
| int(CommonGizmosDataID::ObjectClipper)
|
||||||
|
| int(CommonGizmosDataID::SupportsClipper));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLGizmoSlaBase::update_volumes()
|
void GLGizmoSlaBase::update_volumes()
|
||||||
@ -50,27 +51,54 @@ void GLGizmoSlaBase::update_volumes()
|
|||||||
|
|
||||||
TriangleMesh backend_mesh;
|
TriangleMesh backend_mesh;
|
||||||
std::shared_ptr<const indexed_triangle_set> preview_mesh_ptr = po->get_mesh_to_print();
|
std::shared_ptr<const indexed_triangle_set> preview_mesh_ptr = po->get_mesh_to_print();
|
||||||
if (preview_mesh_ptr)
|
if (preview_mesh_ptr != nullptr)
|
||||||
backend_mesh = TriangleMesh{*preview_mesh_ptr};
|
backend_mesh = TriangleMesh(*preview_mesh_ptr);
|
||||||
|
|
||||||
if (!backend_mesh.empty()) {
|
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->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(backend_mesh);
|
|
||||||
auto last_comp_step = static_cast<int>(po->last_completed_step());
|
auto last_comp_step = static_cast<int>(po->last_completed_step());
|
||||||
if (last_comp_step == slaposCount)
|
if (last_comp_step == slaposCount)
|
||||||
last_comp_step = -1;
|
last_comp_step = -1;
|
||||||
|
|
||||||
m_input_enabled = last_comp_step >= m_min_sla_print_object_step;
|
m_input_enabled = last_comp_step >= m_min_sla_print_object_step;
|
||||||
|
|
||||||
|
const int object_idx = m_parent.get_selection().get_object_idx();
|
||||||
|
const int instance_idx = m_parent.get_selection().get_instance_idx();
|
||||||
|
const Geometry::Transformation& inst_trafo = po->model_object()->instances[instance_idx]->get_transformation();
|
||||||
|
const double current_elevation = po->get_current_elevation();
|
||||||
|
|
||||||
|
auto add_volume = [this, object_idx, instance_idx, &inst_trafo, current_elevation](const TriangleMesh& mesh, int volume_id, bool add_mesh_raycaster = false) {
|
||||||
|
GLVolume* volume = m_volumes.volumes.emplace_back(new GLVolume());
|
||||||
|
volume->model.init_from(mesh);
|
||||||
|
volume->set_instance_transformation(inst_trafo);
|
||||||
|
volume->set_sla_shift_z(current_elevation);
|
||||||
|
if (add_mesh_raycaster)
|
||||||
|
volume->mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh);
|
||||||
if (m_input_enabled)
|
if (m_input_enabled)
|
||||||
new_volume->selected = true; // to set the proper color
|
volume->selected = true; // to set the proper color
|
||||||
else
|
else
|
||||||
new_volume->set_color(DISABLED_COLOR);
|
volume->set_color(DISABLED_COLOR);
|
||||||
|
volume->composite_id = GLVolume::CompositeID(object_idx, volume_id, instance_idx);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Transform3d po_trafo_inverse = po->trafo().inverse();
|
||||||
|
|
||||||
|
// main mesh
|
||||||
|
backend_mesh.transform(po_trafo_inverse);
|
||||||
|
add_volume(backend_mesh, 0, true);
|
||||||
|
|
||||||
|
// supports mesh
|
||||||
|
TriangleMesh supports_mesh = po->support_mesh();
|
||||||
|
if (!supports_mesh.empty()) {
|
||||||
|
supports_mesh.transform(po_trafo_inverse);
|
||||||
|
add_volume(supports_mesh, -int(slaposSupportTree));
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad mesh
|
||||||
|
TriangleMesh pad_mesh = po->pad_mesh();
|
||||||
|
if (!pad_mesh.empty()) {
|
||||||
|
pad_mesh.transform(po_trafo_inverse);
|
||||||
|
add_volume(pad_mesh, -int(slaposPad));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_volumes.volumes.empty()) {
|
if (m_volumes.volumes.empty()) {
|
||||||
@ -110,7 +138,11 @@ void GLGizmoSlaBase::render_volumes()
|
|||||||
clipping_plane.set_normal(-clipping_plane.get_normal());
|
clipping_plane.set_normal(-clipping_plane.get_normal());
|
||||||
m_volumes.set_clipping_plane(clipping_plane.get_data());
|
m_volumes.set_clipping_plane(clipping_plane.get_data());
|
||||||
|
|
||||||
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, false, camera.get_view_matrix(), camera.get_projection_matrix());
|
for (GLVolume* v : m_volumes.volumes) {
|
||||||
|
v->is_active = m_show_sla_supports || (!v->is_sla_pad() && !v->is_sla_support());
|
||||||
|
}
|
||||||
|
|
||||||
|
m_volumes.render(GLVolumeCollection::ERenderType::Opaque, true, camera.get_view_matrix(), camera.get_projection_matrix());
|
||||||
shader->stop_using();
|
shader->stop_using();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -119,6 +151,7 @@ void GLGizmoSlaBase::register_volume_raycasters_for_picking()
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
|
for (size_t i = 0; i < m_volumes.volumes.size(); ++i) {
|
||||||
const GLVolume* v = m_volumes.volumes[i];
|
const GLVolume* v = m_volumes.volumes[i];
|
||||||
|
if (!v->is_sla_pad() && !v->is_sla_support())
|
||||||
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix()));
|
m_volume_raycasters.emplace_back(m_parent.add_raycaster_for_picking(SceneRaycaster::EType::Gizmo, VOLUME_RAYCASTERS_BASE_ID + (int)i, *v->mesh_raycaster, v->world_matrix()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,15 @@ protected:
|
|||||||
|
|
||||||
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
||||||
|
|
||||||
|
bool are_sla_supports_shown() const { return m_show_sla_supports; }
|
||||||
|
void show_sla_supports(bool show) { m_show_sla_supports = show; }
|
||||||
|
|
||||||
const GLVolumeCollection &volumes() const { return m_volumes; }
|
const GLVolumeCollection &volumes() const { return m_volumes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLVolumeCollection m_volumes;
|
GLVolumeCollection m_volumes;
|
||||||
bool m_input_enabled{ false };
|
bool m_input_enabled{ false };
|
||||||
|
bool m_show_sla_supports{ false };
|
||||||
int m_min_sla_print_object_step{ -1 };
|
int m_min_sla_print_object_step{ -1 };
|
||||||
std::vector<std::shared_ptr<SceneRaycasterItem>> m_volume_raycasters;
|
std::vector<std::shared_ptr<SceneRaycasterItem>> m_volume_raycasters;
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,9 @@ namespace GUI {
|
|||||||
|
|
||||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||||
: GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles)
|
: GLGizmoSlaBase(parent, icon_filename, sprite_id, slaposDrillHoles)
|
||||||
{}
|
{
|
||||||
|
show_sla_supports(true);
|
||||||
|
}
|
||||||
|
|
||||||
bool GLGizmoSlaSupports::on_init()
|
bool GLGizmoSlaSupports::on_init()
|
||||||
{
|
{
|
||||||
@ -127,6 +129,7 @@ void GLGizmoSlaSupports::on_render()
|
|||||||
|
|
||||||
m_selection_rectangle.render(m_parent);
|
m_selection_rectangle.render(m_parent);
|
||||||
m_c->object_clipper()->render_cut();
|
m_c->object_clipper()->render_cut();
|
||||||
|
m_c->supports_clipper()->render_cut();
|
||||||
|
|
||||||
glsafe(::glDisable(GL_BLEND));
|
glsafe(::glDisable(GL_BLEND));
|
||||||
}
|
}
|
||||||
|
@ -453,83 +453,66 @@ void SupportsClipper::on_update()
|
|||||||
if (! mo || ! is_sla)
|
if (! mo || ! is_sla)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const GLCanvas3D* canvas = get_pool()->get_canvas();
|
const SLAPrintObject* print_object = get_pool()->selection_info()->print_object();
|
||||||
const PrintObjects& print_objects = canvas->sla_print()->objects();
|
if (print_object == nullptr)
|
||||||
const SLAPrintObject* print_object = (m_print_object_idx >= 0 && m_print_object_idx < int(print_objects.size()))
|
return;
|
||||||
? print_objects[m_print_object_idx]
|
|
||||||
: nullptr;
|
|
||||||
|
|
||||||
// Find the respective SLAPrintObject.
|
if (print_object->get_mesh_to_print() == nullptr) {
|
||||||
if (m_print_object_idx < 0 || m_print_objects_count != int(print_objects.size())) {
|
// The object has been not sliced yet. We better dump the cached data.
|
||||||
m_print_objects_count = print_objects.size();
|
m_supports_clipper.reset();
|
||||||
m_print_object_idx = -1;
|
m_pad_clipper.reset();
|
||||||
for (const SLAPrintObject* po : print_objects) {
|
return;
|
||||||
++m_print_object_idx;
|
|
||||||
if (po->model_object()->id() == mo->id()) {
|
|
||||||
print_object = po;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (print_object
|
const TriangleMesh& support_mesh = print_object->support_mesh();
|
||||||
&& print_object->is_step_done(slaposSupportTree)
|
if (support_mesh.empty()) {
|
||||||
&& ! print_object->support_mesh().empty())
|
// The supports are not available yet. We better dump the cached data.
|
||||||
{
|
m_supports_clipper.reset();
|
||||||
// If the supports are already calculated, save the timestamp of the respective step
|
|
||||||
// so we can later tell they were recalculated.
|
|
||||||
size_t timestamp = print_object->step_state_with_timestamp(slaposSupportTree).timestamp;
|
|
||||||
if (! m_clipper || timestamp != m_old_timestamp) {
|
|
||||||
// The timestamp has changed.
|
|
||||||
m_clipper.reset(new MeshClipper);
|
|
||||||
// The mesh should already have the shared vertices calculated.
|
|
||||||
m_clipper->set_mesh(print_object->support_mesh().its);
|
|
||||||
m_old_timestamp = timestamp;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
m_supports_clipper.reset(new MeshClipper);
|
||||||
|
m_supports_clipper->set_mesh(support_mesh.its);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TriangleMesh& pad_mesh = print_object->pad_mesh();
|
||||||
|
if (pad_mesh.empty()) {
|
||||||
|
// The supports are not available yet. We better dump the cached data.
|
||||||
|
m_pad_clipper.reset();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_pad_clipper.reset(new MeshClipper);
|
||||||
|
m_pad_clipper->set_mesh(pad_mesh.its);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
// The supports are not valid. We better dump the cached data.
|
|
||||||
m_clipper.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SupportsClipper::on_release()
|
void SupportsClipper::on_release()
|
||||||
{
|
{
|
||||||
m_clipper.reset();
|
m_supports_clipper.reset();
|
||||||
m_old_timestamp = 0;
|
m_pad_clipper.reset();
|
||||||
m_print_object_idx = -1;
|
m_print_object_idx = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SupportsClipper::render_cut() const
|
void SupportsClipper::render_cut() const
|
||||||
{
|
{
|
||||||
const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper();
|
const CommonGizmosDataObjects::ObjectClipper* ocl = get_pool()->object_clipper();
|
||||||
if (ocl->get_position() == 0.
|
if (ocl->get_position() == 0.)
|
||||||
|| ! m_clipper)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const SelectionInfo* sel_info = get_pool()->selection_info();
|
const SelectionInfo* sel_info = get_pool()->selection_info();
|
||||||
const ModelObject* mo = sel_info->model_object();
|
const Geometry::Transformation inst_trafo = sel_info->model_object()->instances[sel_info->get_active_instance()]->get_transformation();
|
||||||
const Geometry::Transformation inst_trafo = mo->instances[sel_info->get_active_instance()]->get_transformation();
|
|
||||||
//Geometry::Transformation vol_trafo = mo->volumes.front()->get_transformation();
|
|
||||||
Geometry::Transformation trafo = inst_trafo;// * vol_trafo;
|
|
||||||
trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., sel_info->get_sla_shift()));
|
|
||||||
|
|
||||||
|
if (m_supports_clipper != nullptr) {
|
||||||
|
m_supports_clipper->set_plane(*ocl->get_clipping_plane());
|
||||||
|
m_supports_clipper->set_transformation(inst_trafo);
|
||||||
|
m_supports_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f });
|
||||||
|
}
|
||||||
|
|
||||||
// Get transformation of supports
|
if (m_pad_clipper != nullptr) {
|
||||||
Geometry::Transformation supports_trafo = trafo;
|
m_pad_clipper->set_plane(*ocl->get_clipping_plane());
|
||||||
supports_trafo.set_scaling_factor(Vec3d::Ones());
|
m_pad_clipper->set_transformation(inst_trafo);
|
||||||
supports_trafo.set_offset(Vec3d(trafo.get_offset()(0), trafo.get_offset()(1), sel_info->get_sla_shift()));
|
m_pad_clipper->render_cut({ 0.6f, 0.f, 0.222f, 1.0f });
|
||||||
supports_trafo.set_rotation(Vec3d(0., 0., trafo.get_rotation()(2)));
|
}
|
||||||
// I don't know why, but following seems to be correct.
|
|
||||||
supports_trafo.set_mirror(Vec3d(trafo.get_mirror()(0) * trafo.get_mirror()(1) * trafo.get_mirror()(2),
|
|
||||||
1,
|
|
||||||
1.));
|
|
||||||
|
|
||||||
m_clipper->set_plane(*ocl->get_clipping_plane());
|
|
||||||
m_clipper->set_transformation(supports_trafo);
|
|
||||||
|
|
||||||
m_clipper->render_cut({ 1.0f, 0.f, 0.37f, 1.0f });
|
|
||||||
m_clipper->render_contour({ 1.f, 1.f, 1.f, 1.f });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -293,10 +293,10 @@ protected:
|
|||||||
void on_release() override;
|
void on_release() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_old_timestamp = 0;
|
|
||||||
int m_print_object_idx = -1;
|
int m_print_object_idx = -1;
|
||||||
int m_print_objects_count = 0;
|
int m_print_objects_count = 0;
|
||||||
std::unique_ptr<MeshClipper> m_clipper;
|
std::unique_ptr<MeshClipper> m_supports_clipper;
|
||||||
|
std::unique_ptr<MeshClipper> m_pad_clipper;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace CommonGizmosDataObjects
|
} // namespace CommonGizmosDataObjects
|
||||||
|
Loading…
Reference in New Issue
Block a user