mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-06 17:47:41 +00:00
Realistic View: Phong Shading + Ambient Oclusion + Cast Shadows (#13704)
* Phong Shading * Add shader selection to graphics preferences * SSAO * 3D canvas menu Co-Authored-By: yw4z <yw4z@outlook.com> * better SSAO * Adjust * phong in preview mode * cast shadows sombra 3 sombra 2 * fix 1 * SSAO independent * Fix 2 * clean 1 * shadows availables with gouraud * Update Preferences.cpp * tweeks * No Normal textures * Depth texture allocation * avoid rebinding/redefining state each render. * free SSAO * set shadow fill color * remove duplicated code * cached model to avoid per-frame uploads * yw4z suggestion Co-Authored-By: yw4z <yw4z@outlook.com> * Update Preferences.cpp Co-Authored-By: yw4z <yw4z@outlook.com> * Update GLCanvas3D.cpp * only gouraud for preview mode * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Add new OpenGL shading model setting * Update src/slic3r/GUI/GLCanvas3D.cpp * Apply suggestion from @RF47 * Title Case * normal textures * gamma 2.2 Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com> * Revert "gamma 2.2" This reverts commit 909a84af604a080b3f4b8dd67d13956473a77afe. * Reapply "gamma 2.2" This reverts commit 0f0c3d9ec0d2c9647ce06afac4fe9266b5ffda97. * AO blend Co-Authored-By: Ian Bassi <12130714+ianalexis@users.noreply.github.com> * Revert "AO blend" This reverts commit c5c9a3aa6b295704e71299451b937648e5c5f109. * 4.0 pixel radius * windows light effect direccion brillo * smoothing * ajuste de brillo * ajustes de brillo * No SSAO for bed * disable realistic view on paint gismos * Update ssao.fs * circular panel --------- Co-authored-by: yw4z <yw4z@outlook.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ian Bassi <ian.bassi@outlook.com> Co-authored-by: Ian Bassi <12130714+ianalexis@users.noreply.github.com> Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
@@ -264,6 +264,21 @@ void AppConfig::set_defaults()
|
||||
if (get(SETTING_OPENGL_SHOW_FPS_OVERLAY).empty())
|
||||
set_bool(SETTING_OPENGL_SHOW_FPS_OVERLAY, false);
|
||||
|
||||
if (get(SETTING_OPENGL_REALISTIC_MODE).empty())
|
||||
set_bool(SETTING_OPENGL_REALISTIC_MODE, false);
|
||||
|
||||
if (get(SETTING_OPENGL_REALISTIC_PHONG).empty())
|
||||
set_bool(SETTING_OPENGL_REALISTIC_PHONG, true);
|
||||
|
||||
if (get(SETTING_OPENGL_SHADING_MODEL).empty())
|
||||
set(SETTING_OPENGL_SHADING_MODEL, "gouraud");
|
||||
|
||||
if (get(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS).empty())
|
||||
set_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS, false);
|
||||
|
||||
if (get(SETTING_OPENGL_PHONG_SSAO).empty())
|
||||
set_bool(SETTING_OPENGL_PHONG_SSAO, false);
|
||||
|
||||
if (get("export_sources_full_pathnames").empty())
|
||||
set_bool("export_sources_full_pathnames", false);
|
||||
|
||||
|
||||
@@ -34,6 +34,11 @@ using namespace nlohmann;
|
||||
#define SETTING_OPENGL_FXAA_ENABLED "opengl_fxaa_enabled"
|
||||
#define SETTING_OPENGL_FPS_CAP "opengl_fps_cap"
|
||||
#define SETTING_OPENGL_SHOW_FPS_OVERLAY "opengl_show_fps_overlay"
|
||||
#define SETTING_OPENGL_REALISTIC_MODE "opengl_realistic_mode"
|
||||
#define SETTING_OPENGL_REALISTIC_PHONG "opengl_realistic_phong"
|
||||
#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"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define BAMBU_NETWORK_AGENT_VERSION_LEGACY "01.10.01.09"
|
||||
|
||||
@@ -1218,10 +1218,22 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed)
|
||||
|
||||
GLCanvas3D::~GLCanvas3D()
|
||||
{
|
||||
if (m_fxaa_texture_id != 0 && _set_current()) {
|
||||
glsafe(::glDeleteTextures(1, &m_fxaa_texture_id));
|
||||
m_fxaa_texture_id = 0;
|
||||
if (_set_current()) {
|
||||
if (m_fxaa_texture_id != 0) {
|
||||
glsafe(::glDeleteTextures(1, &m_fxaa_texture_id));
|
||||
m_fxaa_texture_id = 0;
|
||||
}
|
||||
if (m_ssao_color_texture_id != 0) {
|
||||
glsafe(::glDeleteTextures(1, &m_ssao_color_texture_id));
|
||||
m_ssao_color_texture_id = 0;
|
||||
}
|
||||
if (m_ssao_depth_texture_id != 0) {
|
||||
glsafe(::glDeleteTextures(1, &m_ssao_depth_texture_id));
|
||||
m_ssao_depth_texture_id = 0;
|
||||
}
|
||||
m_plate_shadow_mask.reset();
|
||||
}
|
||||
m_plate_shadow_mask_key.clear();
|
||||
|
||||
reset_volumes();
|
||||
|
||||
@@ -2039,14 +2051,16 @@ void GLCanvas3D::render(bool only_init)
|
||||
/* view3D render*/
|
||||
int hover_id = (m_hover_plate_idxs.size() > 0)?m_hover_plate_idxs.front():-1;
|
||||
if (m_canvas_type == ECanvasType::CanvasView3D) {
|
||||
//BBS: add outline logic
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
if (!no_partplate)
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
if (!no_partplate) //BBS: add outline logic
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid);
|
||||
|
||||
//BBS: add outline logic
|
||||
_render_cast_shadows_on_plate(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
_render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running());
|
||||
_render_sla_slices();
|
||||
_render_selection();
|
||||
_render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running());
|
||||
}
|
||||
/* preview render */
|
||||
@@ -2103,6 +2117,9 @@ void GLCanvas3D::render(bool only_init)
|
||||
if (m_picking_enabled && m_rectangle_selection.is_dragging())
|
||||
m_rectangle_selection.render(*this);
|
||||
|
||||
if (_is_ssao_enabled())
|
||||
_render_ssao_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
if (_is_fxaa_enabled())
|
||||
_render_fxaa_pass(static_cast<unsigned int>(cnv_size.get_width()), static_cast<unsigned int>(cnv_size.get_height()));
|
||||
|
||||
@@ -7502,6 +7519,14 @@ bool GLCanvas3D::_is_fxaa_enabled() const
|
||||
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_FXAA_ENABLED);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_ssao_enabled() const
|
||||
{
|
||||
if (wxGetApp().app_config == nullptr)
|
||||
return false;
|
||||
return wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE) &&
|
||||
wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_SSAO);
|
||||
}
|
||||
|
||||
int GLCanvas3D::_get_effective_fps_cap() const
|
||||
{
|
||||
if (wxGetApp().app_config == nullptr)
|
||||
@@ -7596,6 +7621,159 @@ void GLCanvas3D::_render_fxaa_pass(unsigned int width, unsigned int height)
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_ssao_pass(unsigned int width, unsigned int height)
|
||||
{
|
||||
if (width == 0 || height == 0)
|
||||
return;
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("ssao");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
if (m_ssao_color_texture_id == 0) {
|
||||
glsafe(::glGenTextures(1, &m_ssao_color_texture_id));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_color_texture_id));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
}
|
||||
if (m_ssao_depth_texture_id == 0) {
|
||||
glsafe(::glGenTextures(1, &m_ssao_depth_texture_id));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_depth_texture_id));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
}
|
||||
|
||||
if (m_ssao_texture_size[0] != width || m_ssao_texture_size[1] != height) {
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_color_texture_id));
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_depth_texture_id));
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr));
|
||||
m_ssao_texture_size = { { width, height } };
|
||||
}
|
||||
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_color_texture_id));
|
||||
glsafe(::glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_depth_texture_id));
|
||||
glsafe(::glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height));
|
||||
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
|
||||
GLint prev_stencil_mask = 0xFF;
|
||||
glsafe(::glGetIntegerv(GL_STENCIL_WRITEMASK, &prev_stencil_mask));
|
||||
GLboolean prev_stencil_test = GL_FALSE;
|
||||
glsafe(::glGetBooleanv(GL_STENCIL_TEST, &prev_stencil_test));
|
||||
GLboolean prev_depth_mask = GL_TRUE;
|
||||
glsafe(::glGetBooleanv(GL_DEPTH_WRITEMASK, &prev_depth_mask));
|
||||
GLint prev_depth_func = GL_LESS;
|
||||
glsafe(::glGetIntegerv(GL_DEPTH_FUNC, &prev_depth_func));
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
// Build stencil mask for bed/plate and apply SSAO only outside this mask.
|
||||
glsafe(::glEnable(GL_STENCIL_TEST));
|
||||
glsafe(::glStencilMask(0xFF));
|
||||
glsafe(::glClearStencil(0));
|
||||
glsafe(::glClear(GL_STENCIL_BUFFER_BIT));
|
||||
glsafe(::glStencilFunc(GL_ALWAYS, 1, 0xFF));
|
||||
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
// Mark only visible plate pixels (do not exclude objects in front of plate).
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDepthMask(GL_FALSE));
|
||||
glsafe(::glDepthFunc(GL_LEQUAL));
|
||||
|
||||
GLboolean prev_color_mask[4] = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE };
|
||||
glsafe(::glGetBooleanv(GL_COLOR_WRITEMASK, prev_color_mask));
|
||||
glsafe(::glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
|
||||
|
||||
if (const BuildVolume& build_volume = m_bed.build_volume(); build_volume.valid()) {
|
||||
GLShaderProgram* flat = wxGetApp().get_shader("flat");
|
||||
if (flat != nullptr) {
|
||||
flat->start_using();
|
||||
flat->set_uniform("projection_matrix", camera.get_projection_matrix());
|
||||
|
||||
GLModel plate_mask;
|
||||
GLModel::Geometry mask;
|
||||
mask.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
|
||||
|
||||
if (build_volume.type() == BuildVolume_Type::Rectangle) {
|
||||
const BoundingBox3Base<Vec3d> bb = build_volume.bounding_volume();
|
||||
mask.reserve_vertices(4);
|
||||
mask.reserve_indices(6);
|
||||
mask.add_vertex(Vec3f((float)bb.min.x(), (float)bb.min.y(), 0.0f));
|
||||
mask.add_vertex(Vec3f((float)bb.max.x(), (float)bb.min.y(), 0.0f));
|
||||
mask.add_vertex(Vec3f((float)bb.max.x(), (float)bb.max.y(), 0.0f));
|
||||
mask.add_vertex(Vec3f((float)bb.min.x(), (float)bb.max.y(), 0.0f));
|
||||
mask.add_triangle(0, 1, 2);
|
||||
mask.add_triangle(0, 2, 3);
|
||||
} else if (build_volume.type() == BuildVolume_Type::Circle) {
|
||||
const Vec2f c = Vec2f(unscaled<float>(build_volume.circle().center.x()), unscaled<float>(build_volume.circle().center.y()));
|
||||
const float r = unscaled<float>(build_volume.circle().radius);
|
||||
const int segments = 64;
|
||||
mask.reserve_vertices(segments + 1);
|
||||
mask.reserve_indices(segments * 3);
|
||||
mask.add_vertex(Vec3f(c.x(), c.y(), 0.0f));
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
const float a = (2.0f * float(PI) * float(i)) / float(segments);
|
||||
mask.add_vertex(Vec3f(c.x() + r * std::cos(a), c.y() + r * std::sin(a), 0.0f));
|
||||
}
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
const unsigned int i1 = 1 + i;
|
||||
const unsigned int i2 = 1 + ((i + 1) % segments);
|
||||
mask.add_triangle(0, i1, i2);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask.vertices_count() > 0 && mask.indices_count() > 0) {
|
||||
plate_mask.init_from(std::move(mask));
|
||||
flat->set_uniform("view_model_matrix", camera.get_view_matrix());
|
||||
plate_mask.render(flat);
|
||||
}
|
||||
flat->stop_using();
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glStencilMask(0x00));
|
||||
glsafe(::glStencilFunc(GL_NOTEQUAL, 1, 0xFF));
|
||||
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
|
||||
|
||||
shader->start_using();
|
||||
shader->set_uniform("view_model_matrix", Transform3d::Identity());
|
||||
shader->set_uniform("projection_matrix", Transform3d::Identity());
|
||||
shader->set_uniform("color_texture", 0);
|
||||
shader->set_uniform("depth_texture", 1);
|
||||
shader->set_uniform("inv_tex_size", Vec2f(1.0f / static_cast<float>(width), 1.0f / static_cast<float>(height)));
|
||||
shader->set_uniform("z_near", camera.get_near_z());
|
||||
shader->set_uniform("z_far", camera.get_far_z());
|
||||
|
||||
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_color_texture_id));
|
||||
glsafe(::glActiveTexture(GL_TEXTURE1));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_depth_texture_id));
|
||||
m_background.render();
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
shader->stop_using();
|
||||
|
||||
if (!prev_stencil_test)
|
||||
glsafe(::glDisable(GL_STENCIL_TEST));
|
||||
glsafe(::glStencilMask(prev_stencil_mask));
|
||||
glsafe(::glColorMask(prev_color_mask[0], prev_color_mask[1], prev_color_mask[2], prev_color_mask[3]));
|
||||
|
||||
glsafe(::glDepthMask(prev_depth_mask));
|
||||
glsafe(::glDepthFunc(prev_depth_func));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_background()
|
||||
{
|
||||
bool use_error_color = false;
|
||||
@@ -7686,6 +7864,206 @@ void GLCanvas3D::_render_platelist(const Transform3d& view_matrix, const Transfo
|
||||
wxGetApp().plater()->get_partplate_list().render(view_matrix, projection_matrix, bottom, only_current, only_body, hover_id, render_cali, show_grid);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_cast_shadows_on_plate(const Transform3d& view_matrix, const Transform3d& projection_matrix)
|
||||
{
|
||||
// Check if shadow rendering is enabled in configuration
|
||||
if (wxGetApp().app_config == nullptr)
|
||||
return;
|
||||
if (!wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE))
|
||||
return;
|
||||
if (!wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS))
|
||||
return;
|
||||
if (m_volumes.empty())
|
||||
return;
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("flat");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
||||
// Fixed light direction (pointing downward at an angle)
|
||||
// Drive shadow direction from current view angle: define light in eye-space,
|
||||
// then transform it to world-space with inverse view rotation.
|
||||
const Vec3d light_dir_eye = Vec3d(-0.4574957, 0.4574957, 0.7624929).normalized();
|
||||
const Matrix3d view_rot = view_matrix.matrix().block<3, 3>(0, 0);
|
||||
const Vec3d light_dir_to_light = (view_rot.transpose() * light_dir_eye).normalized();
|
||||
const Vec3d ray_dir = -light_dir_to_light; // Direction of shadow projection
|
||||
|
||||
if (std::abs(ray_dir.z()) < 1e-6)
|
||||
return;
|
||||
|
||||
// Shadow projection matrix - flattens geometry onto Z=0 plane along light direction
|
||||
Matrix4d shadow_proj = Matrix4d::Identity();
|
||||
shadow_proj(0, 2) = -ray_dir.x() / ray_dir.z();
|
||||
shadow_proj(1, 2) = -ray_dir.y() / ray_dir.z();
|
||||
shadow_proj(2, 0) = 0.0;
|
||||
shadow_proj(2, 1) = 0.0;
|
||||
shadow_proj(2, 2) = 0.0;
|
||||
shadow_proj(2, 3) = 0.01; // Bias to prevent shadow acne
|
||||
|
||||
// Save OpenGL state
|
||||
GLint prev_depth_func = GL_LESS;
|
||||
glsafe(::glGetIntegerv(GL_DEPTH_FUNC, &prev_depth_func));
|
||||
GLboolean prev_depth_mask = GL_TRUE;
|
||||
glsafe(::glGetBooleanv(GL_DEPTH_WRITEMASK, &prev_depth_mask));
|
||||
GLint prev_stencil_mask = 0xFF;
|
||||
glsafe(::glGetIntegerv(GL_STENCIL_WRITEMASK, &prev_stencil_mask));
|
||||
GLboolean prev_stencil_test = GL_FALSE;
|
||||
glsafe(::glGetBooleanv(GL_STENCIL_TEST, &prev_stencil_test));
|
||||
|
||||
// ============================================================
|
||||
// PASS 0: Create stencil mask for the build plate (value = 1)
|
||||
// ============================================================
|
||||
glsafe(::glEnable(GL_STENCIL_TEST));
|
||||
glsafe(::glStencilMask(0xFF));
|
||||
glsafe(::glClearStencil(0));
|
||||
glsafe(::glClear(GL_STENCIL_BUFFER_BIT));
|
||||
|
||||
glsafe(::glStencilFunc(GL_ALWAYS, 1, 0xFF));
|
||||
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE));
|
||||
|
||||
glsafe(::glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE));
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
shader->start_using();
|
||||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
|
||||
// Draw the build plate (cached model to avoid per-frame uploads)
|
||||
if (const BuildVolume& build_volume = m_bed.build_volume(); build_volume.valid()) {
|
||||
const std::string mask_key = build_volume.type() == BuildVolume_Type::Rectangle
|
||||
? (boost::format("rect|%1$.5f|%2$.5f|%3$.5f|%4$.5f")
|
||||
% build_volume.bounding_volume().min.x()
|
||||
% build_volume.bounding_volume().min.y()
|
||||
% build_volume.bounding_volume().max.x()
|
||||
% build_volume.bounding_volume().max.y()).str()
|
||||
: (build_volume.type() == BuildVolume_Type::Circle
|
||||
? (boost::format("circle|%1$.5f|%2$.5f|%3$.5f")
|
||||
% unscaled<double>(build_volume.circle().center.x())
|
||||
% unscaled<double>(build_volume.circle().center.y())
|
||||
% unscaled<double>(build_volume.circle().radius)).str()
|
||||
: std::string("invalid"));
|
||||
|
||||
if (mask_key != m_plate_shadow_mask_key) {
|
||||
m_plate_shadow_mask.reset();
|
||||
m_plate_shadow_mask_key = mask_key;
|
||||
|
||||
GLModel::Geometry mask;
|
||||
mask.format = { GLModel::Geometry::EPrimitiveType::Triangles, GLModel::Geometry::EVertexLayout::P3 };
|
||||
|
||||
if (build_volume.type() == BuildVolume_Type::Rectangle) {
|
||||
const BoundingBox3Base<Vec3d> bb = build_volume.bounding_volume();
|
||||
mask.reserve_vertices(4);
|
||||
mask.reserve_indices(6);
|
||||
mask.add_vertex(Vec3f((float)bb.min.x(), (float)bb.min.y(), 0.0f));
|
||||
mask.add_vertex(Vec3f((float)bb.max.x(), (float)bb.min.y(), 0.0f));
|
||||
mask.add_vertex(Vec3f((float)bb.max.x(), (float)bb.max.y(), 0.0f));
|
||||
mask.add_vertex(Vec3f((float)bb.min.x(), (float)bb.max.y(), 0.0f));
|
||||
mask.add_triangle(0, 1, 2);
|
||||
mask.add_triangle(0, 2, 3);
|
||||
}
|
||||
else if (build_volume.type() == BuildVolume_Type::Circle) {
|
||||
const Vec2f c = Vec2f(unscaled<float>(build_volume.circle().center.x()), unscaled<float>(build_volume.circle().center.y()));
|
||||
const float r = unscaled<float>(build_volume.circle().radius);
|
||||
const int segments = 64;
|
||||
mask.reserve_vertices(segments + 1);
|
||||
mask.reserve_indices(segments * 3);
|
||||
mask.add_vertex(Vec3f(c.x(), c.y(), 0.0f));
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
const float a = (2.0f * float(PI) * float(i)) / float(segments);
|
||||
mask.add_vertex(Vec3f(c.x() + r * std::cos(a), c.y() + r * std::sin(a), 0.0f));
|
||||
}
|
||||
for (int i = 0; i < segments; ++i) {
|
||||
const unsigned int i1 = 1 + i;
|
||||
const unsigned int i2 = 1 + ((i + 1) % segments);
|
||||
mask.add_triangle(0, i1, i2);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask.vertices_count() > 0 && mask.indices_count() > 0)
|
||||
m_plate_shadow_mask.init_from(std::move(mask));
|
||||
}
|
||||
|
||||
if (m_plate_shadow_mask.is_initialized()) {
|
||||
shader->set_uniform("view_model_matrix", view_matrix);
|
||||
m_plate_shadow_mask.render(shader);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PASS 1: Project object shadows onto plate (increment stencil to 2)
|
||||
// ============================================================
|
||||
// Only render where plate exists (stencil == 1), then increment to 2
|
||||
glsafe(::glStencilFunc(GL_EQUAL, 1, 0xFF));
|
||||
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_INCR));
|
||||
|
||||
glsafe(::glDepthMask(GL_FALSE));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDepthFunc(GL_ALWAYS)); // Shadows don't need depth testing
|
||||
glsafe(::glEnable(GL_POLYGON_OFFSET_FILL));
|
||||
glsafe(::glPolygonOffset(-2.0f, -2.0f));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
|
||||
// Render projected shadow geometry
|
||||
for (GLVolume* volume : m_volumes.volumes) {
|
||||
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
|
||||
continue;
|
||||
|
||||
// CRITICAL FIX: Apply shadow projection in object's local space, then to world, then to view
|
||||
// This ensures shadows are cast from the object's actual position
|
||||
Matrix4d world_matrix = volume->world_matrix().matrix();
|
||||
|
||||
// Project the shadow - this flattens the geometry onto Z=0 in WORLD space
|
||||
Matrix4d shadow_world_matrix = shadow_proj * world_matrix;
|
||||
|
||||
// Transform to view space for rendering
|
||||
Matrix4d view_shadow_matrix = view_matrix.matrix() * shadow_world_matrix;
|
||||
|
||||
shader->set_uniform("view_model_matrix", view_shadow_matrix);
|
||||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
|
||||
volume->model.render(shader);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PASS 2: Draw shadow color where stencil == 2
|
||||
// ============================================================
|
||||
glsafe(::glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE));
|
||||
glsafe(::glStencilFunc(GL_EQUAL, 2, 0xFF));
|
||||
glsafe(::glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP));
|
||||
glsafe(::glStencilMask(0x00));
|
||||
|
||||
glsafe(::glDepthFunc(GL_ALWAYS));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
// Draw shadow fill
|
||||
shader->set_uniform("view_model_matrix", Transform3d::Identity());
|
||||
shader->set_uniform("projection_matrix", Transform3d::Identity());
|
||||
|
||||
const ColorRGBA shadow_fill_color(0.0f, 0.0f, 0.0f, 0.4f); // Darker shadow for visibility
|
||||
const ColorRGBA prev_bg_color = m_background.get_geometry().color;
|
||||
m_background.set_color(shadow_fill_color);
|
||||
shader->set_uniform("uniform_color", shadow_fill_color);
|
||||
m_background.render(shader);
|
||||
m_background.set_color(prev_bg_color);
|
||||
shader->set_uniform("uniform_color", prev_bg_color);
|
||||
|
||||
shader->stop_using();
|
||||
|
||||
// ============================================================
|
||||
// RESTORE STATE
|
||||
// ============================================================
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDepthMask(prev_depth_mask));
|
||||
glsafe(::glDepthFunc(prev_depth_func));
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
glsafe(::glDisable(GL_POLYGON_OFFSET_FILL));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
if (!prev_stencil_test)
|
||||
glsafe(::glDisable(GL_STENCIL_TEST));
|
||||
glsafe(::glStencilMask(prev_stencil_mask));
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_plane() const
|
||||
{
|
||||
;//TODO render assemble plane
|
||||
@@ -7756,12 +8134,20 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
|
||||
else
|
||||
m_volumes.set_show_sinking_contours(!m_gizmos.is_hiding_instances());
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
|
||||
const bool realistic_mode = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE);
|
||||
const bool realistic_phong = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_PHONG);
|
||||
const std::string shader_name = (realistic_mode && realistic_phong) ? "phong" : "gouraud";
|
||||
GLShaderProgram* shader = wxGetApp().get_shader(shader_name);
|
||||
if (shader == nullptr && shader_name != "gouraud")
|
||||
shader = wxGetApp().get_shader("gouraud");
|
||||
ECanvasType canvas_type = this->m_canvas_type;
|
||||
bool partly_inside_enable = canvas_type == ECanvasType::CanvasAssembleView ? false : true;
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
|
||||
const bool phong_ssao = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_SSAO);
|
||||
shader->set_uniform("enable_ssao", phong_ssao);
|
||||
|
||||
const Size& cvn_size = get_canvas_size();
|
||||
{
|
||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||
@@ -8836,6 +9222,15 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
[this]{wxGetApp().toggle_show_outline();}
|
||||
);
|
||||
|
||||
create_menu_item( _utf8(L("Realistic View")),
|
||||
true,
|
||||
cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE),
|
||||
[this, &cfg]{
|
||||
cfg->set_bool(SETTING_OPENGL_REALISTIC_MODE, !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE));
|
||||
cfg->save();
|
||||
}
|
||||
);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
create_menu_item( _utf8(L("Perspective")),
|
||||
|
||||
@@ -727,6 +727,11 @@ public:
|
||||
GLModel m_background;
|
||||
unsigned int m_fxaa_texture_id{ 0 };
|
||||
std::array<unsigned int, 2> m_fxaa_texture_size{ 0, 0 };
|
||||
unsigned int m_ssao_color_texture_id{ 0 };
|
||||
unsigned int m_ssao_depth_texture_id{ 0 };
|
||||
std::array<unsigned int, 2> m_ssao_texture_size{ { 0, 0 } };
|
||||
GLModel m_plate_shadow_mask;
|
||||
std::string m_plate_shadow_mask_key;
|
||||
public:
|
||||
explicit GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed);
|
||||
~GLCanvas3D();
|
||||
@@ -1238,12 +1243,15 @@ private:
|
||||
void _picking_pass();
|
||||
void _rectangular_selection_picking_pass();
|
||||
bool _is_fxaa_enabled() const;
|
||||
bool _is_ssao_enabled() const;
|
||||
int _get_effective_fps_cap() const;
|
||||
bool _is_fps_overlay_enabled() const;
|
||||
void _render_fps_overlay(int fps) const;
|
||||
void _render_fxaa_pass(unsigned int width, unsigned int height);
|
||||
void _render_ssao_pass(unsigned int width, unsigned int height);
|
||||
void _render_background();
|
||||
void _render_bed(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool show_axes);
|
||||
void _render_cast_shadows_on_plate(const Transform3d& view_matrix, const Transform3d& projection_matrix);
|
||||
//BBS: add part plate related logic
|
||||
void _render_platelist(const Transform3d& view_matrix, const Transform3d& projection_matrix, bool bottom, bool only_current, bool only_body = false, int hover_id = -1, bool render_cali = false, bool show_grid = true);
|
||||
//BBS: add outline drawing logic
|
||||
|
||||
@@ -50,6 +50,8 @@ std::pair<bool, std::string> GLShadersManager::init()
|
||||
valid &= append_shader("flat_texture", { prefix + "flat_texture.vs", prefix + "flat_texture.fs" });
|
||||
// used to apply post-processing antialiasing in screen space
|
||||
valid &= append_shader("fxaa", { prefix + "fxaa.vs", prefix + "fxaa.fs" });
|
||||
// used to apply screen-space ambient occlusion in post process
|
||||
valid &= append_shader("ssao", { prefix + "ssao.vs", prefix + "ssao.fs" });
|
||||
// used to render 3D scene background
|
||||
valid &= append_shader("background", { prefix + "background.vs", prefix + "background.fs" });
|
||||
#if SLIC3R_OPENGL_ES
|
||||
@@ -76,6 +78,12 @@ std::pair<bool, std::string> GLShadersManager::init()
|
||||
valid &= append_shader("gouraud", { prefix + "gouraud.vs", prefix + "gouraud.fs" }
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
, { "ENABLE_ENVIRONMENT_MAP"sv }
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
);
|
||||
// used to render objects in 3d editor with phong shading
|
||||
valid &= append_shader("phong", { prefix + "phong.vs", prefix + "phong.fs" }
|
||||
#if ENABLE_ENVIRONMENT_MAP
|
||||
, { "ENABLE_ENVIRONMENT_MAP"sv }
|
||||
#endif // ENABLE_ENVIRONMENT_MAP
|
||||
);
|
||||
// used to render variable layers heights in 3d editor
|
||||
|
||||
@@ -1386,8 +1386,13 @@ bool GLGizmosManager::activate_gizmo(EType type)
|
||||
UndoRedo::SnapshotType::LeavingGizmoWithAction);
|
||||
}
|
||||
|
||||
if (type == Undefined) {
|
||||
if (type == Undefined) {
|
||||
// it is deactivation of gizmo
|
||||
if (m_restore_realistic_view_after_paint && wxGetApp().app_config != nullptr) {
|
||||
wxGetApp().app_config->set_bool(SETTING_OPENGL_REALISTIC_MODE, true);
|
||||
wxGetApp().app_config->save();
|
||||
m_restore_realistic_view_after_paint = false;
|
||||
}
|
||||
m_current = Undefined;
|
||||
return true;
|
||||
}
|
||||
@@ -1396,6 +1401,16 @@ bool GLGizmosManager::activate_gizmo(EType type)
|
||||
GLGizmoBase& new_gizmo = *m_gizmos[type];
|
||||
if (!new_gizmo.is_activable()) return false;
|
||||
|
||||
if (type == Seam || type == FdmSupports || type == FuzzySkin) {
|
||||
if (wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE)) {
|
||||
m_restore_realistic_view_after_paint = true;
|
||||
wxGetApp().app_config->set_bool(SETTING_OPENGL_REALISTIC_MODE, false);
|
||||
wxGetApp().app_config->save();
|
||||
}
|
||||
} else {
|
||||
m_restore_realistic_view_after_paint = false;
|
||||
}
|
||||
|
||||
if (!m_serializing && new_gizmo.wants_enter_leave_snapshots())
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(),
|
||||
new_gizmo.get_gizmo_entering_text(),
|
||||
|
||||
@@ -150,6 +150,7 @@ private:
|
||||
static std::map<int, void*> icon_list;
|
||||
|
||||
bool m_is_dark = false;
|
||||
bool m_restore_realistic_view_after_paint = false;
|
||||
|
||||
/// <summary>
|
||||
/// Process mouse event on gizmo toolbar
|
||||
|
||||
@@ -1554,6 +1554,30 @@ void PreferencesDialog::create_items()
|
||||
g_sizer = f_sizers.back();
|
||||
g_sizer->AddGrowableCol(0, 1);
|
||||
|
||||
//// GRAPHICS > Realistic view
|
||||
g_sizer->Add(create_item_title(_L("Realistic View")), 1, wxEXPAND);
|
||||
|
||||
auto item_realistic_phong = create_item_checkbox(
|
||||
_L("Phong shading"),
|
||||
_L("Uses Phong shading inside realistic view.")
|
||||
, SETTING_OPENGL_REALISTIC_PHONG
|
||||
);
|
||||
g_sizer->Add(item_realistic_phong);
|
||||
|
||||
auto item_realistic_ssao = create_item_checkbox(
|
||||
_L("SSAO ambient occlusion"),
|
||||
_L("Applies SSAO in realistic view."),
|
||||
SETTING_OPENGL_PHONG_SSAO
|
||||
);
|
||||
g_sizer->Add(item_realistic_ssao);
|
||||
|
||||
auto item_realistic_shadows = create_item_checkbox(
|
||||
_L("Shadows"),
|
||||
_L("Renders cast shadows on the plate in realistic view."),
|
||||
SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS
|
||||
);
|
||||
g_sizer->Add(item_realistic_shadows);
|
||||
|
||||
//// GRAPHICS > Anti-aliasing
|
||||
g_sizer->Add(create_item_title(_L("Anti-aliasing")), 1, wxEXPAND);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user