From fd2524a09e64ee2b89ceef1434a4f26529d008a8 Mon Sep 17 00:00:00 2001 From: "jun.zhang" Date: Tue, 26 Nov 2024 20:02:47 +0800 Subject: [PATCH] NEW: add silhouette effect jira: STUDIO-8928 Change-Id: Ia64a96e7e13e65d8be85fddfedcfdc4e5cff4ed5 (cherry picked from commit f090726830ea0490994b62c93c93e18ead731681) --- resources/shaders/110/silhouette.fs | 6 + resources/shaders/110/silhouette.vs | 11 + resources/shaders/110/silhouette_composite.fs | 35 +++ resources/shaders/110/silhouette_composite.vs | 12 + src/BambuStudio.cpp | 32 +-- src/slic3r/CMakeLists.txt | 1 + src/slic3r/GUI/3DScene.cpp | 150 ++++++------ src/slic3r/GUI/3DScene.hpp | 4 +- src/slic3r/GUI/GCodeViewer.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.cpp | 215 +++++++++++++++-- src/slic3r/GUI/GLCanvas3D.hpp | 30 +++ src/slic3r/GUI/GLEnums.hpp | 22 ++ src/slic3r/GUI/GLShader.cpp | 15 ++ src/slic3r/GUI/GLShader.hpp | 2 + src/slic3r/GUI/GLShadersManager.cpp | 4 + src/slic3r/GUI/GUI_App.cpp | 26 ++ src/slic3r/GUI/GUI_App.hpp | 5 + src/slic3r/GUI/OpenGLManager.cpp | 224 +++++++++++++++++- src/slic3r/GUI/OpenGLManager.hpp | 58 +++++ src/slic3r/Utils/CalibUtils.cpp | 8 +- 20 files changed, 756 insertions(+), 106 deletions(-) create mode 100644 resources/shaders/110/silhouette.fs create mode 100644 resources/shaders/110/silhouette.vs create mode 100644 resources/shaders/110/silhouette_composite.fs create mode 100644 resources/shaders/110/silhouette_composite.vs create mode 100644 src/slic3r/GUI/GLEnums.hpp diff --git a/resources/shaders/110/silhouette.fs b/resources/shaders/110/silhouette.fs new file mode 100644 index 000000000..09a175baa --- /dev/null +++ b/resources/shaders/110/silhouette.fs @@ -0,0 +1,6 @@ +#version 110 +uniform vec4 u_base_color; +void main() +{ + gl_FragColor = u_base_color; +} \ No newline at end of file diff --git a/resources/shaders/110/silhouette.vs b/resources/shaders/110/silhouette.vs new file mode 100644 index 000000000..8a4d590e9 --- /dev/null +++ b/resources/shaders/110/silhouette.vs @@ -0,0 +1,11 @@ +#version 110 + +uniform mat4 u_model_matrix; +uniform mat4 u_view_projection_matrix; + +attribute vec3 v_position; + +void main() +{ + gl_Position = u_view_projection_matrix * u_model_matrix * vec4(v_position, 1.0); +} diff --git a/resources/shaders/110/silhouette_composite.fs b/resources/shaders/110/silhouette_composite.fs new file mode 100644 index 000000000..d9c1157d9 --- /dev/null +++ b/resources/shaders/110/silhouette_composite.fs @@ -0,0 +1,35 @@ +#version 110 +uniform sampler2D u_sampler; +uniform mat3 u_convolution_matrix; +uniform vec2 u_viewport_size; + +varying vec2 tex_coords; + +vec4 sample(float offsetX, float offsetY) +{ + return texture2D(u_sampler, vec2(tex_coords.x + offsetX, tex_coords.y + offsetY)); +} +void main() +{ + vec4 pixels[9]; + float deltaWidth = 1.0 / u_viewport_size.x; + float deltaHeight = 1.0 / u_viewport_size.y; + pixels[0] = sample(-deltaWidth, deltaHeight ); + pixels[1] = sample(0.0, deltaHeight ); + pixels[2] = sample(deltaWidth, deltaHeight ); + pixels[3] = sample(-deltaWidth, 0.0); + pixels[4] = sample(0.0, 0.0); + pixels[5] = sample(deltaWidth, 0.0); + pixels[6] = sample(-deltaWidth, -deltaHeight); + pixels[7] = sample(0.0, -deltaHeight); + pixels[8] = sample(deltaWidth, -deltaHeight); + vec4 accumulator = vec4(0.0); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; ++j) + { + accumulator += pixels[3 * i + j] * u_convolution_matrix[i][j]; + } + } + gl_FragColor = accumulator; +} \ No newline at end of file diff --git a/resources/shaders/110/silhouette_composite.vs b/resources/shaders/110/silhouette_composite.vs new file mode 100644 index 000000000..7561fcc34 --- /dev/null +++ b/resources/shaders/110/silhouette_composite.vs @@ -0,0 +1,12 @@ +#version 110 + +attribute vec3 v_position; +attribute vec2 v_tex_coord; + +varying vec2 tex_coords; + +void main() +{ + tex_coords = v_tex_coord; + gl_Position = vec4(v_position, 1.0); +} \ No newline at end of file diff --git a/src/BambuStudio.cpp b/src/BambuStudio.cpp index 6a1f13871..d3e939c03 100644 --- a/src/BambuStudio.cpp +++ b/src/BambuStudio.cpp @@ -5857,11 +5857,13 @@ int CLI::run(int argc, char **argv) thumbnails.push_back(ThumbnailData()); Point isize(size); // round to ints ThumbnailData& thumbnail_data = thumbnails.back(); - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + const auto fb_type = Slic3r::GUI::OpenGLManager::get_framebuffers_type(); + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: %1%") %Slic3r::GUI::OpenGLManager::framebuffer_type_to_string(fb_type).c_str(); + switch (fb_type) { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Supported: case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(thumbnail_data, isize.x(), isize.y(), params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); @@ -5869,14 +5871,12 @@ int CLI::run(int argc, char **argv) } case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(thumbnail_data, isize.x(), isize.y(), params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); break; } default: - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); break; } if (!thumbnails.back().is_valid()) @@ -6432,11 +6432,13 @@ int CLI::run(int argc, char **argv) const ThumbnailsParams thumbnail_params = {{}, false, true, true, true, i}; BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail, need to regenerate")%(i+1); - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + const auto fb_type = Slic3r::GUI::OpenGLManager::get_framebuffers_type(); + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: %1%") % Slic3r::GUI::OpenGLManager::framebuffer_type_to_string(fb_type).c_str(); + switch (fb_type) { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Supported: case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*thumbnail_data, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); @@ -6444,14 +6446,12 @@ int CLI::run(int argc, char **argv) } case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*thumbnail_data, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); break; } default: - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); break; } BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s thumbnail,finished rendering")%(i+1); @@ -6484,11 +6484,13 @@ int CLI::run(int argc, char **argv) const ThumbnailsParams thumbnail_params = { {}, false, true, false, true, i }; BOOST_LOG_TRIVIAL(info) << boost::format("plate %1%'s no_light_thumbnail_file missed, need to regenerate")%(i+1); - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + const auto fb_type = Slic3r::GUI::OpenGLManager::get_framebuffers_type(); + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: %1%") % Slic3r::GUI::OpenGLManager::framebuffer_type_to_string(fb_type).c_str(); + switch (fb_type) { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Supported: case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*no_light_thumbnail, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, false, false, true); @@ -6496,14 +6498,12 @@ int CLI::run(int argc, char **argv) } case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*no_light_thumbnail, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, false, false, true); break; } default: - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); break; } plate_data->no_light_thumbnail_file = "valid_no_light"; @@ -6568,11 +6568,13 @@ int CLI::run(int argc, char **argv) BOOST_LOG_TRIVIAL(info) << boost::format("skip rendering for top&&pick"); } else { - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + const auto fb_type = Slic3r::GUI::OpenGLManager::get_framebuffers_type(); + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: %1%") % Slic3r::GUI::OpenGLManager::framebuffer_type_to_string(fb_type).c_str(); + switch (fb_type) { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Supported: case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: ARB"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*top_thumbnail, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false); @@ -6583,7 +6585,6 @@ int CLI::run(int argc, char **argv) } case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: { - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: EXT"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*top_thumbnail, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model.objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho, true, false); @@ -6593,7 +6594,6 @@ int CLI::run(int argc, char **argv) break; } default: - BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: unknown"); break; } plate_data->top_file = "valid_top"; diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 81223a9f6..58e9186b5 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -107,6 +107,7 @@ set(SLIC3R_GUI_SOURCES GUI/GLShader.hpp GUI/GLCanvas3D.hpp GUI/GLCanvas3D.cpp + GUI/GLEnums.hpp GUI/OpenGLManager.hpp GUI/OpenGLManager.cpp GUI/Selection.hpp diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 702f606f8..55513213a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1552,7 +1552,8 @@ int GLVolumeCollection::get_selection_support_threshold_angle(bool &enable_suppo } //BBS: add outline drawing logic -void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, +void GLVolumeCollection::render(GUI::ERenderPipelineStage render_pipeline_stage, + GLVolumeCollection::ERenderType type, bool disable_cullface, const Transform3d & view_matrix, std::function filter_func, @@ -1599,77 +1600,88 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, #endif // ENABLE_MODIFIERS_ALWAYS_TRANSPARENT // render sinking contours of non-hovered volumes - if (m_show_sinking_contours) - if (volume.first->is_sinking() && !volume.first->is_below_printbed() && - volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) { - shader->stop_using(); - volume.first->render_sinking_contours(); - shader->start_using(); - } + if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { + if (m_show_sinking_contours) + if (volume.first->is_sinking() && !volume.first->is_below_printbed() && + volume.first->hover == GLVolume::HS_None && !volume.first->force_sinking_contours) { + shader->stop_using(); + volume.first->render_sinking_contours(); + shader->start_using(); + } + } glsafe(::glEnableClientState(GL_VERTEX_ARRAY)); glsafe(::glEnableClientState(GL_NORMAL_ARRAY)); - shader->set_uniform("is_text_shape", volume.first->is_text_shape); - shader->set_uniform("uniform_color", volume.first->render_color); - shader->set_uniform("z_range", m_z_range, 2); - shader->set_uniform("clipping_plane", m_clipping_plane, 4); - //BOOST_LOG_TRIVIAL(info) << boost::format("set uniform_color to {%1%, %2%, %3%, %4%}, with_outline=%5%, selected %6%") - // %volume.first->render_color[0]%volume.first->render_color[1]%volume.first->render_color[2]%volume.first->render_color[3] - // %with_outline%volume.first->selected; + if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { + shader->set_uniform("is_text_shape", volume.first->is_text_shape); + shader->set_uniform("uniform_color", volume.first->render_color); + shader->set_uniform("z_range", m_z_range, 2); + shader->set_uniform("clipping_plane", m_clipping_plane, 4); + //BOOST_LOG_TRIVIAL(info) << boost::format("set uniform_color to {%1%, %2%, %3%, %4%}, with_outline=%5%, selected %6%") + // %volume.first->render_color[0]%volume.first->render_color[1]%volume.first->render_color[2]%volume.first->render_color[3] + // %with_outline%volume.first->selected; - //BBS set print_volume to render volume - //shader->set_uniform("print_volume.type", static_cast(m_render_volume.type)); - //shader->set_uniform("print_volume.xy_data", m_render_volume.data); - //shader->set_uniform("print_volume.z_data", m_render_volume.zs); - if (printable_heights) { - std::array extruder_printable_heights; - if ((*printable_heights).size() > 0) { - extruder_printable_heights[0] = 2.0f; - extruder_printable_heights[1] = (*printable_heights)[0]; - extruder_printable_heights[2] = (*printable_heights)[1]; - shader->set_uniform("extruder_printable_heights", extruder_printable_heights); - shader->set_uniform("print_volume.xy_data", m_print_volume.data); - } else { - extruder_printable_heights[0] = 0.0f; - shader->set_uniform("extruder_printable_heights", extruder_printable_heights); + //BBS set print_volume to render volume + //shader->set_uniform("print_volume.type", static_cast(m_render_volume.type)); + //shader->set_uniform("print_volume.xy_data", m_render_volume.data); + //shader->set_uniform("print_volume.z_data", m_render_volume.zs); + if (printable_heights) { + std::array extruder_printable_heights; + if ((*printable_heights).size() > 0) { + extruder_printable_heights[0] = 2.0f; + extruder_printable_heights[1] = (*printable_heights)[0]; + extruder_printable_heights[2] = (*printable_heights)[1]; + shader->set_uniform("extruder_printable_heights", extruder_printable_heights); + shader->set_uniform("print_volume.xy_data", m_print_volume.data); + } + else { + extruder_printable_heights[0] = 0.0f; + shader->set_uniform("extruder_printable_heights", extruder_printable_heights); + } } - } - if (volume.first->partly_inside && partly_inside_enable) { - //only partly inside volume need to be painted with boundary check - shader->set_uniform("print_volume.type", static_cast(m_print_volume.type)); - shader->set_uniform("print_volume.z_data", m_print_volume.zs); - if (!printable_heights || (printable_heights && (*printable_heights).size() == 0)) { - shader->set_uniform("print_volume.xy_data", m_print_volume.data); + if (volume.first->partly_inside && partly_inside_enable) { + //only partly inside volume need to be painted with boundary check + shader->set_uniform("print_volume.type", static_cast(m_print_volume.type)); + shader->set_uniform("print_volume.z_data", m_print_volume.zs); + if (!printable_heights || (printable_heights && (*printable_heights).size() == 0)) { + shader->set_uniform("print_volume.xy_data", m_print_volume.data); + } + } + else { + //use -1 ad a invalid type + shader->set_uniform("print_volume.type", -1); } - } - else { - //use -1 ad a invalid type - shader->set_uniform("print_volume.type", -1); - } - bool enable_support; - int support_threshold_angle = get_selection_support_threshold_angle(enable_support); + bool enable_support; + int support_threshold_angle = get_selection_support_threshold_angle(enable_support); - float normal_z = -::cos(Geometry::deg2rad((float) support_threshold_angle)); + float normal_z = -::cos(Geometry::deg2rad((float)support_threshold_angle)); - shader->set_uniform("volume_world_matrix", volume.first->world_matrix()); - shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower); - shader->set_uniform("slope.volume_world_normal_matrix", static_cast(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast())); - shader->set_uniform("slope.normal_z", normal_z); + shader->set_uniform("volume_world_matrix", volume.first->world_matrix()); + shader->set_uniform("slope.actived", m_slope.isGlobalActive && !volume.first->is_modifier && !volume.first->is_wipe_tower); + shader->set_uniform("slope.volume_world_normal_matrix", static_cast(volume.first->world_matrix().matrix().block(0, 0, 3, 3).inverse().transpose().cast())); + shader->set_uniform("slope.normal_z", normal_z); #if ENABLE_ENVIRONMENT_MAP - unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id(); - bool use_environment_texture = environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1"; - shader->set_uniform("use_environment_tex", use_environment_texture); - if (use_environment_texture) - glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id)); + unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id(); + bool use_environment_texture = environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1"; + shader->set_uniform("use_environment_tex", use_environment_texture); + if (use_environment_texture) + glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id)); #endif // ENABLE_ENVIRONMENT_MAP - glcheck(); + glcheck(); - //BBS: add outline related logic - auto red_color = std::array({1.0f, 0.0f, 0.0f, 1.0f});//slice_error - volume.first->render(with_outline && volume.first->selected, volume.first->slice_error ? red_color : body_color); + //BBS: add outline related logic + auto red_color = std::array({ 1.0f, 0.0f, 0.0f, 1.0f });//slice_error + volume.first->render(with_outline&& volume.first->selected, volume.first->slice_error ? red_color : body_color); + } + else { + if (volume.first->selected) { + shader->set_uniform("u_model_matrix", volume.first->world_matrix()); + volume.first->render(false, body_color); + } + } #if ENABLE_ENVIRONMENT_MAP if (use_environment_texture) @@ -1683,16 +1695,18 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, glsafe(::glDisableClientState(GL_NORMAL_ARRAY)); } - if (m_show_sinking_contours) { - for (GLVolumeWithIdAndZ& volume : to_render) { - // render sinking contours of hovered/displaced volumes - if (volume.first->is_sinking() && !volume.first->is_below_printbed() && - (volume.first->hover != GLVolume::HS_None || volume.first->force_sinking_contours)) { - shader->stop_using(); - glsafe(::glDepthFunc(GL_ALWAYS)); - volume.first->render_sinking_contours(); - glsafe(::glDepthFunc(GL_LESS)); - shader->start_using(); + if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { + if (m_show_sinking_contours) { + for (GLVolumeWithIdAndZ& volume : to_render) { + // render sinking contours of hovered/displaced volumes + if (volume.first->is_sinking() && !volume.first->is_below_printbed() && + (volume.first->hover != GLVolume::HS_None || volume.first->force_sinking_contours)) { + shader->stop_using(); + glsafe(::glDepthFunc(GL_ALWAYS)); + volume.first->render_sinking_contours(); + glsafe(::glDepthFunc(GL_LESS)); + shader->start_using(); + } } } } diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 17dfc260c..2aa36d4b7 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -12,6 +12,7 @@ #include "MeshUtils.hpp" #include "GLShader.hpp" +#include "GLEnums.hpp" #include #include @@ -725,7 +726,8 @@ public: int get_selection_support_threshold_angle(bool&) const; // Render the volumes by OpenGL. //BBS: add outline drawing logic - void render(ERenderType type, + void render(GUI::ERenderPipelineStage render_pipeline_stage, + ERenderType type, bool disable_cullface, const Transform3d & view_matrix, std::function filter_func = std::function(), diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index a5a2eeede..42c96b8f4 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4198,7 +4198,7 @@ void GCodeViewer::render_shells() shader->start_using(); //BBS: reopen cul faces - m_shells.volumes.render(GLVolumeCollection::ERenderType::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix()); + m_shells.volumes.render(GUI::ERenderPipelineStage::Normal, GLVolumeCollection::ERenderType::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix()); shader->stop_using(); glsafe(::glDepthMask(GL_TRUE)); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 033c29370..70e08643b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1181,6 +1181,8 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D &bed) m_assembly_view_desc["part_selection"] = _L("part selection"); m_assembly_view_desc["number_key_caption"] = "1~16 " + _L("number keys"); m_assembly_view_desc["number_key"] = _L("number keys can quickly change the color of objects"); + + m_render_pipeline_stage_stack.push(ERenderPipelineStage::Normal); } GLCanvas3D::~GLCanvas3D() @@ -1920,6 +1922,8 @@ void GLCanvas3D::render(bool only_init) return; } + wxGetApp().set_picking_effect(EPickingEffect::Silhouette); + if (only_init) return; @@ -1962,6 +1966,10 @@ void GLCanvas3D::render(bool only_init) GLfloat position_top[4] = { -0.5f, -0.5f, 1.0f, 0.0f }; glsafe(::glLightfv(GL_LIGHT0, GL_POSITION, position_top)); + const std::array& viewport = camera.get_viewport(); + auto& ogl_manager = wxGetApp().get_opengl_manager(); + ogl_manager.set_viewport_size(viewport[2], viewport[3]); + wxGetApp().imgui()->new_frame(); if (m_picking_enabled) { @@ -2002,20 +2010,27 @@ void GLCanvas3D::render(bool only_init) /* view3D render*/ int hover_id = (m_hover_plate_idxs.size() > 0)?m_hover_plate_idxs.front():-1; + EPickingEffect picking_effect = wxGetApp().get_picking_effect(); + if (EPickingEffect::Disabled != picking_effect) { + if (!ogl_manager.are_framebuffers_supported()) { + picking_effect = EPickingEffect::StencilOutline; // use stencil outline as framebuffer not supported yet. + } + } + bool b_with_stencil_outline = !m_gizmos.is_running() && (EPickingEffect::StencilOutline == picking_effect); if (m_canvas_type == ECanvasType::CanvasView3D) { //BBS: add outline logic - _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); + _render_objects(GLVolumeCollection::ERenderType::Opaque, b_with_stencil_outline); _render_sla_slices(); _render_selection(); if (!no_partplate) _render_bed(!camera.is_looking_downward(), show_axes); if (!no_partplate) //BBS: add outline logic _render_platelist(!camera.is_looking_downward(), only_current, only_body, hover_id, true, show_grid); - _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running()); + _render_objects(GLVolumeCollection::ERenderType::Transparent, b_with_stencil_outline); } /* preview render */ else if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) { - _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); + _render_objects(GLVolumeCollection::ERenderType::Opaque, b_with_stencil_outline); _render_sla_slices(); _render_selection(); _render_bed(!camera.is_looking_downward(), show_axes); @@ -2029,13 +2044,17 @@ void GLCanvas3D::render(bool only_init) if (m_show_world_axes) { m_axes.render(); } - _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); + _render_objects(GLVolumeCollection::ERenderType::Opaque, b_with_stencil_outline); //_render_bed(!camera.is_looking_downward(), show_axes); _render_plane(); //BBS: add outline logic insteadof selection under assemble view //_render_selection(); // BBS: add outline logic - _render_objects(GLVolumeCollection::ERenderType::Transparent, !m_gizmos.is_running()); + _render_objects(GLVolumeCollection::ERenderType::Transparent, b_with_stencil_outline); + } + + if (EPickingEffect::Silhouette == picking_effect) { + _render_silhouette_effect(); } _render_sequential_clearance(); @@ -2149,6 +2168,7 @@ void GLCanvas3D::render(bool only_init) wxGetApp().imgui()->render(); + ogl_manager.clear_dirty(); m_canvas->SwapBuffers(); m_render_stats.increment_fps_counter(); } @@ -2175,8 +2195,11 @@ void GLCanvas3D::render_thumbnail(ThumbnailData& thumbnail_data, unsigned int w, GLShaderProgram* shader = wxGetApp().get_shader("thumbnail"); ModelObjectPtrs& model_objects = GUI::wxGetApp().model().objects; std::vector> colors = ::get_extruders_colors(); - switch (OpenGLManager::get_framebuffers_type()) + const auto fb_type = Slic3r::GUI::OpenGLManager::get_framebuffers_type(); + BOOST_LOG_TRIVIAL(info) << boost::format("framebuffer_type: %1%") % Slic3r::GUI::OpenGLManager::framebuffer_type_to_string(fb_type).c_str(); + switch (fb_type) { + case OpenGLManager::EFramebufferType::Supported: case OpenGLManager::EFramebufferType::Arb: { render_thumbnail_framebuffer(thumbnail_data, w, h, thumbnail_params, wxGetApp().plater()->get_partplate_list(), model_objects, volumes, colors, shader, camera_type, use_top_view, for_picking, ban_light); @@ -7319,9 +7342,13 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with std::array({1.0f, 1.0f, 1.0f, 1.0f});//white bool partly_inside_enable = canvas_type == ECanvasType::CanvasAssembleView ? false : true; auto printable_height_option = GUI::wxGetApp().preset_bundle->printers.get_edited_preset().config.option("extruder_printable_height"); - if (shader != nullptr) { - shader->start_using(); + const GUI::ERenderPipelineStage render_pipeline_stage = _get_current_render_stage(); + if ((GUI::ERenderPipelineStage::Silhouette == render_pipeline_stage) || shader != nullptr) { + if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) + { + shader->start_using(); + } switch (type) { default: @@ -7330,9 +7357,9 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with const GLGizmosManager& gm = get_gizmos_manager(); if (dynamic_cast(gm.get_current()) == nullptr) { - if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) { + if (m_picking_enabled && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f) && GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { int object_id = m_layers_editing.last_object_id; - m_volumes.render(type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) { + m_volumes.render(render_pipeline_stage, type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) { // Which volume to paint without the layer height profile shader? return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id); }); @@ -7347,7 +7374,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with }*/ //BBS:add assemble view related logic // do not cull backfaces to show broken geometry, if any - m_volumes.render(type, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { + m_volumes.render(render_pipeline_stage, type, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { if (canvas_type == ECanvasType::CanvasAssembleView) { return !volume.is_modifier && !volume.is_wipe_tower; } @@ -7358,7 +7385,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with with_outline, body_color, partly_inside_enable, printable_height_option ? &printable_height_option->values : nullptr); } } - else { + else if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { // In case a painting gizmo is open, it should render the painted triangles // before transparent objects are rendered. Otherwise they would not be // visible when inside modifier meshes etc. @@ -7381,7 +7408,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with shader->set_uniform("show_wireframe", false); }*/ //BBS:add assemble view related logic - m_volumes.render(type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { + m_volumes.render(render_pipeline_stage, type, false, wxGetApp().plater()->get_camera().get_view_matrix(), [this, canvas_type](const GLVolume& volume) { if (canvas_type == ECanvasType::CanvasAssembleView) { return !volume.is_modifier; } @@ -7390,7 +7417,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with } }, with_outline, body_color, partly_inside_enable, printable_height_option ? &printable_height_option->values : nullptr); - if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0) { + if (m_canvas_type == CanvasAssembleView && m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position() > 0 && GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { const GLGizmosManager& gm = get_gizmos_manager(); shader->stop_using(); gm.render_painter_assemble_view(); @@ -7404,7 +7431,9 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with shader->set_uniform("show_wireframe", false); }*/ - shader->stop_using(); + if (GUI::ERenderPipelineStage::Silhouette != render_pipeline_stage) { + shader->stop_using(); + } } m_camera_clipping_plane = ClippingPlane::ClipsNothing(); @@ -9712,6 +9741,151 @@ std::vector> GLCanvas3D::_parse_colors(const std::vector 1) + { + m_render_pipeline_stage_stack.pop(); + } +} + +ERenderPipelineStage GLCanvas3D::_get_current_render_stage() const +{ + return m_render_pipeline_stage_stack.top(); +} + +void GLCanvas3D::_render_silhouette_effect() +{; + RenderPipelineStageModifier render_pipeline_stage_modifier(*this, ERenderPipelineStage::Silhouette); + + auto& ogl_manager = wxGetApp().get_opengl_manager(); + + { + // BBS: render silhouette + OpenGLManager::FrameBufferModifier frame_buffer_modifier(ogl_manager, "silhouette"); + + glsafe(::glClearColor(0.0f, 0.0f, 0.0f, 0.0f)); + glsafe(::glClearDepth(1.0f)); + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDisable(GL_BLEND)); + glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); + + GLShaderProgram* p_silhouette_shader = wxGetApp().get_shader("silhouette"); + if (!p_silhouette_shader) + { + BOOST_LOG_TRIVIAL(error) << "Invalid shader: silhouette. Failed to render highlight effect."; + return; + } + + p_silhouette_shader->start_using(); + + std::array picking_color{ 1.0f, 0.36f, 0.0f, 1.0f }; + if (m_canvas_type == ECanvasType::CanvasAssembleView) { + picking_color[0] = 1.0f; + picking_color[1] = 1.0f; + picking_color[2] = 0.0f; + picking_color[3] = 1.0f; + } + else { + picking_color[0] = 1.0f; + picking_color[1] = 1.0f; + picking_color[2] = 1.0f; + picking_color[3] = 1.0f; + } + p_silhouette_shader->set_uniform("u_base_color", picking_color); + + const Camera& camera = wxGetApp().plater()->get_camera(); + const Transform3d& view_matrix = camera.get_view_matrix(); + const Transform3d& projection_matrix = camera.get_projection_matrix(); + const Matrix4d view_proj = projection_matrix.matrix() * view_matrix.matrix(); + p_silhouette_shader->set_uniform("u_view_projection_matrix", view_proj); + _render_objects(GLVolumeCollection::ERenderType::Opaque, false); + _render_objects(GLVolumeCollection::ERenderType::Transparent, false); + + p_silhouette_shader->stop_using(); + + // BBS: end render silhouette + } + + // BBS: composite silhouette + + const auto& p_frame_buffer = ogl_manager.get_frame_buffer("silhouette"); + if (!p_frame_buffer) + { + return; + } + + const auto color_texture_id = p_frame_buffer->get_color_texture(); + if (!p_frame_buffer->is_texture_valid(color_texture_id)) + { + BOOST_LOG_TRIVIAL(error) << "Invalid framebuffer. Failed to render highlight effect."; + return; + } + + glsafe(::glDisable(GL_DEPTH_TEST)); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + + GLShaderProgram* p_silhouette_composite_shader = wxGetApp().get_shader("silhouette_composite"); + if (!p_silhouette_composite_shader) + { + BOOST_LOG_TRIVIAL(error) << "Invalid silhouette texture. Failed to render highlight effect."; + return; + } + p_silhouette_composite_shader->start_using(); + + uint32_t viewport_width = 0; + uint32_t viewport_height = 0; + ogl_manager.get_viewport_size(viewport_width, viewport_height); + const std::array viewport_size{ static_cast(viewport_width), static_cast(viewport_height)}; + p_silhouette_composite_shader->set_uniform("u_viewport_size", viewport_size); + + Matrix3f convolution_matrix; + convolution_matrix.data()[3 * 0 + 0] = -0.4f; + convolution_matrix.data()[3 * 0 + 1] = -0.4f; + convolution_matrix.data()[3 * 0 + 2] = -0.4f; + + convolution_matrix.data()[3 * 1 + 0] = -0.4f; + convolution_matrix.data()[3 * 1 + 1] = 3.6f; + convolution_matrix.data()[3 * 1 + 2] = -0.4f; + + convolution_matrix.data()[3 * 2 + 0] = -0.4f; + convolution_matrix.data()[3 * 2 + 1] = -0.4f; + convolution_matrix.data()[3 * 2 + 2] = -0.4f; + p_silhouette_composite_shader->set_uniform("u_convolution_matrix", convolution_matrix); + + const int stage = 0; + p_silhouette_composite_shader->set_uniform("u_sampler", stage); + glsafe(::glActiveTexture(GL_TEXTURE0 + stage)); + glsafe(::glBindTexture(GL_TEXTURE_2D, color_texture_id)); + + if (!m_full_screen_mesh.is_initialized()) { + GLModel::Geometry geo; + geo.format.type = GLModel::PrimitiveType::Triangles; + geo.format.vertex_layout = GLModel::Geometry::EVertexLayout::P3T2; + + geo.add_vertex(Vec3f{ -1.0f, -1.0f, 0.0f }, Vec2f{ 0.0f, 0.0f }); + geo.add_vertex(Vec3f{ 3.0f, -1.0f, 0.0f }, Vec2f{ 2.0f, 0.0f }); + geo.add_vertex(Vec3f{ -1.0f, 3.0f, 0.0f }, Vec2f{ 0.0f, 2.0f }); + + geo.add_triangle(0, 1, 2); + + m_full_screen_mesh.init_from(std::move(geo)); + } + + m_full_screen_mesh.render_geometry(); + + p_silhouette_composite_shader->stop_using(); + + glsafe(::glDisable(GL_BLEND)); + // BBS: end composite silhouette +} + void GLCanvas3D::_set_warning_notification(EWarning warning, bool state) { enum ErrorType{ @@ -10137,6 +10311,17 @@ void GLCanvas3D::GizmoHighlighterTimer::Notify() wxPostEvent((wxEvtHandler*)GetOwner(), GizmoHighlighterTimerEvent(EVT_GLCANVAS_GIZMO_HIGHLIGHTER_TIMER, *this)); } +GLCanvas3D::RenderPipelineStageModifier::RenderPipelineStageModifier(GLCanvas3D& canvas, ERenderPipelineStage stage) + : m_canvas(canvas) +{ + m_canvas._push_render_stage(stage); +} + +GLCanvas3D::RenderPipelineStageModifier::~RenderPipelineStageModifier() +{ + m_canvas._pop_render_stage(); +} + void GLCanvas3D::ToolbarHighlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/) { m_timer.SetOwner(owner, timerid); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d06275119..71b9dae53 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "GLToolbar.hpp" #include "Event.hpp" @@ -19,6 +20,7 @@ #include "IMToolbar.hpp" #include "slic3r/GUI/3DBed.hpp" #include "libslic3r/Slicing.hpp" +#include "GLEnums.hpp" #include @@ -471,6 +473,25 @@ class GLCanvas3D virtual void Notify() override; }; + class RenderPipelineStageModifier + { + public: + explicit RenderPipelineStageModifier(GLCanvas3D& canvas, ERenderPipelineStage stage); + ~RenderPipelineStageModifier(); + + private: + // no copy + RenderPipelineStageModifier(const RenderPipelineStageModifier&) = delete; + RenderPipelineStageModifier(RenderPipelineStageModifier&&) = delete; + + // no assign + RenderPipelineStageModifier& operator=(const RenderPipelineStageModifier&) = delete; + RenderPipelineStageModifier& operator=(RenderPipelineStageModifier&&) = delete; + private: + GLCanvas3D& m_canvas; + ERenderPipelineStage m_stage; + }; + public: enum ECursorType : unsigned char { @@ -628,6 +649,9 @@ private: int custom_height_count = 0; int assembly_view_count = 0; + std::stack m_render_pipeline_stage_stack; + GLModel m_full_screen_mesh; + public: OrientSettings& get_orient_settings() { @@ -1239,6 +1263,12 @@ private: float get_overlay_window_width() { return 0; /*LayersEditing::get_overlay_window_width();*/ } static std::vector> _parse_colors(const std::vector& colors); + + void _push_render_stage(ERenderPipelineStage stage); + void _pop_render_stage(); + ERenderPipelineStage _get_current_render_stage() const; + + void _render_silhouette_effect(); }; const ModelVolume *get_model_volume(const GLVolume &v, const Model &model); diff --git a/src/slic3r/GUI/GLEnums.hpp b/src/slic3r/GUI/GLEnums.hpp new file mode 100644 index 000000000..e5d368e18 --- /dev/null +++ b/src/slic3r/GUI/GLEnums.hpp @@ -0,0 +1,22 @@ +#ifndef slic3r_GUI_GLEnums_hpp_ +#define slic3r_GUI_GLEnums_hpp_ +namespace Slic3r { +namespace GUI { + + enum class EPickingEffect + { + Disabled, + StencilOutline, + Silhouette + }; + + enum class ERenderPipelineStage + { + Normal, + Silhouette + }; + +} // namespace Slic3r +} // namespace GUI + +#endif // slic3r_GUI_GLEnums_hpp_ \ No newline at end of file diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 222b14b9c..41166b5a7 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -349,6 +349,21 @@ bool GLShaderProgram::set_uniform(const char *name, const Matrix3d &value) const return set_uniform(name, (Matrix3f) value.cast()); } +bool GLShaderProgram::set_uniform(const char* name, const Matrix4f& value) const +{ + int id = get_uniform_location(name); + if (id >= 0) { + glsafe(::glUniformMatrix4fv(id, 1, GL_FALSE, static_cast(value.data()))); + return true; + } + return false; +} + +bool GLShaderProgram::set_uniform(const char* name, const Matrix4d& value) const +{ + return set_uniform(name, (Matrix4f)value.cast()); +} + bool GLShaderProgram::set_uniform(const char* name, const Vec3f& value) const { int id = get_uniform_location(name); diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index de5d3da71..04bcbcfe4 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -59,6 +59,8 @@ public: bool set_uniform(const char* name, const Transform3d& value) const; bool set_uniform(const char* name, const Matrix3f& value) const; bool set_uniform(const char *name, const Matrix3d &value) const; + bool set_uniform(const char* name, const Matrix4f& value) const; + bool set_uniform(const char* name, const Matrix4d& value) const; bool set_uniform(const char* name, const Vec3f& value) const; bool set_uniform(const char* name, const Vec3d& value) const; diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index 21349c8da..c7f427d80 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -92,6 +92,10 @@ std::pair GLShadersManager::init() //BBS: add shader for outline valid &= append_shader("outline", { "outline.vs", "outline.fs" }); + valid &= append_shader("silhouette", { "110/silhouette.vs", "110/silhouette.fs" }); + + valid &= append_shader("silhouette_composite", { "110/silhouette_composite.vs", "110/silhouette_composite.fs" }); + return { valid, error }; } diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 9ea2542ee..5711ffd60 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -7071,6 +7071,32 @@ void GUI_App::check_config_updates_from_menu() check_updates(true); } +void GUI_App::set_picking_effect(EPickingEffect effect) +{ + if (m_picking_effect != effect) + { + std::string str_picking_effect{}; + switch (effect) + { + case EPickingEffect::Disabled: + str_picking_effect = "Disabled"; + break; + case EPickingEffect::StencilOutline: + str_picking_effect = "StencilOutline"; + break; + case EPickingEffect::Silhouette: + str_picking_effect = "Silhouette"; + break; + } + BOOST_LOG_TRIVIAL(info) << "Switched picking effect to: " << str_picking_effect; + m_picking_effect = effect; + } +} + +EPickingEffect GUI_App::get_picking_effect() const +{ + return m_picking_effect; +} bool GUI_App::open_browser_with_warning_dialog(const wxString& url, int flags/* = 0*/) { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 85845e78c..e1f962caf 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -19,6 +19,7 @@ #include "slic3r/GUI/Jobs/UpgradeNetworkJob.hpp" #include "slic3r/GUI/HttpServer.hpp" #include "../Utils/PrintHost.hpp" +#include "slic3r/GUI/GLEnums.hpp" #include #include @@ -659,6 +660,9 @@ public: void check_config_updates_from_updater(); void check_config_updates_from_menu(); + void set_picking_effect(EPickingEffect effect); + EPickingEffect get_picking_effect() const; + private: int updating_bambu_networking(); bool on_init_inner(); @@ -687,6 +691,7 @@ private: std::string m_older_data_dir_path; boost::optional m_last_config_version; std::string m_open_method; + EPickingEffect m_picking_effect{ EPickingEffect::StencilOutline }; }; DECLARE_APP(GUI_App) diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index 4c0577407..d3fbda64e 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -23,6 +23,13 @@ #include "../Utils/MacDarkMode.hpp" #endif // __APPLE__ +#define BBS_GL_EXTENSION_FUNC(_func) (OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Ext ? _func ## EXT : _func) +#define BBS_GL_EXTENSION_FRAMEBUFFER OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Ext ? GL_FRAMEBUFFER_EXT : GL_FRAMEBUFFER +#define BBS_GL_EXTENSION_COLOR_ATTACHMENT(color_attachment) (OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Ext ? color_attachment ## _EXT : color_attachment) +#define BBS_GL_EXTENSION_DEPTH_ATTACHMENT OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Ext ? GL_DEPTH_ATTACHMENT_EXT : GL_DEPTH_ATTACHMENT +#define BBS_GL_EXTENSION_RENDER_BUFFER OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Ext ? GL_RENDERBUFFER_EXT : GL_RENDERBUFFER + + namespace Slic3r { namespace GUI { @@ -41,6 +48,20 @@ const std::string& OpenGLManager::GLInfo::get_version() const return m_version; } +const uint32_t OpenGLManager::GLInfo::get_formated_gl_version() const +{ + if (0 == m_formated_gl_version) + { + GLint major = 0; + GLint minor = 0; + glGetIntegerv(GL_MAJOR_VERSION, &major); + glGetIntegerv(GL_MINOR_VERSION, &minor); + + m_formated_gl_version = major * 10 + minor; + } + return m_formated_gl_version; +} + const std::string& OpenGLManager::GLInfo::get_glsl_version() const { if (!m_detected) @@ -219,6 +240,7 @@ OpenGLManager::OSInfo OpenGLManager::s_os_info; OpenGLManager::~OpenGLManager() { m_shaders_manager.shutdown(); + m_name_to_frame_buffer.clear(); #ifdef __APPLE__ // This is an ugly hack needed to solve the crash happening when closing the application on OSX 10.9.5 with newer wxWidgets @@ -249,7 +271,13 @@ bool OpenGLManager::init_gl(bool popup_error) else s_compressed_textures_supported = false; - if (GLEW_ARB_framebuffer_object) { + const auto& gl_info = OpenGLManager::get_gl_info(); + const uint32_t gl_formated_version = gl_info.get_formated_gl_version(); + if (gl_formated_version >= 30) { + s_framebuffers_type = EFramebufferType::Supported; + BOOST_LOG_TRIVIAL(info) << "Opengl version >= 30, FrameBuffer normal." << std::endl; + } + else if (GLEW_ARB_framebuffer_object) { s_framebuffers_type = EFramebufferType::Arb; BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type ARB."<< std::endl; } @@ -336,6 +364,78 @@ wxGLContext* OpenGLManager::init_glcontext(wxGLCanvas& canvas) return m_context; } +void OpenGLManager::clear_dirty() +{ + m_b_viewport_dirty = false; +} + +void OpenGLManager::set_viewport_size(uint32_t width, uint32_t height) +{ + if (width != m_viewport_width) + { + m_b_viewport_dirty = true; + m_viewport_width = width; + } + if (height != m_viewport_height) + { + m_b_viewport_dirty = true; + m_viewport_height = height; + } +} + +void OpenGLManager::get_viewport_size(uint32_t& width, uint32_t& height) const +{ + width = m_viewport_width; + height = m_viewport_height; +} + +void OpenGLManager::_bind_frame_buffer(const std::string& name) +{ + const auto& iter = m_name_to_frame_buffer.find(name); + if (iter == m_name_to_frame_buffer.end() || m_b_viewport_dirty) { + const auto& p_frame_buffer = std::make_shared(m_viewport_width, m_viewport_height); + m_name_to_frame_buffer.insert_or_assign(name, p_frame_buffer); + } + + m_name_to_frame_buffer[name]->bind(); +} + +void OpenGLManager::_unbind_frame_buffer(const std::string& name) +{ + const auto& iter = m_name_to_frame_buffer.find(name); + if (iter == m_name_to_frame_buffer.end()) { + return; + } + + m_name_to_frame_buffer[name]->unbind(); +} + +const std::shared_ptr& OpenGLManager::get_frame_buffer(const std::string& name) const +{ + const auto& iter = m_name_to_frame_buffer.find(name); + if (iter != m_name_to_frame_buffer.end()) { + return iter->second; + } + static std::shared_ptr sEmpty{ nullptr }; + return sEmpty; +} + +std::string OpenGLManager::framebuffer_type_to_string(EFramebufferType type) +{ + switch (type) + { + case EFramebufferType::Supported: + return "Supported"; + case EFramebufferType::Arb: + return "ARB"; + case EFramebufferType::Ext: + return "EXT"; + case EFramebufferType::Unknown: + default: + return "unknow"; + } +} + wxGLCanvas* OpenGLManager::create_wxglcanvas(wxWindow& parent) { int attribList[] = { @@ -383,5 +483,127 @@ void OpenGLManager::detect_multisample(int* attribList) // s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample"); } +FrameBuffer::FrameBuffer(uint32_t width, uint32_t height) + : m_width(width) + , m_height(height) +{ +} + +FrameBuffer::~FrameBuffer() +{ + if (UINT32_MAX != m_gl_id) + { + //glsafe(::glBindFramebuffer(GL_FRAMEBUFFER, 0)); + glsafe(::glDeleteFramebuffers(1, &m_gl_id)); + m_gl_id = UINT32_MAX; + } + + if (UINT32_MAX != m_color_texture_id) + { + glDeleteTextures(1, &m_color_texture_id); + m_color_texture_id = UINT32_MAX; + } + + if (UINT32_MAX != m_depth_rbo_id) + { + glDeleteRenderbuffers(1, &m_depth_rbo_id); + m_depth_rbo_id = UINT32_MAX; + } +} + +void FrameBuffer::bind() +{ + const OpenGLManager::EFramebufferType framebuffer_type = OpenGLManager::get_framebuffers_type(); + if (OpenGLManager::EFramebufferType::Unknown == framebuffer_type) { + return; + } + if (0 == m_width || 0 == m_height) + { + return; + } + if (UINT32_MAX == m_gl_id) + { + glsafe(BBS_GL_EXTENSION_FUNC(::glGenFramebuffers)(1, &m_gl_id)); + + glsafe(BBS_GL_EXTENSION_FUNC(::glBindFramebuffer)(BBS_GL_EXTENSION_FRAMEBUFFER, m_gl_id)); + + glsafe(::glGenTextures(1, &m_color_texture_id)); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_color_texture_id)); + + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + glsafe(BBS_GL_EXTENSION_FUNC(::glFramebufferTexture2D)(BBS_GL_EXTENSION_FRAMEBUFFER, BBS_GL_EXTENSION_COLOR_ATTACHMENT(GL_COLOR_ATTACHMENT0), GL_TEXTURE_2D, m_color_texture_id, 0)); + + if (OpenGLManager::EFramebufferType::Ext == framebuffer_type) { + GLenum bufs[1]{ GL_COLOR_ATTACHMENT0_EXT }; + glsafe(::glDrawBuffers((GLsizei)1, bufs)); + } + else { + GLenum bufs[1]{ GL_COLOR_ATTACHMENT0 }; + glsafe(::glDrawBuffers((GLsizei)1, bufs)); + } + + glsafe(BBS_GL_EXTENSION_FUNC(::glGenRenderbuffers)(1, &m_depth_rbo_id)); + glsafe(BBS_GL_EXTENSION_FUNC(::glBindRenderbuffer)(BBS_GL_EXTENSION_RENDER_BUFFER, m_depth_rbo_id)); + + glsafe(BBS_GL_EXTENSION_FUNC(::glRenderbufferStorage)(BBS_GL_EXTENSION_RENDER_BUFFER, GL_DEPTH24_STENCIL8, m_width, m_height)); + + glsafe(BBS_GL_EXTENSION_FUNC(::glFramebufferRenderbuffer)(BBS_GL_EXTENSION_FRAMEBUFFER, BBS_GL_EXTENSION_DEPTH_ATTACHMENT, BBS_GL_EXTENSION_RENDER_BUFFER, m_depth_rbo_id)); + + if (OpenGLManager::EFramebufferType::Ext == framebuffer_type) { + if (::glCheckFramebufferStatusEXT(BBS_GL_EXTENSION_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE_EXT) + { + BOOST_LOG_TRIVIAL(error) << "Framebuffer is not complete!"; + glsafe(BBS_GL_EXTENSION_FUNC(::glBindFramebuffer)(BBS_GL_EXTENSION_FRAMEBUFFER, 0)); + return; + } + } + else { + if (::glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + BOOST_LOG_TRIVIAL(error) << "Framebuffer is not complete!"; + glsafe(BBS_GL_EXTENSION_FUNC(::glBindFramebuffer)(BBS_GL_EXTENSION_FRAMEBUFFER, 0)); + return; + } + } + BOOST_LOG_TRIVIAL(trace) << "Successfully created framebuffer: width = " << m_width << ", heihgt = " << m_height; + } + + glsafe(BBS_GL_EXTENSION_FUNC(::glBindFramebuffer)(BBS_GL_EXTENSION_FRAMEBUFFER, m_gl_id)); +} + +void FrameBuffer::unbind() +{ + const OpenGLManager::EFramebufferType framebuffer_type = OpenGLManager::get_framebuffers_type(); + if (OpenGLManager::EFramebufferType::Unknown == framebuffer_type) { + return; + } + glsafe(BBS_GL_EXTENSION_FUNC(::glBindFramebuffer)(BBS_GL_EXTENSION_FRAMEBUFFER, 0)); +} + +uint32_t FrameBuffer::get_color_texture() const noexcept +{ + return m_color_texture_id; +} + +bool FrameBuffer::is_texture_valid(uint32_t texture_id) const noexcept +{ + return m_color_texture_id != UINT32_MAX; +} + +OpenGLManager::FrameBufferModifier::FrameBufferModifier(OpenGLManager& ogl_manager, const std::string& frame_buffer_name) + : m_ogl_manager(ogl_manager) + , m_frame_buffer_name(frame_buffer_name) +{ + m_ogl_manager._bind_frame_buffer(m_frame_buffer_name); +} + +OpenGLManager::FrameBufferModifier::~FrameBufferModifier() +{ + m_ogl_manager._unbind_frame_buffer(m_frame_buffer_name); +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/OpenGLManager.hpp b/src/slic3r/GUI/OpenGLManager.hpp index f2670f8af..54f4656fa 100644 --- a/src/slic3r/GUI/OpenGLManager.hpp +++ b/src/slic3r/GUI/OpenGLManager.hpp @@ -2,6 +2,9 @@ #define slic3r_OpenGLManager_hpp_ #include "GLShadersManager.hpp" +#include +#include +#include class wxWindow; class wxGLCanvas; @@ -11,12 +14,33 @@ namespace Slic3r { namespace GUI { +struct FrameBuffer +{ + FrameBuffer(uint32_t width, uint32_t height); + ~FrameBuffer(); + + void bind(); + void unbind(); + + uint32_t get_color_texture() const noexcept; + + bool is_texture_valid(uint32_t texture_id) const noexcept; + +private: + uint32_t m_width{ 0 }; + uint32_t m_height{ 0 }; + uint32_t m_gl_id{ UINT32_MAX }; + uint32_t m_color_texture_id{ UINT32_MAX }; + uint32_t m_depth_rbo_id{ UINT32_MAX }; +}; + class OpenGLManager { public: enum class EFramebufferType : unsigned char { Unknown, + Supported, // supported, no extension required Arb, Ext }; @@ -28,6 +52,7 @@ public: float m_max_anisotropy{ 0.0f }; std::string m_version; + mutable uint32_t m_formated_gl_version{ 0 }; std::string m_glsl_version; std::string m_vendor; std::string m_renderer; @@ -36,6 +61,7 @@ public: GLInfo() = default; const std::string& get_version() const; + const uint32_t get_formated_gl_version() const; const std::string& get_glsl_version() const; const std::string& get_vendor() const; const std::string& get_renderer() const; @@ -54,6 +80,26 @@ public: void detect() const; }; + class FrameBufferModifier + { + public: + explicit FrameBufferModifier(OpenGLManager& ogl_manager, const std::string& frame_buffer_name); + ~FrameBufferModifier(); + + private: + // no copy + FrameBufferModifier(const FrameBufferModifier&) = delete; + FrameBufferModifier(FrameBufferModifier&&) = delete; + + // no assign + FrameBufferModifier& operator=(const FrameBufferModifier&) = delete; + FrameBufferModifier& operator=(FrameBufferModifier&&) = delete; + + private: + OpenGLManager& m_ogl_manager; + std::string m_frame_buffer_name{}; + }; + #ifdef __APPLE__ // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets struct OSInfo @@ -75,6 +121,10 @@ private: bool m_gl_initialized{ false }; wxGLContext* m_context{ nullptr }; GLShadersManager m_shaders_manager; + uint32_t m_viewport_width{ 0 }; + uint32_t m_viewport_height{ 0 }; + bool m_b_viewport_dirty{ true }; + std::unordered_map> m_name_to_frame_buffer; static GLInfo s_gl_info; #ifdef __APPLE__ // Part of hack to remove crash when closing the application on OSX 10.9.5 when building against newer wxWidgets @@ -95,16 +145,24 @@ public: GLShaderProgram* get_shader(const std::string& shader_name) { return m_shaders_manager.get_shader(shader_name); } GLShaderProgram* get_current_shader() { return m_shaders_manager.get_current_shader(); } + void clear_dirty(); + void set_viewport_size(uint32_t width, uint32_t height); + void get_viewport_size(uint32_t& width, uint32_t& height) const; + const std::shared_ptr& get_frame_buffer(const std::string& name) const; + static bool are_compressed_textures_supported() { return s_compressed_textures_supported; } static bool can_multisample() { return s_multisample == EMultisampleState::Enabled; } static bool are_framebuffers_supported() { return (s_framebuffers_type != EFramebufferType::Unknown); } static EFramebufferType get_framebuffers_type() { return s_framebuffers_type; } + static std::string framebuffer_type_to_string(EFramebufferType type); static wxGLCanvas* create_wxglcanvas(wxWindow& parent); static const GLInfo& get_gl_info() { return s_gl_info; } static bool use_manually_generated_mipmaps() { return m_use_manually_generated_mipmaps; } private: static void detect_multisample(int* attribList); + void _bind_frame_buffer(const std::string& name); + void _unbind_frame_buffer(const std::string& name); }; } // namespace GUI diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index bd1a546f6..fb4892266 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -1315,11 +1315,13 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f } } - switch (Slic3r::GUI::OpenGLManager::get_framebuffers_type()) + const auto fb_type = Slic3r::GUI::OpenGLManager::get_framebuffers_type(); + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": framebuffer_type: %1%") % Slic3r::GUI::OpenGLManager::framebuffer_type_to_string(fb_type).c_str(); + switch (fb_type) { + case Slic3r::GUI::OpenGLManager::EFramebufferType::Supported: case Slic3r::GUI::OpenGLManager::EFramebufferType::Arb: { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": framebuffer_type: ARB"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer(*thumbnail_data, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model->objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); @@ -1327,14 +1329,12 @@ bool CalibUtils::process_and_store_3mf(Model *model, const DynamicPrintConfig &f } case Slic3r::GUI::OpenGLManager::EFramebufferType::Ext: { - BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": framebuffer_type: EXT"); Slic3r::GUI::GLCanvas3D::render_thumbnail_framebuffer_ext(*thumbnail_data, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model->objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); break; } default:{ - BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< boost::format(": framebuffer_type: others"); Slic3r::GUI::GLCanvas3D::render_thumbnail_legacy(*thumbnail_data, thumbnail_width, thumbnail_height, thumbnail_params, partplate_list, model->objects, glvolume_collection, colors_out, shader, Slic3r::GUI::Camera::EType::Ortho); break; }