From aa92cbf051b56c7174079d8d1cfc42c2440847ad Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 2 Jun 2020 10:02:50 +0200 Subject: [PATCH] New tech ENABLE_SMOOTH_NORMALS (disabled) -> Added two experimental functions to smooth normals using libigl (none of them working properly in detecting edges) when calling GLIndexedVertexArray::load_mesh_full_shading() --- src/libslic3r/Technologies.hpp | 3 + src/slic3r/GUI/3DScene.cpp | 118 ++++++++++++++++++++++++++++++--- src/slic3r/GUI/3DScene.hpp | 7 +- src/slic3r/GUI/GLCanvas3D.cpp | 16 ++++- 4 files changed, 131 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index b29b1a7f6..0c5720c6b 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -45,5 +45,8 @@ // Enable rendering of objects using environment map #define ENABLE_ENVIRONMENT_MAP (1 && ENABLE_2_3_0_ALPHA1) +// Enable smoothing of objects normals +#define ENABLE_SMOOTH_NORMALS (0 && ENABLE_2_3_0_ALPHA1) + #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4c61270cf..dc57500c4 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1,5 +1,11 @@ #include +#if ENABLE_SMOOTH_NORMALS +#include +#include +#include +#endif // ENABLE_SMOOTH_NORMALS + #include "3DScene.hpp" #if ENABLE_ENVIRONMENT_MAP #include "GUI_App.hpp" @@ -57,23 +63,107 @@ void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char namespace Slic3r { -void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh) +#if ENABLE_SMOOTH_NORMALS +static void smooth_normals_corner(TriangleMesh& mesh, std::vector& normals) +{ + mesh.repair(); + + using MapMatrixXfUnaligned = Eigen::Map>; + using MapMatrixXiUnaligned = Eigen::Map>; + + std::vector face_normals(mesh.stl.stats.number_of_facets); + for (uint32_t i = 0; i < mesh.stl.stats.number_of_facets; ++i) { + face_normals[i] = mesh.stl.facet_start[i].normal; + } + + Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), + Eigen::Index(mesh.its.vertices.size()), 3).cast(); + Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), + Eigen::Index(mesh.its.indices.size()), 3); + Eigen::MatrixXd in_normals = MapMatrixXfUnaligned(face_normals.front().data(), + Eigen::Index(face_normals.size()), 3).cast(); + Eigen::MatrixXd out_normals; + + igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals); + + normals = std::vector(mesh.its.vertices.size()); + for (size_t i = 0; i < mesh.its.indices.size(); ++i) { + for (size_t j = 0; j < 3; ++j) { + normals[mesh.its.indices[i][j]] = out_normals.row(i * 3 + j).cast(); + } + } +} + +static void smooth_normals_vertex(TriangleMesh& mesh, std::vector& normals) +{ + mesh.repair(); + + using MapMatrixXfUnaligned = Eigen::Map>; + using MapMatrixXiUnaligned = Eigen::Map>; + + Eigen::MatrixXd vertices = MapMatrixXfUnaligned(mesh.its.vertices.front().data(), + Eigen::Index(mesh.its.vertices.size()), 3).cast(); + Eigen::MatrixXi indices = MapMatrixXiUnaligned(mesh.its.indices.front().data(), + Eigen::Index(mesh.its.indices.size()), 3); + Eigen::MatrixXd out_normals; + +// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM, out_normals); +// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA, out_normals); + igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE, out_normals); +// igl::per_vertex_normals(vertices, indices, igl::PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT, out_normals); + + normals = std::vector(mesh.its.vertices.size()); + for (size_t i = 0; i < static_cast(out_normals.rows()); ++i) { + normals[i] = out_normals.row(i).cast(); + } +} +#endif // ENABLE_SMOOTH_NORMALS + +#if ENABLE_SMOOTH_NORMALS +void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals) +#else +void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh& mesh) +#endif // ENABLE_SMOOTH_NORMALS { assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0); assert(quad_indices.empty() && triangle_indices_size == 0); assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size()); - this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count()); +#if ENABLE_SMOOTH_NORMALS + if (smooth_normals) { + TriangleMesh new_mesh(mesh); + std::vector normals; + smooth_normals_corner(new_mesh, normals); +// smooth_normals_vertex(new_mesh, normals); - unsigned int vertices_count = 0; - for (int i = 0; i < (int)mesh.stl.stats.number_of_facets; ++i) { - const stl_facet &facet = mesh.stl.facet_start[i]; - for (int j = 0; j < 3; ++j) - this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2)); + this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 2 * new_mesh.its.vertices.size()); + for (size_t i = 0; i < new_mesh.its.vertices.size(); ++i) { + const stl_vertex& v = new_mesh.its.vertices[i]; + const stl_normal& n = normals[i]; + this->push_geometry(v(0), v(1), v(2), n(0), n(1), n(2)); + } - this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); - vertices_count += 3; + for (size_t i = 0; i < new_mesh.its.indices.size(); ++i) { + const stl_triangle_vertex_indices& idx = new_mesh.its.indices[i]; + this->push_triangle(idx(0), idx(1), idx(2)); + } } + else { +#endif // ENABLE_SMOOTH_NORMALS + this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count()); + + unsigned int vertices_count = 0; + for (int i = 0; i < (int)mesh.stl.stats.number_of_facets; ++i) { + const stl_facet& facet = mesh.stl.facet_start[i]; + for (int j = 0; j < 3; ++j) + this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2)); + + this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2); + vertices_count += 3; + } +#if ENABLE_SMOOTH_NORMALS + } +#endif // ENABLE_SMOOTH_NORMALS } void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized) @@ -462,7 +552,11 @@ int GLVolumeCollection::load_object_volume( this->volumes.emplace_back(new GLVolume(color)); GLVolume& v = *this->volumes.back(); v.set_color_from_model_volume(model_volume); +#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); v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx); if (model_volume->is_model_part()) @@ -504,8 +598,12 @@ void GLVolumeCollection::load_object_auxiliary( 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_SMOOTH_NORMALS + v.indexed_vertex_array.load_mesh(mesh, true); +#else v.indexed_vertex_array.load_mesh(mesh); - v.indexed_vertex_array.finalize_geometry(opengl_initialized); +#endif // ENABLE_SMOOTH_NORMALS + v.indexed_vertex_array.finalize_geometry(opengl_initialized); v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first); v.geometry_id = std::pair(timestamp, model_instance.id().id); // Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance. diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 1401e79fb..da111d7aa 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -125,8 +125,13 @@ public: unsigned int triangle_indices_VBO_id{ 0 }; unsigned int quad_indices_VBO_id{ 0 }; - void load_mesh_full_shading(const TriangleMesh &mesh); +#if ENABLE_SMOOTH_NORMALS + void load_mesh_full_shading(const TriangleMesh& mesh, bool smooth_normals = false); + void load_mesh(const TriangleMesh& mesh, bool smooth_normals = false) { this->load_mesh_full_shading(mesh, smooth_normals); } +#else + void load_mesh_full_shading(const TriangleMesh& mesh); void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); } +#endif // ENABLE_SMOOTH_NORMALS inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 69bebc301..9c4a8d2b3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2491,11 +2491,19 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re TriangleMesh mesh = print_object->get_mesh(slaposDrillHoles); assert(! mesh.empty()); mesh.transform(sla_print->sla_trafo(*m_model->objects[volume.object_idx()]).inverse()); +#if ENABLE_SMOOTH_NORMALS + volume.indexed_vertex_array.load_mesh(mesh, true); +#else volume.indexed_vertex_array.load_mesh(mesh); - } else { +#endif // ENABLE_SMOOTH_NORMALS + } else { // Reload the original volume. +#if ENABLE_SMOOTH_NORMALS + volume.indexed_vertex_array.load_mesh(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()); - } +#endif // ENABLE_SMOOTH_NORMALS + } volume.finalize_geometry(true); } //FIXME it is an ugly hack to write the timestamp into the "offsets" field to not have to add another member variable @@ -6814,7 +6822,11 @@ void GLCanvas3D::_load_sla_shells() const TriangleMesh &mesh, const float color[4], bool outside_printer_detection_enabled) { m_volumes.volumes.emplace_back(new GLVolume(color)); GLVolume& v = *m_volumes.volumes.back(); +#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(this->m_initialized); v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled; v.composite_id.volume_id = volume_id;