ENABLE_SMOOTH_NORMALS (#14080)

* ENABLE_SMOOTH_NORMALS

* Remove definition of macro L if defined

* Update GLModel.cpp

* suavizado ajustado en 5 grados

5 grados

3,5 grados

* Ajuste de brillo menos intenso

* opcion smooth normals

Update GLModel.cpp

test

test 3

* cleaning macros

* tooltip

* Apply suggestion from @RF47

* Apply suggestion from @RF47

* Apply suggestions from code review

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
Rodrigo Faselli
2026-06-18 22:42:12 -03:00
committed by SoftFever
parent 70fd764e7d
commit da7e0540a9
9 changed files with 79 additions and 61 deletions

View File

@@ -10,18 +10,18 @@ const float EPSILON = 0.0001;
// 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.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 128.0
#define LIGHT_TOP_DIFFUSE (0.85 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.35 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 32.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 LIGHT_FRONT_SPECULAR (0.28 * INTENSITY_CORRECTION)
#define LIGHT_FRONT_SHININESS 64.0
#define LIGHT_FRONT_DIFFUSE (0.35 * INTENSITY_CORRECTION)
#define LIGHT_FRONT_SPECULAR (0.12 * INTENSITY_CORRECTION)
#define LIGHT_FRONT_SHININESS 16.0
#define INTENSITY_AMBIENT 0.22
#define WINDOW_REFLECTION_INTENSITY 0.55
#define INTENSITY_AMBIENT 0.25
#define WINDOW_REFLECTION_INTENSITY 0.30
struct PrintVolumeDetection
{
@@ -162,11 +162,11 @@ vec3 compute_window_reflection(vec3 normal, vec3 view_dir)
float bars = 1.0;
// Fresnel effect for edge glow
float fresnel = pow(1.0 - max(dot(normal, view_dir), 0.0), 1.0);
float fresnel = pow(1.0 - max(dot(normal, view_dir), 0.0), 1.2);
float facing = smoothstep(-0.4, 0.6, reflect_light.z);
float intensity = window_light * bars * (0.25 + 0.25 * fresnel) * facing;
intensity = clamp(intensity, 0.0, 0.45);
float intensity = window_light * bars * (0.15 + 0.15 * fresnel) * facing;
intensity = clamp(intensity, 0.0, 0.25);
return vec3(intensity);
}

View File

@@ -10,18 +10,18 @@ const float EPSILON = 0.0001;
// 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.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 128.0
#define LIGHT_TOP_DIFFUSE (0.85 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.35 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 32.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 LIGHT_FRONT_SPECULAR (0.28 * INTENSITY_CORRECTION)
#define LIGHT_FRONT_SHININESS 64.0
#define LIGHT_FRONT_DIFFUSE (0.35 * INTENSITY_CORRECTION)
#define LIGHT_FRONT_SPECULAR (0.12 * INTENSITY_CORRECTION)
#define LIGHT_FRONT_SHININESS 16.0
#define INTENSITY_AMBIENT 0.22
#define WINDOW_REFLECTION_INTENSITY 0.55
#define INTENSITY_AMBIENT 0.25
#define WINDOW_REFLECTION_INTENSITY 0.30
struct PrintVolumeDetection
{
@@ -164,12 +164,13 @@ vec3 compute_window_reflection(vec3 normal, vec3 view_dir)
// No bars - just pure circular glass
float bars = 1.0;
// Fresnel effect for edge glow
float fresnel = pow(1.0 - max(dot(normal, view_dir), 0.0), 1.0);
float fresnel = pow(1.0 - max(dot(normal, view_dir), 0.0), 1.2);
float facing = smoothstep(-0.4, 0.6, reflect_light.z);
float intensity = window_light * bars * (0.25 + 0.25 * fresnel) * facing;
intensity = clamp(intensity, 0.0, 0.45);
float intensity = window_light * bars * (0.15 + 0.15 * fresnel) * facing;
intensity = clamp(intensity, 0.0, 0.25);
return vec3(intensity);
}

View File

@@ -276,6 +276,9 @@ void AppConfig::set_defaults()
if (get(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS).empty())
set_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS, false);
if (get(SETTING_OPENGL_PHONG_SMOOTH_NORMALS).empty())
set_bool(SETTING_OPENGL_PHONG_SMOOTH_NORMALS, false);
if (get(SETTING_OPENGL_PHONG_SSAO).empty())
set_bool(SETTING_OPENGL_PHONG_SSAO, false);

View File

@@ -39,6 +39,7 @@ using namespace nlohmann;
#define SETTING_OPENGL_SHADING_MODEL "opengl_shading_model"
#define SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS "opengl_phong_basic_plate_shadows"
#define SETTING_OPENGL_PHONG_SSAO "opengl_phong_ssao"
#define SETTING_OPENGL_PHONG_SMOOTH_NORMALS "opengl_phong_smooth_normals"
#if defined(_WIN32) || defined(_WIN64)
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.09"

View File

@@ -24,8 +24,7 @@
// Enable rendering of objects using environment map
#define ENABLE_ENVIRONMENT_MAP 0
// Enable smoothing of objects normals
#define ENABLE_SMOOTH_NORMALS 0
// Enable rendering markers for options in preview as fixed screen size points
#define ENABLE_FIXED_SCREEN_SIZE_POINT_MARKERS 1

View File

