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:
bubnikv 2019-04-02 13:47:49 +02:00
parent 9594bf43b5
commit 086f11df98
11 changed files with 80 additions and 62 deletions

View file

@ -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(

View file

@ -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;

View file

@ -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)

View file

@ -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);

View file

@ -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)
{

View file

@ -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();

View file

@ -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);