diff --git a/resources/icons/Pmetal_001.png b/resources/icons/Pmetal_001.png new file mode 100644 index 000000000..c848f839c Binary files /dev/null and b/resources/icons/Pmetal_001.png differ diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index 853a5512c..45175acc2 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -17,6 +17,9 @@ struct SlopeDetection uniform vec4 uniform_color; uniform SlopeDetection slope; +uniform sampler2D environment_tex; +uniform bool use_environment_tex; + varying vec3 clipping_planes_dots; // x = tainted, y = specular; @@ -26,6 +29,7 @@ varying vec3 delta_box_min; varying vec3 delta_box_max; varying float world_normal_z; +varying vec3 eye_normal; vec3 slope_color() { @@ -40,5 +44,8 @@ void main() vec3 color = slope.actived ? slope_color() : uniform_color.rgb; // if the fragment is outside the print volume -> use darker color color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; - gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); + if (use_environment_tex) + gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, uniform_color.a); + else + gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, uniform_color.a); } diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index 2644d48e4..d60f6eae8 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -51,22 +51,23 @@ varying vec3 delta_box_max; varying vec3 clipping_planes_dots; varying float world_normal_z; +varying vec3 eye_normal; void main() { // First transform the normal into camera space and normalize the result. - vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + eye_normal = normalize(gl_NormalMatrix * gl_Normal); // Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex. // Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range. - float NdotL = max(dot(normal, LIGHT_TOP_DIR), 0.0); + float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0); intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE; vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz; - intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, normal)), 0.0), LIGHT_TOP_SHININESS); + intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS); // Perform the same lighting calculation for the 2nd light source (no specular applied). - NdotL = max(dot(normal, LIGHT_FRONT_DIR), 0.0); + NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0); intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // compute deltas for out of print volume detection (world coordinates) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index f9a2328fa..b29b1a7f6 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -42,5 +42,8 @@ // Enable rendering of objects colored by facets' slope #define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1) +// Enable rendering of objects using environment map +#define ENABLE_ENVIRONMENT_MAP (1 && ENABLE_2_3_0_ALPHA1) + #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 2fee7050a..4c61270cf 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1,6 +1,11 @@ #include #include "3DScene.hpp" +#if ENABLE_ENVIRONMENT_MAP +#include "GUI_App.hpp" +#include "Plater.hpp" +#include "AppConfig.hpp" +#endif // ENABLE_ENVIRONMENT_MAP #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/ExtrusionEntityCollection.hpp" @@ -663,6 +668,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1; GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1; #endif // ENABLE_SLOPE_RENDERING + +#if ENABLE_ENVIRONMENT_MAP + GLint use_environment_tex_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "use_environment_tex") : -1; +#endif // ENABLE_ENVIRONMENT_MAP glcheck(); if (print_box_min_id != -1) @@ -682,6 +691,18 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab glsafe(::glUniform2fv(slope_z_range_id, 1, (const GLfloat*)m_slope.z_range.data())); #endif // ENABLE_SLOPE_RENDERING +#if ENABLE_ENVIRONMENT_MAP + unsigned int environment_texture_id = GUI::wxGetApp().plater()->get_environment_texture_id(); + bool use_environment_texture = current_program_id > 0 && environment_texture_id > 0 && GUI::wxGetApp().app_config->get("use_environment_map") == "1"; + + if (use_environment_tex_id != -1) + { + glsafe(::glUniform1i(use_environment_tex_id, use_environment_texture ? 1 : 0)); + if (use_environment_texture) + glsafe(::glBindTexture(GL_TEXTURE_2D, environment_texture_id)); + } +#endif // ENABLE_ENVIRONMENT_MAP + GLVolumeWithIdAndZList to_render = volumes_to_render(this->volumes, type, view_matrix, filter_func); for (GLVolumeWithIdAndZ& volume : to_render) { volume.first->set_render_color(); @@ -712,6 +733,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab #endif // ENABLE_SLOPE_RENDERING } +#if ENABLE_ENVIRONMENT_MAP + if (use_environment_tex_id != -1 && use_environment_texture) + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); +#endif // ENABLE_ENVIRONMENT_MAP + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); diff --git a/src/slic3r/GUI/AppConfig.cpp b/src/slic3r/GUI/AppConfig.cpp index ba13a25d8..c9d4c026f 100644 --- a/src/slic3r/GUI/AppConfig.cpp +++ b/src/slic3r/GUI/AppConfig.cpp @@ -93,6 +93,11 @@ void AppConfig::set_defaults() if (get("use_free_camera").empty()) set("use_free_camera", "0"); +#if ENABLE_ENVIRONMENT_MAP + if (get("use_environment_map").empty()) + set("use_environment_map", "0"); +#endif // ENABLE_ENVIRONMENT_MAP + // Remove legacy window positions/sizes erase("", "main_frame_maximized"); erase("", "main_frame_pos"); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 2f75f6a37..69bebc301 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1994,6 +1994,10 @@ void GLCanvas3D::render() return; } +#if ENABLE_ENVIRONMENT_MAP + wxGetApp().plater()->init_environment_texture(); +#endif // ENABLE_ENVIRONMENT_MAP + const Size& cnv_size = get_canvas_size(); // Probably due to different order of events on Linux/GTK2, when one switched from 3D scene // to preview, this was called before canvas had its final size. It reported zero width diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 7f60b38b4..03bbab796 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1583,6 +1583,9 @@ struct Plater::priv Sidebar *sidebar; Bed3D bed; Camera camera; +#if ENABLE_ENVIRONMENT_MAP + GLTexture environment_texture; +#endif // ENABLE_ENVIRONMENT_MAP Mouse3DController mouse3d_controller; View3D* view3D; GLToolbar view_toolbar; @@ -2078,7 +2081,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) }); wxGetApp().other_instance_message_handler()->init(this->q); - // collapse sidebar according to saved value bool is_collapsed = wxGetApp().app_config->get("collapsed_sidebar") == "1"; sidebar->collapse(is_collapsed); @@ -5531,6 +5533,19 @@ Camera& Plater::get_camera() return p->camera; } +#if ENABLE_ENVIRONMENT_MAP +void Plater::init_environment_texture() +{ + if (p->environment_texture.get_id() == 0) + p->environment_texture.load_from_file(resources_dir() + "/icons/Pmetal_001.png", false, GLTexture::SingleThreaded, false); +} + +unsigned int Plater::get_environment_texture_id() const +{ + return p->environment_texture.get_id(); +} +#endif // ENABLE_ENVIRONMENT_MAP + const Bed3D& Plater::get_bed() const { return p->bed; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 970005055..10b6b354e 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -319,6 +319,11 @@ public: const Camera& get_camera() const; Camera& get_camera(); +#if ENABLE_ENVIRONMENT_MAP + void init_environment_texture(); + unsigned int get_environment_texture_id() const; +#endif // ENABLE_ENVIRONMENT_MAP + const Bed3D& get_bed() const; Bed3D& get_bed(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 35f2ee429..50abfb7e6 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -180,10 +180,28 @@ void PreferencesDialog::build() create_settings_mode_widget(); +#if ENABLE_ENVIRONMENT_MAP + m_optgroup_render = std::make_shared(this, _(L("Render"))); + m_optgroup_render->label_width = 40; + m_optgroup_render->m_on_change = [this](t_config_option_key opt_key, boost::any value) { + m_values[opt_key] = boost::any_cast(value) ? "1" : "0"; + }; + + def.label = L("Use environment map"); + def.type = coBool; + def.tooltip = L("If enabled, renders object using the environment map."); + def.set_default_value(new ConfigOptionBool{ app_config->get("use_environment_map") == "1" }); + option = Option(def, "use_environment_map"); + m_optgroup_render->append_single_option_line(option); +#endif // ENABLE_ENVIRONMENT_MAP + auto sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); sizer->Add(m_optgroup_gui->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); +#if ENABLE_ENVIRONMENT_MAP + sizer->Add(m_optgroup_render->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); +#endif // ENABLE_ENVIRONMENT_MAP SetFont(wxGetApp().normal_font()); diff --git a/src/slic3r/GUI/Preferences.hpp b/src/slic3r/GUI/Preferences.hpp index d90f01e2b..f61c4d932 100644 --- a/src/slic3r/GUI/Preferences.hpp +++ b/src/slic3r/GUI/Preferences.hpp @@ -20,6 +20,9 @@ class PreferencesDialog : public DPIDialog std::shared_ptr m_optgroup_general; std::shared_ptr m_optgroup_camera; std::shared_ptr m_optgroup_gui; +#if ENABLE_ENVIRONMENT_MAP + std::shared_ptr m_optgroup_render; +#endif // ENABLE_ENVIRONMENT_MAP wxSizer* m_icon_size_sizer; wxRadioBox* m_layout_mode_box; bool isOSX {false};