mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-25 01:40:57 +00:00
Improve preview colors (#15809)
Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
co-authored by
Rodrigo Faselli
parent
f83bfa17ff
commit
d820303a3f
@@ -303,6 +303,9 @@ void AppConfig::set_defaults()
|
||||
if (get(SETTING_OPENGL_REALISTIC_PHONG).empty())
|
||||
set_bool(SETTING_OPENGL_REALISTIC_PHONG, true);
|
||||
|
||||
if (get(SETTING_OPENGL_REALISTIC_PREVIEW).empty())
|
||||
set_bool(SETTING_OPENGL_REALISTIC_PREVIEW, false);
|
||||
|
||||
if (get(SETTING_OPENGL_SHADING_MODEL).empty())
|
||||
set(SETTING_OPENGL_SHADING_MODEL, "gouraud");
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ using namespace nlohmann;
|
||||
#define SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS "opengl_phong_basic_plate_shadows"
|
||||
#define SETTING_OPENGL_PHONG_SSAO "opengl_phong_ssao"
|
||||
#define SETTING_OPENGL_PHONG_SMOOTH_NORMALS "opengl_phong_smooth_normals"
|
||||
#define SETTING_OPENGL_REALISTIC_PREVIEW "opengl_realistic_preview"
|
||||
|
||||
#define SETTING_PLUGIN_PAGES_VISIBLE_COUNT "plugin_pages_visible_count"
|
||||
#define PLUGIN_PAGES_VISIBLE_COUNT_MIN 1
|
||||
|
||||
@@ -60,6 +60,22 @@ public:
|
||||
// using the given camera matrices.
|
||||
//
|
||||
void render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
|
||||
//
|
||||
// ORCA: realistic view. Render the toolpaths as seen from the light, to fill the caller's
|
||||
// shadow map. Depth only - the caller masks colour writes and owns the framebuffer.
|
||||
//
|
||||
void render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position);
|
||||
//
|
||||
// ORCA: realistic view. The shadow map the toolpaths sample, in the given texture unit.
|
||||
// intensity == 0, the default, turns the lookup off and restores the plain shading.
|
||||
//
|
||||
void set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size);
|
||||
//
|
||||
// ORCA: tone applied to the shaded toolpaths, to pay back the light the lighting term,
|
||||
// the shadow and the SSAO pass each take off. 1.0/1.0, the default, is a no-op; the
|
||||
// caller decides which of the two it varies with the realistic view setting.
|
||||
//
|
||||
void set_tone(float exposure, float saturation);
|
||||
|
||||
//
|
||||
// ************************************************************************
|
||||
|
||||
@@ -16,7 +16,8 @@ static const char* Segments_Vertex_Shader =
|
||||
"#define FIX_TWISTING\n"
|
||||
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
|
||||
"const float light_top_diffuse = 0.6 * 0.8;\n"
|
||||
"const float light_top_specular = 0.6 * 0.125;\n"
|
||||
// ORCA: the specular was 0.6 * 0.125, too faint to give the filament any sheen.
|
||||
"const float light_top_specular = 0.6 * 0.25;\n"
|
||||
"const float light_top_shininess = 20.0;\n"
|
||||
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
|
||||
"const float light_front_diffuse = 0.6 * 0.2;\n"
|
||||
@@ -30,8 +31,19 @@ static const char* Segments_Vertex_Shader =
|
||||
"uniform samplerBuffer height_width_angle_tex;\n"
|
||||
"uniform samplerBuffer color_tex;\n"
|
||||
"uniform usamplerBuffer segment_index_tex;\n"
|
||||
// ORCA: 0 during the shadow caster pass - the bias below shifts eye_position but not
|
||||
// world_position, so the caster would write a depth the receiver never looks up.
|
||||
"uniform float bias_scale;\n"
|
||||
"in int vertex_id;\n"
|
||||
"out vec3 color;\n"
|
||||
"// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n"
|
||||
"// ambient and emissive terms in color, which a shadow does not occlude. Their sum is the\n"
|
||||
"// single lighting term this replaces, so shading is unchanged while shadows are off.\n"
|
||||
"out vec3 color_direct;\n"
|
||||
"// ORCA: realistic view - the fragment shader looks the fragment up in the shadow map, which\n"
|
||||
"// needs its world position and, for the depth bias, its eye space normal.\n"
|
||||
"out vec3 world_position;\n"
|
||||
"out vec3 shadow_normal;\n"
|
||||
"vec3 decode_color(float color) {\n"
|
||||
" int c = int(round(color));\n"
|
||||
" int r = (c >> 16) & 0xFF;\n"
|
||||
@@ -40,11 +52,11 @@ static const char* Segments_Vertex_Shader =
|
||||
" float f = 1.0 / 255.0f;\n"
|
||||
" return f * vec3(r, g, b);\n"
|
||||
"}\n"
|
||||
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
|
||||
"float direct_lighting(vec3 eye_position, vec3 eye_normal) {\n"
|
||||
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
|
||||
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
|
||||
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
|
||||
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
|
||||
" return top_diffuse + front_diffuse + top_specular;\n"
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
" int id_a = int(texelFetch(segment_index_tex, gl_InstanceID).r);\n"
|
||||
@@ -135,19 +147,63 @@ static const char* Segments_Vertex_Shader =
|
||||
" }\n"
|
||||
" vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n"
|
||||
" // ORCA: Apply bias to z-position to avoid z-fighting\n"
|
||||
" eye_position.z += bias;\n"
|
||||
" eye_position.z += bias * bias_scale;\n"
|
||||
" vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n"
|
||||
" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n"
|
||||
" color = color_base * lighting(eye_position, eye_normal);\n"
|
||||
" color = color_base * (ambient + emission);\n"
|
||||
" color_direct = color_base * direct_lighting(eye_position, eye_normal);\n"
|
||||
" world_position = pos;\n"
|
||||
" shadow_normal = eye_normal;\n"
|
||||
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* Segments_Fragment_Shader =
|
||||
"#version 150\n"
|
||||
"// ORCA: realistic view - object-on-object and self shadows, read from the same depth map the\n"
|
||||
"// rest of the 3D scene samples. shadow_intensity == 0, the default, short-circuits the lookup,\n"
|
||||
"// so the toolpaths shade exactly as before whenever realistic view is off.\n"
|
||||
"const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
|
||||
"uniform sampler2D shadow_map;\n"
|
||||
"uniform mat4 shadow_light_vp;\n"
|
||||
"uniform float shadow_intensity;\n"
|
||||
"uniform float shadow_map_texel;\n"
|
||||
// ORCA: the lighting term peaks near 0.9 and every later multiplier - the shadow, then the SSAO
|
||||
// post pass - only takes more light away, so the print reads dimmer and duller than the legend
|
||||
// colours. These pay that back. Both are 1.0 for an untouched image; what the caller actually
|
||||
// passes in each mode is decided in GLCanvas3D::_render_gcode, not here.
|
||||
"uniform float exposure;\n"
|
||||
"uniform float saturation;\n"
|
||||
"const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);\n"
|
||||
"in vec3 color;\n"
|
||||
"in vec3 color_direct;\n"
|
||||
"in vec3 world_position;\n"
|
||||
"in vec3 shadow_normal;\n"
|
||||
"out vec4 fragment_color;\n"
|
||||
"float shadow_shade() {\n"
|
||||
" if (shadow_intensity <= 0.0)\n"
|
||||
" return 1.0;\n"
|
||||
" vec4 lp = shadow_light_vp * vec4(world_position, 1.0);\n"
|
||||
" vec3 proj = lp.xyz / lp.w;\n"
|
||||
" proj = proj * 0.5 + 0.5;\n"
|
||||
" if (proj.z > 1.0)\n"
|
||||
" return 1.0;\n"
|
||||
" // Slope-scaled bias, as in gouraud.fs. An extrusion is only a handful of shadow-map texels\n"
|
||||
" // wide, so grazing faces need the larger bias to keep self-shadow acne off the top surfaces.\n"
|
||||
" float NdotL = dot(normalize(shadow_normal), SHADOW_LIGHT_DIR);\n"
|
||||
" float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));\n"
|
||||
" float sum = 0.0;\n"
|
||||
" for (int x = -2; x <= 2; ++x) {\n"
|
||||
" for (int y = -2; y <= 2; ++y) {\n"
|
||||
" float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;\n"
|
||||
" sum += (proj.z - bias > closest) ? 1.0 : 0.0;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" return 1.0 - shadow_intensity * (sum / 25.0);\n"
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
" fragment_color = vec4(color, 1.0);\n"
|
||||
" vec3 c = (color + color_direct * shadow_shade()) * exposure;\n"
|
||||
" c = mix(vec3(dot(c, LUMA)), c, saturation);\n"
|
||||
" fragment_color = vec4(clamp(c, 0.0, 1.0), 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* Options_Vertex_Shader =
|
||||
|
||||
@@ -17,7 +17,8 @@ static const char* Segments_Vertex_Shader_ES =
|
||||
"#define FIX_TWISTING\n"
|
||||
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
|
||||
"const float light_top_diffuse = 0.6 * 0.8;\n"
|
||||
"const float light_top_specular = 0.6 * 0.125;\n"
|
||||
// ORCA: the specular was 0.6 * 0.125, too faint to give the filament any sheen.
|
||||
"const float light_top_specular = 0.6 * 0.25;\n"
|
||||
"const float light_top_shininess = 20.0;\n"
|
||||
"const vec3 light_front_dir = vec3(0.6985074, 0.1397015, 0.6985074);\n"
|
||||
"const float light_front_diffuse = 0.6 * 0.3;\n"
|
||||
@@ -33,6 +34,14 @@ static const char* Segments_Vertex_Shader_ES =
|
||||
"uniform usampler2D segment_index_tex;\n"
|
||||
"in float vertex_id_float;\n"
|
||||
"out vec3 color;\n"
|
||||
"// ORCA: realistic view - the light the shadow map is able to block, kept apart from the\n"
|
||||
"// ambient and emissive terms in color, which a shadow does not occlude. Their sum is the\n"
|
||||
"// single lighting term this replaces, so shading is unchanged while shadows are off.\n"
|
||||
"out vec3 color_direct;\n"
|
||||
"// ORCA: realistic view - the fragment shader looks the fragment up in the shadow map, which\n"
|
||||
"// needs its world position and, for the depth bias, its eye space normal.\n"
|
||||
"out vec3 world_position;\n"
|
||||
"out vec3 shadow_normal;\n"
|
||||
"vec3 decode_color(float color) {\n"
|
||||
" int c = int(round(color));\n"
|
||||
" int r = (c >> 16) & 0xFF;\n"
|
||||
@@ -41,11 +50,11 @@ static const char* Segments_Vertex_Shader_ES =
|
||||
" float f = 1.0 / 255.0f;\n"
|
||||
" return f * vec3(r, g, b);\n"
|
||||
"}\n"
|
||||
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
|
||||
"float direct_lighting(vec3 eye_position, vec3 eye_normal) {\n"
|
||||
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
|
||||
" float front_diffuse = light_front_diffuse * max(dot(eye_normal, light_front_dir), 0.0);\n"
|
||||
" float top_specular = light_top_specular * pow(max(dot(-normalize(eye_position), reflect(-light_top_dir, eye_normal)), 0.0), light_top_shininess);\n"
|
||||
" return ambient + top_diffuse + front_diffuse + top_specular + emission;\n"
|
||||
" return top_diffuse + front_diffuse + top_specular;\n"
|
||||
"}\n"
|
||||
"ivec2 tex_coord(sampler2D sampler, int id) {\n"
|
||||
" ivec2 tex_size = textureSize(sampler, 0);\n"
|
||||
@@ -143,17 +152,64 @@ static const char* Segments_Vertex_Shader_ES =
|
||||
" vec3 eye_position = (view_matrix * vec4(pos, 1.0)).xyz;\n"
|
||||
" vec3 eye_normal = (view_matrix * vec4(normalize(pos - endpoint_pos), 0.0)).xyz;\n"
|
||||
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n"
|
||||
" color = color_base * lighting(eye_position, eye_normal);\n"
|
||||
" color = color_base * (ambient + emission);\n"
|
||||
" color_direct = color_base * direct_lighting(eye_position, eye_normal);\n"
|
||||
" world_position = pos;\n"
|
||||
" shadow_normal = eye_normal;\n"
|
||||
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* Segments_Fragment_Shader_ES =
|
||||
"#version 300 es\n"
|
||||
"precision highp float;\n"
|
||||
"// ORCA: sampler2D defaults to lowp in an ES fragment shader, far too coarse to compare\n"
|
||||
"// shadow map depths against.\n"
|
||||
"precision highp sampler2D;\n"
|
||||
"// ORCA: realistic view - object-on-object and self shadows, read from the same depth map the\n"
|
||||
"// rest of the 3D scene samples. shadow_intensity == 0, the default, short-circuits the lookup,\n"
|
||||
"// so the toolpaths shade exactly as before whenever realistic view is off.\n"
|
||||
"const vec3 SHADOW_LIGHT_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
|
||||
"uniform sampler2D shadow_map;\n"
|
||||
"uniform mat4 shadow_light_vp;\n"
|
||||
"uniform float shadow_intensity;\n"
|
||||
"uniform float shadow_map_texel;\n"
|
||||
// ORCA: the lighting term peaks near 0.9 and every later multiplier - the shadow, then the SSAO
|
||||
// post pass - only takes more light away, so the print reads dimmer and duller than the legend
|
||||
// colours. These pay that back. Both are 1.0 for an untouched image; what the caller actually
|
||||
// passes in each mode is decided in GLCanvas3D::_render_gcode, not here.
|
||||
"uniform float exposure;\n"
|
||||
"uniform float saturation;\n"
|
||||
"const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);\n"
|
||||
"in vec3 color;\n"
|
||||
"in vec3 color_direct;\n"
|
||||
"in vec3 world_position;\n"
|
||||
"in vec3 shadow_normal;\n"
|
||||
"out vec4 fragment_color;\n"
|
||||
"float shadow_shade() {\n"
|
||||
" if (shadow_intensity <= 0.0)\n"
|
||||
" return 1.0;\n"
|
||||
" vec4 lp = shadow_light_vp * vec4(world_position, 1.0);\n"
|
||||
" vec3 proj = lp.xyz / lp.w;\n"
|
||||
" proj = proj * 0.5 + 0.5;\n"
|
||||
" if (proj.z > 1.0)\n"
|
||||
" return 1.0;\n"
|
||||
" // Slope-scaled bias, as in gouraud.fs. An extrusion is only a handful of shadow-map texels\n"
|
||||
" // wide, so grazing faces need the larger bias to keep self-shadow acne off the top surfaces.\n"
|
||||
" float NdotL = dot(normalize(shadow_normal), SHADOW_LIGHT_DIR);\n"
|
||||
" float bias = mix(0.0004, 0.004, clamp(1.0 - NdotL, 0.0, 1.0));\n"
|
||||
" float sum = 0.0;\n"
|
||||
" for (int x = -2; x <= 2; ++x) {\n"
|
||||
" for (int y = -2; y <= 2; ++y) {\n"
|
||||
" float closest = texture(shadow_map, proj.xy + vec2(float(x), float(y)) * shadow_map_texel).r;\n"
|
||||
" sum += (proj.z - bias > closest) ? 1.0 : 0.0;\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
" return 1.0 - shadow_intensity * (sum / 25.0);\n"
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
" fragment_color = vec4(color, 1.0);\n"
|
||||
" vec3 c = (color + color_direct * shadow_shade()) * exposure;\n"
|
||||
" c = mix(vec3(dot(c, LUMA)), c, saturation);\n"
|
||||
" fragment_color = vec4(clamp(c, 0.0, 1.0), 1.0);\n"
|
||||
"}\n";
|
||||
|
||||
static const char* Options_Vertex_Shader_ES =
|
||||
|
||||
@@ -42,6 +42,21 @@ void Viewer::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
|
||||
m_impl->render(view_matrix, projection_matrix);
|
||||
}
|
||||
|
||||
void Viewer::render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position)
|
||||
{
|
||||
m_impl->render_shadow_casters(view_matrix, projection_matrix, light_position);
|
||||
}
|
||||
|
||||
void Viewer::set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size)
|
||||
{
|
||||
m_impl->set_shadow_map(texture_unit, light_view_projection, intensity, texel_size);
|
||||
}
|
||||
|
||||
void Viewer::set_tone(float exposure, float saturation)
|
||||
{
|
||||
m_impl->set_tone(exposure, saturation);
|
||||
}
|
||||
|
||||
EViewType Viewer::get_view_type() const
|
||||
{
|
||||
return m_impl->get_view_type();
|
||||
|
||||
@@ -763,6 +763,14 @@ void ViewerImpl::init(const std::string& opengl_context_version)
|
||||
m_uni_segments_height_width_angle_tex_id = glGetUniformLocation(m_segments_shader_id, "height_width_angle_tex");
|
||||
m_uni_segments_colors_tex_id = glGetUniformLocation(m_segments_shader_id, "color_tex");
|
||||
m_uni_segments_segment_index_tex_id = glGetUniformLocation(m_segments_shader_id, "segment_index_tex");
|
||||
// ORCA: realistic view
|
||||
m_uni_segments_shadow_map_id = glGetUniformLocation(m_segments_shader_id, "shadow_map");
|
||||
m_uni_segments_shadow_light_vp_id = glGetUniformLocation(m_segments_shader_id, "shadow_light_vp");
|
||||
m_uni_segments_shadow_intensity_id = glGetUniformLocation(m_segments_shader_id, "shadow_intensity");
|
||||
m_uni_segments_shadow_map_texel_id = glGetUniformLocation(m_segments_shader_id, "shadow_map_texel");
|
||||
m_uni_segments_exposure_id = glGetUniformLocation(m_segments_shader_id, "exposure");
|
||||
m_uni_segments_saturation_id = glGetUniformLocation(m_segments_shader_id, "saturation");
|
||||
m_uni_segments_bias_scale_id = glGetUniformLocation(m_segments_shader_id, "bias_scale");
|
||||
glcheck();
|
||||
assert(m_uni_segments_view_matrix_id != -1 &&
|
||||
m_uni_segments_projection_matrix_id != -1 &&
|
||||
@@ -1321,7 +1329,7 @@ void ViewerImpl::update_colors()
|
||||
m_settings.update_colors = false;
|
||||
}
|
||||
|
||||
void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
|
||||
void ViewerImpl::apply_pending_updates()
|
||||
{
|
||||
if (m_settings.update_view_full_range)
|
||||
update_view_full_range();
|
||||
@@ -1331,6 +1339,11 @@ void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matr
|
||||
|
||||
if (m_settings.update_colors)
|
||||
update_colors();
|
||||
}
|
||||
|
||||
void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix)
|
||||
{
|
||||
apply_pending_updates();
|
||||
|
||||
const Mat4x4 inv_view_matrix = inverse(view_matrix);
|
||||
const Vec3 camera_position = { inv_view_matrix[12], inv_view_matrix[13], inv_view_matrix[14] };
|
||||
@@ -1345,6 +1358,30 @@ void ViewerImpl::render(const Mat4x4& view_matrix, const Mat4x4& projection_matr
|
||||
#endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS
|
||||
}
|
||||
|
||||
void ViewerImpl::render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position)
|
||||
{
|
||||
apply_pending_updates();
|
||||
|
||||
// Only the extrusions and travels cast: the option markers are indicators, not material.
|
||||
m_rendering_shadow_casters = true;
|
||||
render_segments(view_matrix, projection_matrix, light_position);
|
||||
m_rendering_shadow_casters = false;
|
||||
}
|
||||
|
||||
void ViewerImpl::set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size)
|
||||
{
|
||||
m_shadow_map_texture_unit = texture_unit;
|
||||
m_shadow_light_vp = light_view_projection;
|
||||
m_shadow_intensity = intensity;
|
||||
m_shadow_map_texel = texel_size;
|
||||
}
|
||||
|
||||
void ViewerImpl::set_tone(float exposure, float saturation)
|
||||
{
|
||||
m_exposure = exposure;
|
||||
m_saturation = saturation;
|
||||
}
|
||||
|
||||
void ViewerImpl::set_view_type(EViewType type)
|
||||
{
|
||||
m_settings.view_type = type;
|
||||
@@ -1994,6 +2031,15 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
|
||||
glsafe(glUniformMatrix4fv(m_uni_segments_view_matrix_id, 1, GL_FALSE, view_matrix.data()));
|
||||
glsafe(glUniformMatrix4fv(m_uni_segments_projection_matrix_id, 1, GL_FALSE, projection_matrix.data()));
|
||||
glsafe(glUniform3fv(m_uni_segments_camera_position_id, 1, camera_position.data()));
|
||||
// ORCA: realistic view. The depth pass writes the map it would otherwise read, so it shades
|
||||
// with the lookup off.
|
||||
glsafe(glUniform1i(m_uni_segments_shadow_map_id, m_shadow_map_texture_unit));
|
||||
glsafe(glUniformMatrix4fv(m_uni_segments_shadow_light_vp_id, 1, GL_FALSE, m_shadow_light_vp.data()));
|
||||
glsafe(glUniform1f(m_uni_segments_shadow_intensity_id, m_rendering_shadow_casters ? 0.0f : m_shadow_intensity));
|
||||
glsafe(glUniform1f(m_uni_segments_shadow_map_texel_id, m_shadow_map_texel));
|
||||
glsafe(glUniform1f(m_uni_segments_exposure_id, m_exposure));
|
||||
glsafe(glUniform1f(m_uni_segments_saturation_id, m_saturation));
|
||||
glsafe(glUniform1f(m_uni_segments_bias_scale_id, m_rendering_shadow_casters ? 0.0f : 1.0f));
|
||||
|
||||
glsafe(glDisable(GL_CULL_FACE));
|
||||
|
||||
|
||||
@@ -71,6 +71,24 @@ public:
|
||||
// Render the toolpaths
|
||||
//
|
||||
void render(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
|
||||
//
|
||||
// ORCA: realistic view. Render the toolpaths as seen from the light, to fill the caller's
|
||||
// shadow map. Only depth matters here, so the caller masks colour writes; light_position
|
||||
// takes the place of the camera when the segment boxes are expanded, which gives their
|
||||
// silhouette as the light sees it.
|
||||
//
|
||||
void render_shadow_casters(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& light_position);
|
||||
//
|
||||
// ORCA: realistic view. The shadow map the toolpaths sample, in the given texture unit.
|
||||
// intensity == 0, the default, turns the lookup off and restores the plain shading.
|
||||
//
|
||||
void set_shadow_map(int texture_unit, const Mat4x4& light_view_projection, float intensity, float texel_size);
|
||||
//
|
||||
// ORCA: tone applied to the shaded toolpaths, to pay back the light the lighting term,
|
||||
// the shadow and the SSAO pass each take off. 1.0/1.0, the default, is a no-op; the
|
||||
// caller decides which of the two it varies with the realistic view setting.
|
||||
//
|
||||
void set_tone(float exposure, float saturation);
|
||||
|
||||
EViewType get_view_type() const { return m_settings.view_type; }
|
||||
void set_view_type(EViewType type);
|
||||
@@ -330,6 +348,13 @@ private:
|
||||
int m_uni_segments_height_width_angle_tex_id{ -1 };
|
||||
int m_uni_segments_colors_tex_id{ -1 };
|
||||
int m_uni_segments_segment_index_tex_id{ -1 };
|
||||
int m_uni_segments_shadow_map_id{ -1 };
|
||||
int m_uni_segments_shadow_light_vp_id{ -1 };
|
||||
int m_uni_segments_shadow_intensity_id{ -1 };
|
||||
int m_uni_segments_shadow_map_texel_id{ -1 };
|
||||
int m_uni_segments_exposure_id{ -1 };
|
||||
int m_uni_segments_saturation_id{ -1 };
|
||||
int m_uni_segments_bias_scale_id{ -1 };
|
||||
//
|
||||
// Caches for OpenGL uniforms id for options shader
|
||||
//
|
||||
@@ -469,6 +494,27 @@ private:
|
||||
size_t m_enabled_options_tex_size{ 0 };
|
||||
#endif // ENABLE_OPENGL_ES
|
||||
|
||||
//
|
||||
// ORCA: realistic view. Shadow map state set by set_shadow_map(), consumed by the segments
|
||||
// shader. m_rendering_shadow_casters forces the intensity to 0 for the depth pass, which
|
||||
// must not sample the very map it is writing.
|
||||
//
|
||||
// Defaults past the four texture units render_segments() binds itself, so the sampler never
|
||||
// aliases one of the buffer textures before the owner of the map has said where it lives.
|
||||
int m_shadow_map_texture_unit{ 4 };
|
||||
Mat4x4 m_shadow_light_vp{ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
float m_shadow_intensity{ 0.0f };
|
||||
float m_shadow_map_texel{ 0.0f };
|
||||
bool m_rendering_shadow_casters{ false };
|
||||
|
||||
//
|
||||
// ORCA: realistic view. Tone set by set_tone(), consumed by the segments shader.
|
||||
// The identity values leave the shading as it is outside realistic view.
|
||||
//
|
||||
float m_exposure{ 1.0f };
|
||||
float m_saturation{ 1.0f };
|
||||
|
||||
void apply_pending_updates();
|
||||
void update_view_full_range();
|
||||
void update_color_ranges();
|
||||
void update_heights_widths();
|
||||
|
||||
@@ -1641,6 +1641,29 @@ void GCodeViewer::render_scene(int canvas_width, int canvas_height)
|
||||
m_sequential_view.render_marker(!m_no_render_path, canvas_width, sequential_view_height(canvas_height), m_viewer.get_view_type());
|
||||
}
|
||||
|
||||
void GCodeViewer::render_shadow_casters(const Transform3d& light_view_matrix, const Transform3d& light_projection_matrix, const Vec3d& light_position)
|
||||
{
|
||||
if (!has_data())
|
||||
return;
|
||||
|
||||
m_viewer.render_shadow_casters(
|
||||
libvgcode::convert(static_cast<Matrix4f>(light_view_matrix.matrix().cast<float>())),
|
||||
libvgcode::convert(static_cast<Matrix4f>(light_projection_matrix.matrix().cast<float>())),
|
||||
libvgcode::convert(static_cast<Vec3f>(light_position.cast<float>())));
|
||||
}
|
||||
|
||||
void GCodeViewer::set_shadow_map(int texture_unit, const Transform3d& light_view_projection, float intensity, float texel_size)
|
||||
{
|
||||
m_viewer.set_shadow_map(texture_unit,
|
||||
libvgcode::convert(static_cast<Matrix4f>(light_view_projection.matrix().cast<float>())),
|
||||
intensity, texel_size);
|
||||
}
|
||||
|
||||
void GCodeViewer::set_tone(float exposure, float saturation)
|
||||
{
|
||||
m_viewer.set_tone(exposure, saturation);
|
||||
}
|
||||
|
||||
void GCodeViewer::render_overlay(int canvas_width, int canvas_height, int right_margin)
|
||||
{
|
||||
if (m_viewer.get_extrusion_roles().empty())
|
||||
|
||||
@@ -279,6 +279,13 @@ public:
|
||||
void render_scene(int canvas_width, int canvas_height);
|
||||
// Legend, sliders, the marker's position window and the G-code window, all ImGui.
|
||||
void render_overlay(int canvas_width, int canvas_height, int right_margin);
|
||||
// ORCA: realistic view. Depth-only pass drawing the toolpaths as the light sees them, into
|
||||
// the shadow map the caller has bound, and the map they sample back in render_scene.
|
||||
void render_shadow_casters(const Transform3d& light_view_matrix, const Transform3d& light_projection_matrix, const Vec3d& light_position);
|
||||
void set_shadow_map(int texture_unit, const Transform3d& light_view_projection, float intensity, float texel_size);
|
||||
// ORCA: tone applied to the shaded toolpaths, paying back the light the lighting term,
|
||||
// the shadow and the SSAO pass each take off. 1.0/1.0 is a no-op.
|
||||
void set_tone(float exposure, float saturation);
|
||||
//BBS
|
||||
// void _render_calibration_thumbnail_internal(ThumbnailData& thumbnail_data, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||
// void _render_calibration_thumbnail_framebuffer(ThumbnailData& thumbnail_data, unsigned int w, unsigned int h, const ThumbnailsParams& thumbnail_params, PartPlateList& partplate_list, OpenGLManager& opengl_manager);
|
||||
|
||||
+97
-109
@@ -2199,8 +2199,8 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size)
|
||||
// Recorded by PartPlate::render_icons() below, when it runs.
|
||||
wxGetApp().plater()->get_partplate_list().clear_hover_tooltip();
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
// Invalidate the shadow map each frame; only the View3D path below rebuilds it. This keeps
|
||||
// the Preview / Assemble canvases from sampling a stale map with an outdated light matrix.
|
||||
// Invalidate the shadow map each frame; the View3D and Preview paths below rebuild it. This
|
||||
// keeps the Assemble canvas from sampling a stale map with an outdated light matrix.
|
||||
m_shadow_map_valid = false;
|
||||
_render_background();
|
||||
|
||||
@@ -2251,6 +2251,8 @@ void GLCanvas3D::_render_scene(const Camera& camera, const Size& cnv_size)
|
||||
_render_selection();
|
||||
_render_bed(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), m_show_world_axes);
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id);
|
||||
// Realistic view: the print casts a shadow onto the plate here as it does in View3D.
|
||||
_render_shadows(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
// BBS: GUI refactor: add canvas size as parameters
|
||||
_render_gcode(cnv_size.get_width(), cnv_size.get_height());
|
||||
}
|
||||
@@ -7644,11 +7646,20 @@ bool GLCanvas3D::_is_fxaa_enabled() const
|
||||
return wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_FXAA_ENABLED);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_realistic_view_enabled() const
|
||||
{
|
||||
const AppConfig* cfg = wxGetApp().app_config;
|
||||
if (cfg == nullptr || !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE))
|
||||
return false;
|
||||
// Prepare and Assemble follow the umbrella toggle alone; Preview needs its own opt-in.
|
||||
return m_canvas_type != ECanvasType::CanvasPreview || cfg->get_bool(SETTING_OPENGL_REALISTIC_PREVIEW);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_is_ssao_enabled() const
|
||||
{
|
||||
if (wxGetApp().app_config == nullptr)
|
||||
return false;
|
||||
return wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE) &&
|
||||
return _is_realistic_view_enabled() &&
|
||||
wxGetApp().app_config->get_bool(SETTING_OPENGL_PHONG_SSAO);
|
||||
}
|
||||
|
||||
@@ -7803,95 +7814,23 @@ void GLCanvas3D::_render_ssao_pass(unsigned int width, unsigned int 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());
|
||||
// The shader reconstructs the surface normal from the depth buffer, there being no normal
|
||||
// target to read: it unprojects a pixel back into view space, then measures the result
|
||||
// against world +Z expressed in view space to tell a top surface from a wall.
|
||||
const Matrix4d inv_projection_matrix = camera.get_projection_matrix().matrix().inverse();
|
||||
shader->set_uniform("inv_projection_matrix", inv_projection_matrix);
|
||||
const Vec3d up_view = (camera.get_view_matrix().matrix().block<3, 3>(0, 0) * Vec3d::UnitZ()).normalized();
|
||||
shader->set_uniform("up_view", up_view);
|
||||
|
||||
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_ssao_color_texture_id));
|
||||
@@ -7903,13 +7842,6 @@ void GLCanvas3D::_render_ssao_pass(unsigned int width, unsigned int height)
|
||||
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));
|
||||
@@ -8154,15 +8086,19 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform
|
||||
{
|
||||
if (wxGetApp().app_config == nullptr)
|
||||
return;
|
||||
if (!wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE))
|
||||
if (!_is_realistic_view_enabled())
|
||||
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)
|
||||
// The preview canvas holds no volumes of its own for FFF. Once slicing has run its printed
|
||||
// geometry is the G-code toolpaths, which both cast into the map here and sample it back in
|
||||
// _render_gcode; before slicing there are only shells, and nothing casts at all. View3D and
|
||||
// SLA preview use m_volumes. The shells are deliberately never casters: they are a
|
||||
// translucent ghost of the whole object, so they would drop the solid shadow of a print that
|
||||
// has not been sliced, and at any layer below the last, one that is not there yet.
|
||||
const bool toolpath_casters = m_canvas_type == ECanvasType::CanvasPreview && m_gcode_viewer.has_data();
|
||||
if (!toolpath_casters && m_volumes.empty())
|
||||
return;
|
||||
|
||||
if (OpenGLManager::get_framebuffers_type() == OpenGLManager::EFramebufferType::Arb) {
|
||||
@@ -8174,10 +8110,30 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform
|
||||
|
||||
// Bounding box of the printable objects (the shadow casters).
|
||||
BoundingBoxf3 obj_bb;
|
||||
for (const GLVolume* volume : m_volumes.volumes) {
|
||||
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
|
||||
continue;
|
||||
obj_bb.merge(volume->transformed_bounding_box());
|
||||
if (toolpath_casters) {
|
||||
// Merged corner by corner: BoundingBoxf3(min, max) marks itself undefined at zero
|
||||
// Z extent, which a single layer print gives, and the check below would then drop
|
||||
// every shadow in the frame.
|
||||
const BoundingBoxf3& paths_bb = m_gcode_viewer.get_paths_bounding_box();
|
||||
if ((paths_bb.min.array() <= paths_bb.max.array()).all()) {
|
||||
obj_bb.merge(paths_bb.min);
|
||||
obj_bb.merge(paths_bb.max);
|
||||
}
|
||||
// Only the enabled layers are drawn, so fitting the map to the whole print wastes
|
||||
// its depth range and makes contact shadows shift as the slider moves. The z = 0
|
||||
// shadow is enclosed separately below, so the plate shadow is unaffected.
|
||||
const std::vector<double> layer_zs = m_gcode_viewer.get_layers_zs();
|
||||
if (!layer_zs.empty()) {
|
||||
const size_t top = std::min<size_t>(m_gcode_viewer.get_layers_z_range()[1], layer_zs.size() - 1);
|
||||
obj_bb.max.z() = std::max(obj_bb.min.z(), std::min(obj_bb.max.z(), layer_zs[top]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const GLVolume* volume : m_volumes.volumes) {
|
||||
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
|
||||
continue;
|
||||
obj_bb.merge(volume->transformed_bounding_box());
|
||||
}
|
||||
}
|
||||
if (!obj_bb.defined)
|
||||
return; // no objects to cast shadows
|
||||
@@ -8299,16 +8255,21 @@ void GLCanvas3D::_render_shadows(const Transform3d& view_matrix, const Transform
|
||||
glsafe(::glPolygonOffset(4.0f, 4.0f));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
|
||||
shader->start_using();
|
||||
shader->set_uniform("projection_matrix", Transform3d(light_proj));
|
||||
for (GLVolume* volume : m_volumes.volumes) {
|
||||
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
|
||||
continue;
|
||||
const Transform3d view_model = Transform3d(light_view) * volume->world_matrix();
|
||||
shader->set_uniform("view_model_matrix", view_model);
|
||||
volume->model.render(shader);
|
||||
if (toolpath_casters)
|
||||
m_gcode_viewer.render_shadow_casters(Transform3d(light_view), Transform3d(light_proj), eye);
|
||||
// Only this branch draws through "flat"; the toolpaths bring their own program.
|
||||
else if (GLShaderProgram* shader = wxGetApp().get_shader("flat"); shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("projection_matrix", Transform3d(light_proj));
|
||||
for (GLVolume* volume : m_volumes.volumes) {
|
||||
if (volume == nullptr || !volume->is_active || !volume->printable || volume->is_modifier || volume->is_wipe_tower)
|
||||
continue;
|
||||
const Transform3d view_model = Transform3d(light_view) * volume->world_matrix();
|
||||
shader->set_uniform("view_model_matrix", view_model);
|
||||
volume->model.render(shader);
|
||||
}
|
||||
shader->stop_using();
|
||||
}
|
||||
shader->stop_using();
|
||||
|
||||
// Restore state
|
||||
glsafe(::glDisable(GL_POLYGON_OFFSET_FILL));
|
||||
@@ -8517,7 +8478,7 @@ void GLCanvas3D::_render_objects(GLVolumeCollection::ERenderType type, bool with
|
||||
return;
|
||||
}
|
||||
|
||||
const bool realistic_mode = wxGetApp().app_config != nullptr && wxGetApp().app_config->get_bool(SETTING_OPENGL_REALISTIC_MODE);
|
||||
const bool realistic_mode = _is_realistic_view_enabled();
|
||||
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);
|
||||
@@ -8741,7 +8702,34 @@ void GLCanvas3D::_render_wireframe_overlay()
|
||||
//BBS: GUI refactor: add canvas size as parameters
|
||||
void GLCanvas3D::_render_gcode(int canvas_width, int canvas_height)
|
||||
{
|
||||
// Realistic view: the toolpaths receive the same depth map they were rendered into by
|
||||
// _render_shadows, which is what gives them object-on-object and self shadows. Intensity 0
|
||||
// short-circuits the lookup in the shader, so this is inert whenever the map is missing.
|
||||
const bool receive_shadows = m_shadow_map_valid && m_shadow_map_texture_id != 0 && m_shadow_map_size != 0;
|
||||
if (receive_shadows) {
|
||||
glsafe(::glActiveTexture(GL_TEXTURE4));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_shadow_map_texture_id));
|
||||
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||
m_gcode_viewer.set_shadow_map(4, m_shadow_light_vp, 0.35f, 1.0f / static_cast<float>(m_shadow_map_size));
|
||||
}
|
||||
else
|
||||
m_gcode_viewer.set_shadow_map(4, Transform3d::Identity(), 0.0f, 0.0f);
|
||||
|
||||
// The lighting term leaves the print dimmer and duller than the legend colours. Saturation
|
||||
// pays back the duller half in both modes; brightness only where something takes light off
|
||||
// again - realistic view with at least one lossy pass on - else the lift would just clip.
|
||||
const AppConfig* cfg = wxGetApp().app_config;
|
||||
const bool lossy_passes = cfg != nullptr && _is_realistic_view_enabled() &&
|
||||
(cfg->get_bool(SETTING_OPENGL_PHONG_BASIC_PLATE_SHADOWS) || cfg->get_bool(SETTING_OPENGL_PHONG_SSAO));
|
||||
m_gcode_viewer.set_tone(lossy_passes ? 1.1f : 1.0f, 1.15f);
|
||||
|
||||
m_gcode_viewer.render_scene(canvas_width, canvas_height);
|
||||
|
||||
if (receive_shadows) {
|
||||
glsafe(::glActiveTexture(GL_TEXTURE4));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
glsafe(::glActiveTexture(GL_TEXTURE0));
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_gcode_overlay(int canvas_width, int canvas_height)
|
||||
@@ -9831,7 +9819,7 @@ void GLCanvas3D::_render_canvas_toolbar()
|
||||
);
|
||||
|
||||
create_menu_item( _utf8(L("Realistic View")),
|
||||
m_canvas_type != ECanvasType::CanvasPreview, // not work on preview
|
||||
true, // work on all
|
||||
cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE),
|
||||
[&cfg]{
|
||||
cfg->set_bool(SETTING_OPENGL_REALISTIC_MODE, !cfg->get_bool(SETTING_OPENGL_REALISTIC_MODE));
|
||||
|
||||
@@ -1324,6 +1324,7 @@ private:
|
||||
void _picking_pass();
|
||||
void _rectangular_selection_picking_pass();
|
||||
bool _is_fxaa_enabled() const;
|
||||
bool _is_realistic_view_enabled() const;
|
||||
bool _is_ssao_enabled() const;
|
||||
int _get_effective_fps_cap() const;
|
||||
bool _is_fps_overlay_enabled() const;
|
||||
|
||||
@@ -1932,6 +1932,15 @@ void PreferencesDialog::create_items()
|
||||
);
|
||||
g_sizer->Add(item_realistic_phong);
|
||||
|
||||
auto item_realistic_preview = create_item_checkbox(
|
||||
_L("Enable in Preview"),
|
||||
_L("Also applies realistic view to the Preview canvas, not just Prepare.\n"
|
||||
"Preview draws the full toolpath geometry, so shadows and SSAO cost considerably"
|
||||
" more there than on a plain model."),
|
||||
SETTING_OPENGL_REALISTIC_PREVIEW
|
||||
);
|
||||
g_sizer->Add(item_realistic_preview);
|
||||
|
||||
auto item_realistic_ssao = create_item_checkbox(
|
||||
_L("SSAO ambient occlusion"),
|
||||
_L("Applies SSAO in realistic view."),
|
||||
|
||||
Reference in New Issue
Block a user