@@ -758,13 +758,9 @@ int GLVolumeCollection::load_object_volume(
GLVolume& v = *this->volumes.back();
v.set_color(color_from_model_volume(*model_volume));
v.name = model_volume->name;
#if ENABLE_SMOOTH_NORMALS
v.model.init_from(mesh, true);
#else
v.model.init_from(*mesh);
if (need_raycaster) { v.mesh_raycaster = std::make_unique<GUI::MeshRaycaster>(mesh); }
#endif // ENABLE_SMOOTH_NORMALS
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
if (model_volume->is_model_part())
@@ -815,13 +811,9 @@ 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.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);
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(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.

View File

@@ -2793,22 +2793,14 @@ 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.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
@@ -10001,11 +9993,7 @@ void GLCanvas3D::_load_sla_shells()
const TriangleMesh& mesh, const ColorRGBA& color, bool outside_printer_detection_enabled) {
m_volumes.volumes.emplace_back(new GLVolume(color));
GLVolume& v = *m_volumes.volumes.back();
#if ENABLE_SMOOTH_NORMALS
v.model.init_from(mesh, true);
#else
v.model.init_from(mesh);
#endif // ENABLE_SMOOTH_NORMALS
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
v.composite_id.volume_id = volume_id;
v.set_instance_offset(unscale(instance.shift.x(), instance.shift.y(), 0.0));

View File

@@ -14,18 +14,20 @@
#include <boost/filesystem/operations.hpp>
#include <boost/algorithm/string/predicate.hpp>
#if ENABLE_SMOOTH_NORMALS
#if defined(L)
#undef L
#endif
#include <igl/per_face_normals.h>
#include <igl/per_corner_normals.h>
#include <igl/per_vertex_normals.h>
#endif // ENABLE_SMOOTH_NORMALS
#include <glad/gl.h>
namespace Slic3r {
namespace GUI {
#if ENABLE_SMOOTH_NORMALS
static void smooth_normals_corner(const TriangleMesh& mesh, std::vector<stl_normal>& normals)
{
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
@@ -41,7 +43,7 @@ static void smooth_normals_corner(const TriangleMesh& mesh, std::vector<stl_norm
Eigen::Index(face_normals.size()), 3).cast<double>();
Eigen::MatrixXd out_normals;
igl::per_corner_normals(vertices, indices, in_normals, 1.0, out_normals);
igl::per_corner_normals(vertices, indices, 1.0, out_normals);
normals = std::vector<stl_normal>(mesh.its.vertices.size());
for (size_t i = 0; i < mesh.its.indices.size(); ++i) {
@@ -50,7 +52,6 @@ static void smooth_normals_corner(const TriangleMesh& mesh, std::vector<stl_norm
}
}
}
#endif // ENABLE_SMOOTH_NORMALS
void GLModel::Geometry::add_vertex(const Vec2f& position)
{
@@ -455,17 +456,41 @@ void GLModel::init_from(const indexed_triangle_set& its)
data.reserve_vertices(3 * its.indices.size());
data.reserve_indices(3 * its.indices.size());
// vertices + indices
unsigned int vertices_counter = 0;
for (uint32_t i = 0; i < its.indices.size(); ++i) {
const stl_triangle_vertex_indices face = its.indices[i];
const stl_vertex vertex[3] = { its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]] };
const stl_vertex n = face_normal_normalized(vertex);
for (size_t j = 0; j < 3; ++j) {
data.add_vertex(vertex[j], n);
// Read user preference: smooth normals enabled
const bool realistic_mode = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE);
const bool smooth_normals_enabled = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_SMOOTH_NORMALS);
if (realistic_mode && smooth_normals_enabled) {
// Use per-corner smooth normals (via IGL)
using MapMatrixXfUnaligned = Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
using MapMatrixXiUnaligned = Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>>;
Eigen::MatrixXd vertices = MapMatrixXfUnaligned(its.vertices.front().data(), Eigen::Index(its.vertices.size()), 3).cast<double>();
Eigen::MatrixXi indices = MapMatrixXiUnaligned(its.indices.front().data(), Eigen::Index(its.indices.size()), 3);
Eigen::MatrixXd corner_normals;
igl::per_corner_normals(vertices, indices, 5.0, corner_normals);
unsigned int vertices_counter = 0;
for (uint32_t i = 0; i < its.indices.size(); ++i) {
const stl_triangle_vertex_indices face = its.indices[i];
for (size_t j = 0; j < 3; ++j) {
const Vec3f normal = corner_normals.row(Eigen::Index(i * 3 + j)).cast<float>();
data.add_vertex(its.vertices[face[j]], normal);
}
data.add_triangle(vertices_counter, vertices_counter + 1, vertices_counter + 2);
vertices_counter += 3;
}
} else {
//Original flat (per-face) normals
unsigned int vertices_counter = 0;
for (uint32_t i = 0; i < its.indices.size(); ++i) {
const stl_triangle_vertex_indices face = its.indices[i];
const stl_vertex vertex[3] = {its.vertices[face[0]], its.vertices[face[1]], its.vertices[face[2]]};
const stl_vertex n = face_normal_normalized(vertex);
for (size_t j = 0; j < 3; ++j)
data.add_vertex(vertex[j], n);
data.add_triangle(vertices_counter, vertices_counter + 1, vertices_counter + 2);
vertices_counter += 3;
}
vertices_counter += 3;
data.add_triangle(vertices_counter - 3, vertices_counter - 2, vertices_counter - 1);
}
// update bounding box

View File

@@ -1578,6 +1578,15 @@ void PreferencesDialog::create_items()
);
g_sizer->Add(item_realistic_shadows);
auto item_realistic_smooth_normals = create_item_checkbox(
_L("Smooth normals"),
_L("Applies smooth normals to the realistic view.\n\nRequires manual scene reload to take effect "
"(right-click on 3D view → \"Reload All\")."),
SETTING_OPENGL_PHONG_SMOOTH_NORMALS
);
g_sizer->Add(item_realistic_smooth_normals);
//// GRAPHICS > Anti-aliasing
g_sizer->Add(create_item_title(_L("Anti-aliasing")), 1, wxEXPAND);