Handling of left hand oriented coordinate systems:
is_left_handed() method on transformations and volumes rendering of GLVolumes in left handed coordinate systems by glFrontFace(GL_CW); SLA slicing on left hand oriented instances by flipping the mesh for SLAPrintObject in X. rendering of the SLA cutting plane in left handed systems resetting the SLA clipping planes on 3D preview invalidation
This commit is contained in:
parent
9594bf43b5
commit
086f11df98
11 changed files with 80 additions and 62 deletions
|
@ -246,6 +246,7 @@ public:
|
|||
|
||||
const Vec3d& get_mirror() const { return m_mirror; }
|
||||
double get_mirror(Axis axis) const { return m_mirror(axis); }
|
||||
bool is_left_handed() const { return m_mirror.x() * m_mirror.y() * m_mirror.z() < 0.; }
|
||||
|
||||
void set_mirror(const Vec3d& mirror);
|
||||
void set_mirror(Axis axis, double mirror);
|
||||
|
|
|
@ -394,6 +394,7 @@ public:
|
|||
|
||||
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
|
||||
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
|
||||
bool is_left_handed() const { return m_transformation.is_left_handed(); }
|
||||
|
||||
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); }
|
||||
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); }
|
||||
|
|
|
@ -93,7 +93,10 @@ static Transform3d sla_trafo(const ModelObject &model_object)
|
|||
offset(0) = 0.;
|
||||
offset(1) = 0.;
|
||||
rotation(2) = 0.;
|
||||
return Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror());
|
||||
Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror());
|
||||
if (model_instance.is_left_handed())
|
||||
trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo;
|
||||
return trafo;
|
||||
}
|
||||
|
||||
// List of instances, where the ModelInstance transformation is a composite of sla_trafo and the transformation defined by SLAPrintObject::Instance.
|
||||
|
@ -399,7 +402,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
|
|||
|
||||
// FIXME: this invalidates the transformed mesh in SLAPrintObject
|
||||
// which is expensive to calculate (especially the raw_mesh() call)
|
||||
print_object->set_trafo(sla_trafo(model_object));
|
||||
print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed());
|
||||
|
||||
print_object->set_instances(new_instances);
|
||||
print_object->config_apply(config, true);
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
|
||||
const SLAPrintObjectConfig& config() const { return m_config; }
|
||||
const Transform3d& trafo() const { return m_trafo; }
|
||||
bool is_left_handed() const { return m_left_handed; }
|
||||
|
||||
struct Instance {
|
||||
Instance(ModelID instance_id, const Point &shift, float rotation) : instance_id(instance_id), shift(shift), rotation(rotation) {}
|
||||
|
@ -241,8 +242,8 @@ protected:
|
|||
void config_apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false)
|
||||
{ this->m_config.apply_only(other, keys, ignore_nonexistent); }
|
||||
|
||||
void set_trafo(const Transform3d& trafo) {
|
||||
m_transformed_rmesh.invalidate([this, &trafo](){ m_trafo = trafo; });
|
||||
void set_trafo(const Transform3d& trafo, bool left_handed) {
|
||||
m_transformed_rmesh.invalidate([this, &trafo, left_handed](){ m_trafo = trafo; m_left_handed = left_handed; });
|
||||
}
|
||||
|
||||
void set_instances(const std::vector<Instance> &instances) { m_instances = instances; }
|
||||
|
@ -262,6 +263,8 @@ private:
|
|||
|
||||
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
|
||||
Transform3d m_trafo = Transform3d::Identity();
|
||||
// m_trafo is left handed -> 3x3 affine transformation has negative determinant.
|
||||
bool m_left_handed = false;
|
||||
|
||||
std::vector<Instance> m_instances;
|
||||
|
||||
|
|
|
@ -333,6 +333,13 @@ Transform3d GLVolume::world_matrix() const
|
|||
return m;
|
||||
}
|
||||
|
||||
bool GLVolume::is_left_handed() const
|
||||
{
|
||||
const Vec3d &m1 = m_instance_transformation.get_mirror();
|
||||
const Vec3d &m2 = m_volume_transformation.get_mirror();
|
||||
return m1.x() * m1.y() * m1.z() * m2.x() * m2.y() * m2.z() < 0.;
|
||||
}
|
||||
|
||||
const BoundingBoxf3& GLVolume::transformed_bounding_box() const
|
||||
{
|
||||
assert(bounding_box.defined || bounding_box.min(0) >= bounding_box.max(0) || bounding_box.min(1) >= bounding_box.max(1) || bounding_box.min(2) >= bounding_box.max(2));
|
||||
|
@ -401,6 +408,8 @@ void GLVolume::render() const
|
|||
if (!is_active)
|
||||
return;
|
||||
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CW);
|
||||
glsafe(::glCullFace(GL_BACK));
|
||||
glsafe(::glPushMatrix());
|
||||
|
||||
|
@ -410,6 +419,8 @@ void GLVolume::render() const
|
|||
else
|
||||
this->indexed_vertex_array.render();
|
||||
glsafe(::glPopMatrix());
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CCW);
|
||||
}
|
||||
|
||||
void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) const
|
||||
|
@ -420,6 +431,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
|
|||
if (!indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)
|
||||
return;
|
||||
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
|
||||
GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
|
||||
if (n_triangles + n_quads == 0)
|
||||
|
@ -481,6 +495,9 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c
|
|||
}
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CCW);
|
||||
}
|
||||
|
||||
void GLVolume::render_legacy() const
|
||||
|
@ -489,6 +506,9 @@ void GLVolume::render_legacy() const
|
|||
if (!is_active)
|
||||
return;
|
||||
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CW);
|
||||
|
||||
GLsizei n_triangles = GLsizei(std::min(indexed_vertex_array.triangle_indices_size, tverts_range.second - tverts_range.first));
|
||||
GLsizei n_quads = GLsizei(std::min(indexed_vertex_array.quad_indices_size, qverts_range.second - qverts_range.first));
|
||||
if (n_triangles + n_quads == 0)
|
||||
|
@ -520,6 +540,9 @@ void GLVolume::render_legacy() const
|
|||
glsafe(::glDrawElements(GL_QUADS, n_quads, GL_UNSIGNED_INT, indexed_vertex_array.quad_indices.data() + qverts_range.first));
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
|
||||
if (this->is_left_handed())
|
||||
glFrontFace(GL_CCW);
|
||||
}
|
||||
|
||||
std::vector<int> GLVolumeCollection::load_object(
|
||||
|
|
|
@ -388,6 +388,7 @@ public:
|
|||
int instance_idx() const { return this->composite_id.instance_id; }
|
||||
|
||||
Transform3d world_matrix() const;
|
||||
bool is_left_handed() const;
|
||||
|
||||
const BoundingBoxf3& transformed_bounding_box() const;
|
||||
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
|
||||
|
|
|
@ -5010,24 +5010,12 @@ void GLCanvas3D::_render_sla_slices() const
|
|||
Pointf3s &top_obj_triangles = it_caps_top->second.object;
|
||||
Pointf3s &top_sup_triangles = it_caps_top->second.supports;
|
||||
|
||||
const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
|
||||
struct InstanceTransform
|
||||
{
|
||||
Vec3d offset;
|
||||
float rotation;
|
||||
};
|
||||
|
||||
std::vector<InstanceTransform> instance_transforms;
|
||||
for (const SLAPrintObject::Instance& inst : instances)
|
||||
{
|
||||
instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) });
|
||||
}
|
||||
|
||||
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) &&
|
||||
obj->is_step_done(slaposSliceSupports) && !obj->get_slice_index().empty())
|
||||
{
|
||||
double layer_height = print->default_object_config().layer_height.value;
|
||||
double initial_layer_height = print->material_config().initial_layer_height.value;
|
||||
bool left_handed = obj->is_left_handed();
|
||||
|
||||
coord_t key_zero = obj->get_slice_index().front().print_level();
|
||||
// Slice at the center of the slab starting at clip_min_z will be rendered for the lower plane.
|
||||
|
@ -5046,10 +5034,10 @@ void GLCanvas3D::_render_sla_slices() const
|
|||
const ExPolygons& sup_bottom = slice_low.get_slice(soSupport);
|
||||
// calculate model bottom cap
|
||||
if (bottom_obj_triangles.empty() && !obj_bottom.empty())
|
||||
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, true);
|
||||
bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z - plane_shift_z, ! left_handed);
|
||||
// calculate support bottom cap
|
||||
if (bottom_sup_triangles.empty() && !sup_bottom.empty())
|
||||
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, true);
|
||||
bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z - plane_shift_z, ! left_handed);
|
||||
}
|
||||
|
||||
if (slice_high.is_valid()) {
|
||||
|
@ -5057,49 +5045,35 @@ void GLCanvas3D::_render_sla_slices() const
|
|||
const ExPolygons& sup_top = slice_high.get_slice(soSupport);
|
||||
// calculate model top cap
|
||||
if (top_obj_triangles.empty() && !obj_top.empty())
|
||||
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, false);
|
||||
top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z + plane_shift_z, left_handed);
|
||||
// calculate support top cap
|
||||
if (top_sup_triangles.empty() && !sup_top.empty())
|
||||
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, false);
|
||||
top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z + plane_shift_z, left_handed);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bottom_obj_triangles.empty() || !top_obj_triangles.empty() || !bottom_sup_triangles.empty() || !top_sup_triangles.empty())
|
||||
{
|
||||
for (const InstanceTransform& inst : instance_transforms)
|
||||
for (const SLAPrintObject::Instance& inst : obj->instances())
|
||||
{
|
||||
::glPushMatrix();
|
||||
::glTranslated(inst.offset(0), inst.offset(1), inst.offset(2));
|
||||
::glRotatef(inst.rotation, 0.0, 0.0, 1.0);
|
||||
|
||||
::glBegin(GL_TRIANGLES);
|
||||
|
||||
::glTranslated(unscale<double>(inst.shift.x()), unscale<double>(inst.shift.y()), 0);
|
||||
::glRotatef(Geometry::rad2deg(inst.rotation), 0.0, 0.0, 1.0);
|
||||
if (obj->is_left_handed())
|
||||
// The polygons are mirrored by X.
|
||||
::glScalef(-1.0, 1.0, 1.0);
|
||||
::glColor3f(1.0f, 0.37f, 0.0f);
|
||||
|
||||
for (const Vec3d& v : bottom_obj_triangles)
|
||||
{
|
||||
::glVertex3dv((GLdouble*)v.data());
|
||||
}
|
||||
|
||||
for (const Vec3d& v : top_obj_triangles)
|
||||
{
|
||||
::glVertex3dv((GLdouble*)v.data());
|
||||
}
|
||||
|
||||
::glColor3f(1.0f, 0.0f, 0.37f);
|
||||
|
||||
for (const Vec3d& v : bottom_sup_triangles)
|
||||
{
|
||||
::glVertex3dv((GLdouble*)v.data());
|
||||
}
|
||||
|
||||
for (const Vec3d& v : top_sup_triangles)
|
||||
{
|
||||
::glVertex3dv((GLdouble*)v.data());
|
||||
}
|
||||
|
||||
::glEnd();
|
||||
|
||||
::glEnableClientState(GL_VERTEX_ARRAY);
|
||||
::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_obj_triangles.front().data());
|
||||
::glDrawArrays(GL_TRIANGLES, 0, bottom_obj_triangles.size());
|
||||
::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_obj_triangles.front().data());
|
||||
::glDrawArrays(GL_TRIANGLES, 0, top_obj_triangles.size());
|
||||
::glColor3f(1.0f, 0.0f, 0.37f);
|
||||
::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)bottom_sup_triangles.front().data());
|
||||
::glDrawArrays(GL_TRIANGLES, 0, bottom_sup_triangles.size());
|
||||
::glVertexPointer(3, GL_DOUBLE, 0, (GLdouble*)top_sup_triangles.front().data());
|
||||
::glDrawArrays(GL_TRIANGLES, 0, top_sup_triangles.size());
|
||||
::glDisableClientState(GL_VERTEX_ARRAY);
|
||||
::glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
@ -6217,6 +6191,8 @@ void GLCanvas3D::_load_shells_fff()
|
|||
|
||||
void GLCanvas3D::_load_shells_sla()
|
||||
{
|
||||
//FIXME use reload_scene
|
||||
#if 1
|
||||
const SLAPrint* print = this->sla_print();
|
||||
if (print->objects().empty())
|
||||
// nothing to render, return
|
||||
|
@ -6240,9 +6216,7 @@ void GLCanvas3D::_load_shells_sla()
|
|||
|
||||
m_volumes.load_object(model_obj, obj_idx, instance_idxs, "object", m_use_VBOs && m_initialized);
|
||||
|
||||
const std::vector<SLAPrintObject::Instance>& instances = obj->instances();
|
||||
|
||||
for (const SLAPrintObject::Instance& instance : instances)
|
||||
for (const SLAPrintObject::Instance& instance : obj->instances())
|
||||
{
|
||||
Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0);
|
||||
Vec3d rotation(0.0, 0.0, (double)instance.rotation);
|
||||
|
@ -6265,6 +6239,7 @@ void GLCanvas3D::_load_shells_sla()
|
|||
v.composite_id.volume_id = -1;
|
||||
v.set_instance_offset(offset);
|
||||
v.set_instance_rotation(rotation);
|
||||
v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.);
|
||||
}
|
||||
|
||||
// add pad
|
||||
|
@ -6283,6 +6258,7 @@ void GLCanvas3D::_load_shells_sla()
|
|||
v.composite_id.volume_id = -1;
|
||||
v.set_instance_offset(offset);
|
||||
v.set_instance_rotation(rotation);
|
||||
v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.);
|
||||
}
|
||||
|
||||
// finalize volumes and sends geometry to gpu
|
||||
|
@ -6305,6 +6281,9 @@ void GLCanvas3D::_load_shells_sla()
|
|||
}
|
||||
|
||||
update_volumes_colors_by_extruder();
|
||||
#else
|
||||
this->reload_scene(true, true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data)
|
||||
|
|
|
@ -634,6 +634,7 @@ public:
|
|||
m_sla_caps[id].reset();
|
||||
}
|
||||
}
|
||||
void reset_clipping_planes_cache() { m_sla_caps[0].triangles.clear(); m_sla_caps[1].triangles.clear(); }
|
||||
void set_use_clipping_planes(bool use) { m_use_clipping_planes = use; }
|
||||
|
||||
void set_color_by(const std::string& value);
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
|
||||
View3D::View3D(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process)
|
||||
: m_canvas_widget(nullptr)
|
||||
, m_canvas(nullptr)
|
||||
{
|
||||
|
@ -155,7 +155,9 @@ void View3D::render()
|
|||
m_canvas->set_as_dirty();
|
||||
}
|
||||
|
||||
Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
|
||||
Preview::Preview(
|
||||
wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
|
||||
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process_func)
|
||||
: m_canvas_widget(nullptr)
|
||||
, m_canvas(nullptr)
|
||||
, m_double_slider_sizer(nullptr)
|
||||
|
@ -179,14 +181,14 @@ Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_t
|
|||
, m_volumes_cleanup_required(false)
|
||||
#endif // __linux__
|
||||
{
|
||||
if (init(parent, bed, camera, view_toolbar))
|
||||
if (init(parent, bed, camera, view_toolbar, model))
|
||||
{
|
||||
show_hide_ui_elements("none");
|
||||
load_print();
|
||||
}
|
||||
}
|
||||
|
||||
bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar)
|
||||
bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model)
|
||||
{
|
||||
if (!Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 /* disable wxTAB_TRAVERSAL */))
|
||||
return false;
|
||||
|
@ -196,6 +198,7 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
|
|||
m_canvas = _3DScene::get_canvas(this->m_canvas_widget);
|
||||
m_canvas->allow_multisample(GLCanvas3DManager::can_multisample());
|
||||
m_canvas->set_config(m_config);
|
||||
m_canvas->set_model(model);
|
||||
m_canvas->set_process(m_process);
|
||||
m_canvas->enable_legend_texture(true);
|
||||
m_canvas->enable_dynamic_background(true);
|
||||
|
@ -781,6 +784,8 @@ void Preview::load_print_as_sla()
|
|||
}
|
||||
sort_remove_duplicates(zs);
|
||||
|
||||
m_canvas->reset_clipping_planes_cache();
|
||||
|
||||
n_layers = (unsigned int)zs.size();
|
||||
if (n_layers == 0)
|
||||
{
|
||||
|
|
|
@ -102,7 +102,8 @@ class Preview : public wxPanel
|
|||
PrusaDoubleSlider* m_slider {nullptr};
|
||||
|
||||
public:
|
||||
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, DynamicPrintConfig* config, BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
|
||||
Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model, DynamicPrintConfig* config,
|
||||
BackgroundSlicingProcess* process, GCodePreviewData* gcode_preview_data, std::function<void()> schedule_background_process = [](){});
|
||||
virtual ~Preview();
|
||||
|
||||
wxGLCanvas* get_wxglcanvas() { return m_canvas_widget; }
|
||||
|
@ -120,7 +121,7 @@ public:
|
|||
void refresh_print();
|
||||
|
||||
private:
|
||||
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
|
||||
bool init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar, Model* model);
|
||||
|
||||
void bind_event_handlers();
|
||||
void unbind_event_handlers();
|
||||
|
|
|
@ -1350,7 +1350,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
this->q->Bind(EVT_SLICING_UPDATE, &priv::on_slicing_update, this);
|
||||
|
||||
view3D = new View3D(q, bed, camera, view_toolbar, &model, config, &background_process);
|
||||
preview = new Preview(q, bed, camera, view_toolbar, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });
|
||||
preview = new Preview(q, bed, camera, view_toolbar, &model, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); });
|
||||
|
||||
panels.push_back(view3D);
|
||||
panels.push_back(preview);
|
||||
|
|
Loading…
Reference in a new issue