Faster Preview View (#15884)

Co-authored-by: Kris Austin <kris.austin@gmail.com>
This commit is contained in:
Ian Bassi
2026-10-02 14:45:58 -03:00
committed by GitHub
co-authored by Kris Austin
parent 4ffba13210
commit 70bc02467b
37 changed files with 1740 additions and 290 deletions
+2
View File
@@ -37,6 +37,8 @@ static constexpr float MAX_WIPES_RADIUS_MM = 1.0f;
// Used for positions, displacements and so on.
//
using Vec3 = std::array<float, 3>;
// ORCA: the per vertex data uploaded as GL_RGBA32F, see extract_pos_and_or_hwa().
using Vec4 = std::array<float, 4>;
//
// 4x4 square matrix with elements in column-major order:
+4
View File
@@ -80,6 +80,10 @@ public:
// ORCA: section view. Cuts away where dot(plane, (x, y, z, 1)) < 0; { 0, 0, 0, 1 } keeps all.
//
void set_clipping_plane(const std::array<float, 4>& plane);
//
// ORCA: direction to the top light in eye space, shading the toolpaths and biasing their shadow lookup.
//
void set_light_top_dir(const Vec3& direction);
//
// ************************************************************************
+86 -24
View File
@@ -14,7 +14,7 @@ static const char* Segments_Vertex_Shader =
"#version 150\n"
"#define POINTY_CAPS\n"
"#define FIX_TWISTING\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"uniform vec3 light_top_dir;\n"
"const float light_top_diffuse = 0.6 * 0.8;\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"
@@ -31,13 +31,9 @@ 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"
// draw the instances last to first, top layers before the ones they hide, so that early depth
// rejection discards most of the hidden fragments; set when the camera looks down on the print
"uniform int reverse_order;\n"
"uniform int instance_count;\n"
// ORCA: draw last segment first, so looking down the top layers hide the rest from the fragment shader.
"uniform bool reverse_order;\n"
"uniform int instances_count;\n"
// ORCA: section view
"uniform vec4 clipping_plane;\n"
"in int vertex_id;\n"
@@ -53,13 +49,22 @@ static const char* Segments_Vertex_Shader =
// ORCA: section view - the segment and the light on its cut face
"flat out int segment_id;\n"
"out vec3 cut_color_direct;\n"
"vec3 decode_color(float color) {\n"
// ORCA: the layers greyed or dimmed around the one the sliders show, see ViewerImpl::set_layer_colors().
"uniform ivec2 lit_layers;\n"
"uniform int grey_below_layer;\n"
"uniform float dim_brightness;\n"
"uniform int kept_vertex;\n"
"vec3 decode_color(float color, int id, int layer) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n"
" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n"
" if (dim_brightness >= 0.0)\n"
" rgb = floor(rgb * dim_brightness);\n"
" else if (layer < grey_below_layer)\n"
" rgb = vec3(64.0);\n"
" }\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
" return f * rgb;\n"
"}\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"
@@ -68,7 +73,7 @@ static const char* Segments_Vertex_Shader =
" return top_diffuse + front_diffuse + top_specular;\n"
"}\n"
"void main() {\n"
" int instance = (reverse_order != 0) ? instance_count - 1 - gl_InstanceID : gl_InstanceID;\n"
" int instance = reverse_order ? instances_count - 1 - gl_InstanceID : gl_InstanceID;\n"
" int id_a = int(texelFetch(segment_index_tex, instance).r);\n"
" int id_b = id_a + 1;\n"
" vec3 pos_a = texelFetch(position_tex, id_a).xyz;\n"
@@ -157,9 +162,9 @@ 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 * bias_scale;\n"
" eye_position.z += bias;\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"
" vec3 color_base = decode_color(texelFetch(color_tex, id).r, id, int(texelFetch(position_tex, id).w));\n"
" color = color_base * (ambient + emission);\n"
" color_direct = color_base * direct_lighting(eye_position, eye_normal);\n"
" world_position = pos;\n"
@@ -170,12 +175,60 @@ static const char* Segments_Vertex_Shader =
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
// ORCA: realistic view - shadow caster, one light facing ribbon per segment, not instanced as tiny instances are slow.
static const char* Segments_Shadow_Caster_Vertex_Shader =
"#version 150\n"
"const vec3 UP = vec3(0, 0, 1);\n"
"const int CORNERS[6] = int[](0, 1, 2, 0, 2, 3);\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform samplerBuffer position_tex;\n"
"uniform samplerBuffer height_width_angle_tex;\n"
"uniform usamplerBuffer segment_index_tex;\n"
"uniform bool reverse_order;\n"
"uniform int instances_count;\n"
"out vec3 world_position;\n"
"void main() {\n"
" int segment = gl_VertexID / 6;\n"
" int corner = CORNERS[gl_VertexID - 6 * segment];\n"
" int instance = reverse_order ? instances_count - 1 - segment : segment;\n"
" int id_a = int(texelFetch(segment_index_tex, instance).r);\n"
" int id = corner < 2 ? id_a : id_a + 1;\n"
" vec3 pos_a = texelFetch(position_tex, id_a).xyz;\n"
" vec3 pos_b = texelFetch(position_tex, id_a + 1).xyz;\n"
" vec3 line = pos_b - pos_a;\n"
" float line_len = length(line);\n"
" vec3 line_dir = line_len < 1e-4 ? vec3(1.0, 0.0, 0.0) : line / line_len;\n"
" vec3 line_right_dir = abs(dot(line_dir, UP)) > 0.9 ? normalize(cross(vec3(1, 0, 0), line_dir)) : normalize(cross(line_dir, UP));\n"
" vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));\n"
" vec3 to_light = vec3(view_matrix[0][2], view_matrix[1][2], view_matrix[2][2]);\n"
" vec3 side_dir = cross(to_light, line_dir);\n"
" side_dir = dot(side_dir, side_dir) < 1e-8 ? line_right_dir : normalize(side_dir);\n"
" vec2 height_width = texelFetch(height_width_angle_tex, id).xy;\n"
" float half_extent = 0.5 * (height_width.y * abs(dot(line_right_dir, side_dir)) + height_width.x * abs(dot(line_up_dir, side_dir)));\n"
" float along = (corner < 2 ? -0.5 : 0.5) * height_width.y;\n"
" float side = (corner == 0 || corner == 3) ? -1.0 : 1.0;\n"
" vec3 pos = (corner < 2 ? pos_a : pos_b) + along * line_dir + side * half_extent * side_dir;\n"
" world_position = pos;\n"
" gl_Position = projection_matrix * (view_matrix * vec4(pos, 1.0));\n"
"}\n";
// ORCA: realistic view - the shadow caster writes depth only. What a section cuts away casts no shadow.
static const char* Segments_Shadow_Caster_Fragment_Shader =
"#version 150\n"
"uniform vec4 clipping_plane;\n"
"in vec3 world_position;\n"
"void main() {\n"
" if (dot(vec4(world_position, 1.0), clipping_plane) < 0.0)\n"
" discard;\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 vec3 light_top_dir;\n"
"uniform sampler2D shadow_map;\n"
"uniform mat4 shadow_light_vp;\n"
"uniform float shadow_intensity;\n"
@@ -212,7 +265,7 @@ static const char* Segments_Fragment_Shader =
" 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(normal), SHADOW_LIGHT_DIR);\n"
" float NdotL = dot(normalize(normal), light_top_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"
@@ -289,13 +342,22 @@ static const char* Options_Vertex_Shader =
"in vec3 in_normal;\n"
"out vec3 color;\n"
"out float clipping_plane_dot;\n"
"vec3 decode_color(float color) {\n"
// ORCA: as in Segments_Vertex_Shader.
"uniform ivec2 lit_layers;\n"
"uniform int grey_below_layer;\n"
"uniform float dim_brightness;\n"
"uniform int kept_vertex;\n"
"vec3 decode_color(float color, int id, int layer) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n"
" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n"
" if (dim_brightness >= 0.0)\n"
" rgb = floor(rgb * dim_brightness);\n"
" else if (layer < grey_below_layer)\n"
" rgb = vec3(64.0);\n"
" }\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
" return f * rgb;\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
@@ -321,7 +383,7 @@ static const char* Options_Vertex_Shader =
" // ORCA: Apply bias to z-position to avoid z-fighting\n"
" eye_position.z += bias;\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, id).r);\n"
" vec3 color_base = decode_color(texelFetch(color_tex, id).r, id, int(texelFetch(position_tex, id).w));\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
+96 -16
View File
@@ -15,7 +15,7 @@ static const char* Segments_Vertex_Shader_ES =
"precision lowp usampler2D;\n"
"#define POINTY_CAPS\n"
"#define FIX_TWISTING\n"
"const vec3 light_top_dir = vec3(-0.4574957, 0.4574957, 0.7624929);\n"
"uniform vec3 light_top_dir;\n"
"const float light_top_diffuse = 0.6 * 0.8;\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"
@@ -32,6 +32,9 @@ static const char* Segments_Vertex_Shader_ES =
"uniform sampler2D height_width_angle_tex;\n"
"uniform sampler2D color_tex;\n"
"uniform usampler2D segment_index_tex;\n"
// ORCA: draw last segment first, so looking down the top layers hide the rest from the fragment shader.
"uniform bool reverse_order;\n"
"uniform int instances_count;\n"
// ORCA: section view
"uniform vec4 clipping_plane;\n"
"in float vertex_id_float;\n"
@@ -47,13 +50,22 @@ static const char* Segments_Vertex_Shader_ES =
// ORCA: section view - the segment and the light on its cut face
"flat out int segment_id;\n"
"out vec3 cut_color_direct;\n"
"vec3 decode_color(float color) {\n"
// ORCA: the layers greyed or dimmed around the one the sliders show, see ViewerImpl::set_layer_colors().
"uniform ivec2 lit_layers;\n"
"uniform int grey_below_layer;\n"
"uniform float dim_brightness;\n"
"uniform int kept_vertex;\n"
"vec3 decode_color(float color, int id, int layer) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n"
" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n"
" if (dim_brightness >= 0.0)\n"
" rgb = floor(rgb * dim_brightness);\n"
" else if (layer < grey_below_layer)\n"
" rgb = vec3(64.0);\n"
" }\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
" return f * rgb;\n"
"}\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"
@@ -71,7 +83,8 @@ static const char* Segments_Vertex_Shader_ES =
"}\n"
"void main() {\n"
" int vertex_id = int(vertex_id_float);\n"
" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, gl_InstanceID), 0).r);\n"
" int instance = reverse_order ? instances_count - 1 - gl_InstanceID : gl_InstanceID;\n"
" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, instance), 0).r);\n"
" int id_b = id_a + 1;\n"
" vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;\n"
" vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_b), 0).xyz;\n"
@@ -156,7 +169,7 @@ static const char* Segments_Vertex_Shader_ES =
" }\n"
" 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"
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r, id, int(texelFetch(position_tex, tex_coord(position_tex, id), 0).w));\n"
" color = color_base * (ambient + emission);\n"
" color_direct = color_base * direct_lighting(eye_position, eye_normal);\n"
" world_position = pos;\n"
@@ -167,6 +180,64 @@ static const char* Segments_Vertex_Shader_ES =
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
// ORCA: realistic view - shadow caster, one light facing ribbon per segment, not instanced as tiny instances are slow.
static const char* Segments_Shadow_Caster_Vertex_Shader_ES =
"#version 300 es\n"
"precision lowp usampler2D;\n"
"const vec3 UP = vec3(0, 0, 1);\n"
"const int CORNERS[6] = int[](0, 1, 2, 0, 2, 3);\n"
"uniform mat4 view_matrix;\n"
"uniform mat4 projection_matrix;\n"
"uniform sampler2D position_tex;\n"
"uniform sampler2D height_width_angle_tex;\n"
"uniform usampler2D segment_index_tex;\n"
"uniform bool reverse_order;\n"
"uniform int instances_count;\n"
"out vec3 world_position;\n"
"ivec2 tex_coord(sampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n"
"}\n"
"ivec2 tex_coord_u(usampler2D sampler, int id) {\n"
" ivec2 tex_size = textureSize(sampler, 0);\n"
" return (tex_size.y == 1) ? ivec2(id, 0) : ivec2(id % tex_size.x, id / tex_size.x);\n"
"}\n"
"void main() {\n"
" int segment = gl_VertexID / 6;\n"
" int corner = CORNERS[gl_VertexID - 6 * segment];\n"
" int instance = reverse_order ? instances_count - 1 - segment : segment;\n"
" int id_a = int(texelFetch(segment_index_tex, tex_coord_u(segment_index_tex, instance), 0).r);\n"
" int id = corner < 2 ? id_a : id_a + 1;\n"
" vec3 pos_a = texelFetch(position_tex, tex_coord(position_tex, id_a), 0).xyz;\n"
" vec3 pos_b = texelFetch(position_tex, tex_coord(position_tex, id_a + 1), 0).xyz;\n"
" vec3 line = pos_b - pos_a;\n"
" float line_len = length(line);\n"
" vec3 line_dir = line_len < 1e-4 ? vec3(1.0, 0.0, 0.0) : line / line_len;\n"
" vec3 line_right_dir = abs(dot(line_dir, UP)) > 0.9 ? normalize(cross(vec3(1, 0, 0), line_dir)) : normalize(cross(line_dir, UP));\n"
" vec3 line_up_dir = normalize(cross(line_right_dir, line_dir));\n"
" vec3 to_light = vec3(view_matrix[0][2], view_matrix[1][2], view_matrix[2][2]);\n"
" vec3 side_dir = cross(to_light, line_dir);\n"
" side_dir = dot(side_dir, side_dir) < 1e-8 ? line_right_dir : normalize(side_dir);\n"
" vec2 height_width = texelFetch(height_width_angle_tex, tex_coord(height_width_angle_tex, id), 0).xy;\n"
" float half_extent = 0.5 * (height_width.y * abs(dot(line_right_dir, side_dir)) + height_width.x * abs(dot(line_up_dir, side_dir)));\n"
" float along = (corner < 2 ? -0.5 : 0.5) * height_width.y;\n"
" float side = (corner == 0 || corner == 3) ? -1.0 : 1.0;\n"
" vec3 pos = (corner < 2 ? pos_a : pos_b) + along * line_dir + side * half_extent * side_dir;\n"
" world_position = pos;\n"
" gl_Position = projection_matrix * (view_matrix * vec4(pos, 1.0));\n"
"}\n";
// ORCA: realistic view - the shadow caster writes depth only. What a section cuts away casts no shadow.
static const char* Segments_Shadow_Caster_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
"uniform vec4 clipping_plane;\n"
"in vec3 world_position;\n"
"void main() {\n"
" if (dot(vec4(world_position, 1.0), clipping_plane) < 0.0)\n"
" discard;\n"
"}\n";
static const char* Segments_Fragment_Shader_ES =
"#version 300 es\n"
"precision highp float;\n"
@@ -178,7 +249,7 @@ static const char* Segments_Fragment_Shader_ES =
"// 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 vec3 light_top_dir;\n"
"uniform sampler2D shadow_map;\n"
"uniform mat4 shadow_light_vp;\n"
"uniform float shadow_intensity;\n"
@@ -215,7 +286,7 @@ static const char* Segments_Fragment_Shader_ES =
" 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(normal), SHADOW_LIGHT_DIR);\n"
" float NdotL = dot(normalize(normal), light_top_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"
@@ -291,13 +362,22 @@ static const char* Options_Vertex_Shader_ES =
"in vec3 in_normal;\n"
"out vec3 color;\n"
"out float clipping_plane_dot;\n"
"vec3 decode_color(float color) {\n"
// ORCA: the layers greyed or dimmed around the one the sliders show, see ViewerImpl::set_layer_colors().
"uniform ivec2 lit_layers;\n"
"uniform int grey_below_layer;\n"
"uniform float dim_brightness;\n"
"uniform int kept_vertex;\n"
"vec3 decode_color(float color, int id, int layer) {\n"
" int c = int(round(color));\n"
" int r = (c >> 16) & 0xFF;\n"
" int g = (c >> 8) & 0xFF;\n"
" int b = (c >> 0) & 0xFF;\n"
" vec3 rgb = vec3((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);\n"
" if (id != kept_vertex && layer != lit_layers.x && layer != lit_layers.y) {\n"
" if (dim_brightness >= 0.0)\n"
" rgb = floor(rgb * dim_brightness);\n"
" else if (layer < grey_below_layer)\n"
" rgb = vec3(64.0);\n"
" }\n"
" float f = 1.0 / 255.0f;\n"
" return f * vec3(r, g, b);\n"
" return f * rgb;\n"
"}\n"
"float lighting(vec3 eye_position, vec3 eye_normal) {\n"
" float top_diffuse = light_top_diffuse * max(dot(eye_normal, light_top_dir), 0.0);\n"
@@ -326,7 +406,7 @@ static const char* Options_Vertex_Shader_ES =
" clipping_plane_dot = dot(vec4(offset, 1.0), clipping_plane);\n"
" vec3 eye_position = (view_matrix * vec4(scale_matrix * in_position + offset, 1.0)).xyz;\n"
" vec3 eye_normal = (view_matrix * vec4(in_normal, 0.0)).xyz;\n"
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r);\n"
" vec3 color_base = decode_color(texelFetch(color_tex, tex_coord(color_tex, id), 0).r, id, int(texelFetch(position_tex, tex_coord(position_tex, id), 0).w));\n"
" color = color_base * lighting(eye_position, eye_normal);\n"
" gl_Position = projection_matrix * vec4(eye_position, 1.0);\n"
"}\n";
+5
View File
@@ -52,6 +52,11 @@ void Viewer::set_shadow_map(int texture_unit, const Mat4x4& light_view_projectio
m_impl->set_shadow_map(texture_unit, light_view_projection, intensity, texel_size);
}
void Viewer::set_light_top_dir(const Vec3& direction)
{
m_impl->set_light_top_dir(direction);
}
void Viewer::set_tone(float exposure, float saturation)
{
m_impl->set_tone(exposure, saturation);
+159 -131
View File
@@ -349,7 +349,7 @@ void ViewerImpl::TextureData::init(size_t vertices_count)
m_tex_ids = std::vector<TexIds>(m_count);
}
void ViewerImpl::TextureData::set_positions(const std::vector<Vec3>& positions)
void ViewerImpl::TextureData::set_positions(const std::vector<Vec4>& positions)
{
if (m_count == 0)
return;
@@ -383,17 +383,17 @@ void ViewerImpl::TextureData::set_positions(const std::vector<Vec3>& positions)
glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
if (remaining >= tex_capacity) {
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGB, GL_FLOAT, &positions[offset]));
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGBA, GL_FLOAT, &positions[offset]));
m_tex_ids[i].positions.second = w * h;
}
else {
// the last row is only partially fitted with data, send it separately
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGB, GL_FLOAT, nullptr));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h - 1), GL_RGB, GL_FLOAT, &positions[offset]));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast<GLsizei>(h - 1), static_cast<GLsizei>(remaining % w), 1, GL_RGB, GL_FLOAT, &positions[offset + w * (h - 1)]));
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGBA, GL_FLOAT, nullptr));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h - 1), GL_RGBA, GL_FLOAT, &positions[offset]));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast<GLsizei>(h - 1), static_cast<GLsizei>(remaining % w), 1, GL_RGBA, GL_FLOAT, &positions[offset + w * (h - 1)]));
m_tex_ids[i].positions.second = w * (h - 1) + remaining % w;
}
m_positions_size += m_tex_ids[i].positions.second * sizeof(Vec3);
m_positions_size += m_tex_ids[i].positions.second * sizeof(Vec4);
remaining = (remaining > tex_capacity) ? remaining - tex_capacity: 0;
}
@@ -402,7 +402,7 @@ void ViewerImpl::TextureData::set_positions(const std::vector<Vec3>& positions)
glsafe(glPixelStorei(GL_UNPACK_ALIGNMENT, curr_unpack_alignment));
}
void ViewerImpl::TextureData::set_heights_widths_angles(const std::vector<Vec3>& heights_widths_angles)
void ViewerImpl::TextureData::set_heights_widths_angles(const std::vector<Vec4>& heights_widths_angles)
{
if (m_count == 0)
return;
@@ -436,17 +436,17 @@ void ViewerImpl::TextureData::set_heights_widths_angles(const std::vector<Vec3>&
glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
glsafe(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
if (remaining >= tex_capacity) {
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGB, GL_FLOAT, &heights_widths_angles[offset]));
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGBA, GL_FLOAT, &heights_widths_angles[offset]));
m_tex_ids[i].heights_widths_angles.second = w * h;
}
else {
// the last row is only partially fitted with data, send it separately
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGB, GL_FLOAT, nullptr));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h - 1), GL_RGB, GL_FLOAT, &heights_widths_angles[offset]));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast<GLsizei>(h - 1), static_cast<GLsizei>(remaining % w), 1, GL_RGB, GL_FLOAT, &heights_widths_angles[offset + w * (h - 1)]));
glsafe(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, static_cast<GLsizei>(w), static_cast<GLsizei>(h), 0, GL_RGBA, GL_FLOAT, nullptr));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h - 1), GL_RGBA, GL_FLOAT, &heights_widths_angles[offset]));
glsafe(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, static_cast<GLsizei>(h - 1), static_cast<GLsizei>(remaining % w), 1, GL_RGBA, GL_FLOAT, &heights_widths_angles[offset + w * (h - 1)]));
m_tex_ids[i].heights_widths_angles.second = w * (h - 1) + remaining % w;
}
m_height_width_angle_size += m_tex_ids[i].heights_widths_angles.second * sizeof(Vec3);
m_height_width_angle_size += m_tex_ids[i].heights_widths_angles.second * sizeof(Vec4);
remaining = (remaining > tex_capacity) ? remaining - tex_capacity : 0;
}
@@ -732,6 +732,21 @@ ViewerImpl::ViewerImpl()
reset_default_options_colors();
}
void ViewerImpl::SegmentsUniforms::init(unsigned int shader_id)
{
view_matrix = glGetUniformLocation(shader_id, "view_matrix");
projection_matrix = glGetUniformLocation(shader_id, "projection_matrix");
camera_position = glGetUniformLocation(shader_id, "camera_position");
positions_tex = glGetUniformLocation(shader_id, "position_tex");
height_width_angle_tex = glGetUniformLocation(shader_id, "height_width_angle_tex");
colors_tex = glGetUniformLocation(shader_id, "color_tex");
segment_index_tex = glGetUniformLocation(shader_id, "segment_index_tex");
reverse_order = glGetUniformLocation(shader_id, "reverse_order");
instances_count = glGetUniformLocation(shader_id, "instances_count");
// ORCA: section view
clipping_plane = glGetUniformLocation(shader_id, "clipping_plane");
}
void ViewerImpl::init(const std::string& opengl_context_version)
{
if (m_initialized)
@@ -756,15 +771,7 @@ void ViewerImpl::init(const std::string& opengl_context_version)
m_segments_shader_id = init_shader("segments", Segments_Vertex_Shader, Segments_Fragment_Shader);
#endif // ENABLE_OPENGL_ES
m_uni_segments_view_matrix_id = glGetUniformLocation(m_segments_shader_id, "view_matrix");
m_uni_segments_projection_matrix_id = glGetUniformLocation(m_segments_shader_id, "projection_matrix");
m_uni_segments_camera_position_id = glGetUniformLocation(m_segments_shader_id, "camera_position");
m_uni_segments_positions_tex_id = glGetUniformLocation(m_segments_shader_id, "position_tex");
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");
m_uni_segments_reverse_order_id = glGetUniformLocation(m_segments_shader_id, "reverse_order");
m_uni_segments_instance_count_id = glGetUniformLocation(m_segments_shader_id, "instance_count");
m_uni_segments.init(m_segments_shader_id);
// 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");
@@ -772,17 +779,29 @@ void ViewerImpl::init(const std::string& opengl_context_version)
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");
// ORCA: section view
m_uni_segments_clipping_plane_id = glGetUniformLocation(m_segments_shader_id, "clipping_plane");
m_uni_segments_light_top_dir_id = glGetUniformLocation(m_segments_shader_id, "light_top_dir");
m_uni_segments_layer_colors.init(m_segments_shader_id);
glcheck();
assert(m_uni_segments.view_matrix != -1 &&
m_uni_segments.projection_matrix != -1 &&
m_uni_segments.camera_position != -1 &&
m_uni_segments.positions_tex != -1 &&
m_uni_segments.height_width_angle_tex != -1 &&
m_uni_segments.colors_tex != -1 &&
m_uni_segments.segment_index_tex != -1 &&
m_uni_segments.reverse_order != -1 &&
m_uni_segments.instances_count != -1);
// ORCA: realistic view
#ifdef ENABLE_OPENGL_ES
m_segments_caster_shader_id = init_shader("segments_shadow_caster", Segments_Shadow_Caster_Vertex_Shader_ES, Segments_Shadow_Caster_Fragment_Shader_ES);
#else
m_segments_caster_shader_id = init_shader("segments_shadow_caster", Segments_Shadow_Caster_Vertex_Shader, Segments_Shadow_Caster_Fragment_Shader);
#endif // ENABLE_OPENGL_ES
m_uni_segments_caster.init(m_segments_caster_shader_id);
// The caster pulls its vertices from gl_VertexID, but a core profile needs a vertex array bound to draw.
glsafe(glGenVertexArrays(1, &m_segments_caster_vao_id));
glcheck();
assert(m_uni_segments_view_matrix_id != -1 &&
m_uni_segments_projection_matrix_id != -1 &&
m_uni_segments_camera_position_id != -1 &&
m_uni_segments_positions_tex_id != -1 &&
m_uni_segments_height_width_angle_tex_id != -1 &&
m_uni_segments_colors_tex_id != -1 &&
m_uni_segments_segment_index_tex_id != -1);
m_segment_template.init();
@@ -801,6 +820,7 @@ void ViewerImpl::init(const std::string& opengl_context_version)
m_uni_options_segment_index_tex_id = glGetUniformLocation(m_options_shader_id, "segment_index_tex");
// ORCA: section view
m_uni_options_clipping_plane_id = glGetUniformLocation(m_options_shader_id, "clipping_plane");
m_uni_options_layer_colors.init(m_options_shader_id);
glcheck();
assert(m_uni_options_view_matrix_id != -1 &&
m_uni_options_projection_matrix_id != -1 &&
@@ -874,6 +894,14 @@ void ViewerImpl::shutdown()
glsafe(glDeleteProgram(m_segments_shader_id));
m_segments_shader_id = 0;
}
if (m_segments_caster_shader_id != 0) {
glsafe(glDeleteProgram(m_segments_caster_shader_id));
m_segments_caster_shader_id = 0;
}
if (m_segments_caster_vao_id != 0) {
glsafe(glDeleteVertexArrays(1, &m_segments_caster_vao_id));
m_segments_caster_vao_id = 0;
}
m_initialized = false;
OpenGLWrapper::unload_opengl();
}
@@ -894,7 +922,7 @@ void ViewerImpl::reset()
for (std::vector<float>& times : m_layer_start_times)
std::vector<float>().swap(times);
std::vector<uint32_t>().swap(m_layer_first_vertex);
std::vector<float>().swap(m_colors_scratch);
m_layers_in_vertex_order = false;
m_valid_lines_bitset.clear();
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
m_cog_marker.reset();
@@ -924,9 +952,8 @@ void ViewerImpl::reset()
// On some graphic cards texture buffers using GL_RGB32F format do not work, see:
// https://dev.prusa3d.com/browse/SPE-2411
// https://github.com/prusa3d/PrusaSlicer/issues/12908
// To let all drivers be happy, we use GL_RGBA32F format, so we need to add an extra (currently unused) float
// To let all drivers be happy, we use GL_RGBA32F format, so we need to add an extra float
// to position and heights_widths_angles vectors
using Vec4 = std::array<float, 4>;
static void extract_pos_and_or_hwa(const std::vector<PathVertex>& vertices, float travels_radius, float wipes_radius, BitSet<>& valid_lines_bitset,
std::vector<Vec4>* positions = nullptr, std::vector<Vec4>* heights_widths_angles = nullptr, bool update_bitset = false) {
@@ -963,8 +990,8 @@ static void extract_pos_and_or_hwa(const std::vector<PathVertex>& vertices, floa
}
if (positions != nullptr) {
// the last component is a dummy float to comply with GL_RGBA32F format
Vec4 position = { v.position[0], v.position[1], v.position[2], 0.0f };
// ORCA: the last component, there to comply with GL_RGBA32F format, carries the layer the shaders grey and dim by
Vec4 position = { v.position[0], v.position[1], v.position[2], static_cast<float>(v.layer_id) };
if (move_type == EMoveType::Extrude)
// push down extrusion vertices by half height to render them at the right z
position[2] -= 0.5f * v.height;
@@ -1080,6 +1107,8 @@ void ViewerImpl::load(GCodeInputData&& gcode_data)
}
for (size_t i = m_layer_first_vertex.size() - 1; i > 0; --i)
m_layer_first_vertex[i - 1] = std::min(m_layer_first_vertex[i - 1], m_layer_first_vertex[i]);
m_layers_in_vertex_order = std::is_sorted(m_vertices.begin(), m_vertices.end(),
[](const PathVertex& a, const PathVertex& b) { return a.layer_id < b.layer_id; });
// the running time at each layer's first vertex, summed in vertex order so that
// get_estimated_time_at() matches a full accumulation exactly
@@ -1274,17 +1303,6 @@ static float encode_color(const Color& color) {
return static_cast<float>(i_color);
}
// ORCA: returns the encoded color scaled towards black by 'brightness', preserving its hue.
// 1.0 = no change, 0.0 = black.
static float encode_color_dimmed(const Color& color, float brightness) {
const int r = static_cast<int>(color[0] * brightness);
const int g = static_cast<int>(color[1] * brightness);
const int b = static_cast<int>(color[2] * brightness);
const int i_color = r << 16 | g << 8 | b;
return static_cast<float>(i_color);
}
void ViewerImpl::update_colors_texture()
{
#if !defined(ENABLE_OPENGL_ES)
@@ -1292,6 +1310,32 @@ void ViewerImpl::update_colors_texture()
return;
#endif // ENABLE_OPENGL_ES
// ORCA: the colors of the vertices alone; the layers greyed or dimmed around the one the sliders
// show are left to the shaders, see set_layer_colors(), so that a slider step uploads nothing.
#ifdef ENABLE_OPENGL_ES
if (!m_vertices_colors.empty())
// update gpu buffer for colors
m_texture_data.set_colors(m_vertices_colors);
#else
m_colors_tex_size = m_vertices_colors.size() * sizeof(float);
// update gpu buffer for colors
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_colors_buf_id));
glsafe(glBufferData(GL_TEXTURE_BUFFER, m_vertices_colors.size() * sizeof(float), m_vertices_colors.data(), GL_STATIC_DRAW));
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0));
#endif // ENABLE_OPENGL_ES
}
void ViewerImpl::LayerColorsUniforms::init(unsigned int shader_id)
{
lit_layers = glGetUniformLocation(shader_id, "lit_layers");
grey_below_layer = glGetUniformLocation(shader_id, "grey_below_layer");
dim_brightness = glGetUniformLocation(shader_id, "dim_brightness");
kept_vertex = glGetUniformLocation(shader_id, "kept_vertex");
}
void ViewerImpl::set_layer_colors(const LayerColorsUniforms& uni) const
{
const size_t top_layer_id = m_settings.top_layer_only_view_range ? m_layers.get_view_range()[1] : 0;
const bool color_top_layer_only = m_view_range.get_full()[1] != m_view_range.get_visible()[1];
@@ -1310,43 +1354,15 @@ void ViewerImpl::update_colors_texture()
const bool dim_previous_layers = m_settings.dim_previous_layers && m_settings.top_layer_only_view_range &&
!m_layers.empty() && (inspecting_top_layer || inspecting_bottom_layer);
// Based on current settings and slider position, we might want to render some
// vertices as dark grey (or darkened, see above). Use either that or the normal color (from the cache).
// Reused across calls: this runs on every slider tick, and the allocation alone is
// 4 bytes per vertex of the whole print each time.
std::vector<float>& colors = m_colors_scratch;
colors.resize(m_vertices_colors.size());
assert(colors.size() == m_vertices.size() && m_vertices_colors.size() == m_vertices.size());
for (size_t i=0; i<m_vertices.size(); ++i) {
const PathVertex& v = m_vertices[i];
const bool keep_spiral_seam = m_settings.spiral_vase_mode && i == m_view_range.get_enabled()[0];
// ORCA: layers kept at full brightness by the dimming above are excluded from the greying below too
const bool inspected_layer = dim_previous_layers &&
((inspecting_top_layer && v.layer_id == layers_range[1]) ||
(inspecting_bottom_layer && v.layer_id == layers_range[0]));
if (dim_previous_layers && !inspected_layer && !keep_spiral_seam)
colors[i] = encode_color_dimmed(get_vertex_color(v), m_settings.dim_previous_layers_brightness);
else if (!inspected_layer && color_top_layer_only && v.layer_id < top_layer_id && !keep_spiral_seam)
colors[i] = encode_color(DUMMY_COLOR);
else
colors[i] = m_vertices_colors[i];
}
#ifdef ENABLE_OPENGL_ES
if (!colors.empty())
// update gpu buffer for colors
m_texture_data.set_colors(colors);
#else
m_colors_tex_size = colors.size() * sizeof(float);
// update gpu buffer for colors
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_colors_buf_id));
glsafe(glBufferData(GL_TEXTURE_BUFFER, colors.size() * sizeof(float), colors.data(), GL_STATIC_DRAW));
glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0));
#endif // ENABLE_OPENGL_ES
// Without dimming, the layers below the top one go dark grey while the moves slider is short of
// the end. Neither touches the inspected layers, nor the first vertex of a spiral vase layer.
glsafe(glUniform2i(uni.lit_layers, dim_previous_layers && inspecting_bottom_layer ? static_cast<int>(layers_range[0]) : -1,
dim_previous_layers && inspecting_top_layer ? static_cast<int>(layers_range[1]) : -1));
glsafe(glUniform1i(uni.grey_below_layer, color_top_layer_only ? static_cast<int>(top_layer_id) : 0));
glsafe(glUniform1f(uni.dim_brightness, dim_previous_layers ? m_settings.dim_previous_layers_brightness : -1.0f));
glsafe(glUniform1i(uni.kept_vertex, m_settings.spiral_vase_mode ? static_cast<int>(m_view_range.get_enabled()[0]) : -1));
}
void ViewerImpl::update_colors()
{
@@ -1366,7 +1382,7 @@ void ViewerImpl::update_colors()
// Recalculate "normal" colors of all the vertices for current view settings.
// If some part of the preview should be rendered in dark grey, it is taken
// care of in update_colors_texture. That is to avoid the need to recalculate
// care of in the shaders, see set_layer_colors(). That is to avoid the need to recalculate
// the "normal" color on every slider move.
for (size_t i = 0; i < m_vertices.size(); ++i)
m_vertices_colors[i] = encode_color(get_vertex_color(m_vertices[i]));
@@ -1453,8 +1469,6 @@ void ViewerImpl::set_layers_view_range(Interval::value_type min, Interval::value
update_view_full_range();
m_view_range.set_visible(m_view_range.get_enabled());
m_settings.update_enabled_entities = true;
//m_settings.update_colors = true;
update_colors_texture();
}
void ViewerImpl::toggle_top_layer_only_view_range()
@@ -1463,8 +1477,6 @@ void ViewerImpl::toggle_top_layer_only_view_range()
update_view_full_range();
m_view_range.set_visible(m_view_range.get_enabled());
m_settings.update_enabled_entities = true;
//m_settings.update_colors = true;
update_colors_texture();
}
// ORCA: enable/disable darkening of the layers the layer slider is not scrubbed to
@@ -1473,9 +1485,6 @@ void ViewerImpl::set_dim_previous_layers(bool value)
if (m_settings.dim_previous_layers == value)
return;
m_settings.dim_previous_layers = value;
// defer the actual color/texture rebuild to the next render(), when the GL context is current
// (this may be toggled from the Preferences dialog, outside the canvas context)
m_settings.update_colors = true;
}
// ORCA: set how bright the darkened layers are rendered, 1.0 = unchanged, 0.0 = black
@@ -1485,7 +1494,6 @@ void ViewerImpl::set_dim_previous_layers_brightness(float value)
if (m_settings.dim_previous_layers_brightness == value)
return;
m_settings.dim_previous_layers_brightness = value;
m_settings.update_colors = true;
}
std::vector<ETimeMode> ViewerImpl::get_time_modes() const
@@ -1593,8 +1601,6 @@ void ViewerImpl::set_view_visible_range(Interval::value_type min, Interval::valu
update_view_full_range();
m_view_range.set_visible(min, max);
update_enabled_entities();
//m_settings.update_colors = true;
update_colors_texture();
}
float ViewerImpl::get_estimated_time_at(size_t id) const
@@ -1819,7 +1825,6 @@ size_t ViewerImpl::get_used_cpu_memory() const
for (const std::vector<float>& times : m_layer_start_times)
ret += STDVEC_MEMSIZE(times, float);
ret += STDVEC_MEMSIZE(m_layer_first_vertex, uint32_t);
ret += STDVEC_MEMSIZE(m_colors_scratch, float);
ret += m_valid_lines_bitset.size_in_bytes_cpu();
ret += m_height_range.size_in_bytes_cpu();
ret += m_width_range.size_in_bytes_cpu();
@@ -1912,6 +1917,11 @@ void ViewerImpl::update_view_full_range()
}
auto last_it = first_it;
// ORCA: skip straight to the layer above the range rather than walking there
if (m_layers_in_vertex_order && layers_range[1] + 1 < m_layer_first_vertex.size())
last_it = std::max(first_it, m_vertices.begin() + m_layer_first_vertex[layers_range[1] + 1]);
else if (m_layers_in_vertex_order)
last_it = m_vertices.end();
while (last_it != m_vertices.end() && last_it->layer_id <= layers_range[1]) {
++last_it;
}
@@ -1951,12 +1961,14 @@ void ViewerImpl::update_view_full_range()
if (m_settings.top_layer_only_view_range) {
const Interval& full_range = m_view_range.get_full();
auto top_first_it = m_vertices.begin() + full_range[0];
bool shortened = false;
while (top_first_it != m_vertices.end() && (top_first_it->layer_id < layers_range[1] || !is_visible(*top_first_it, m_settings))) {
const auto range_first_it = m_vertices.begin() + full_range[0];
auto top_first_it = range_first_it;
// ORCA: skip straight to the top layer rather than walking there
if (m_layers_in_vertex_order)
top_first_it = std::max(top_first_it, m_vertices.begin() + m_layer_first_vertex[layers_range[1]]);
while (top_first_it != m_vertices.end() && (top_first_it->layer_id < layers_range[1] || !is_visible(*top_first_it, m_settings)))
++top_first_it;
shortened = true;
}
const bool shortened = top_first_it != range_first_it;
if (shortened)
--top_first_it;
@@ -2038,7 +2050,7 @@ void ViewerImpl::update_color_ranges()
void ViewerImpl::update_heights_widths()
{
#ifdef ENABLE_OPENGL_ES
std::vector<Vec3> heights_widths_angles;
std::vector<Vec4> heights_widths_angles;
heights_widths_angles.reserve(m_vertices.size());
extract_pos_and_or_hwa(m_vertices, m_travels_radius, m_wipes_radius, m_valid_lines_bitset, nullptr, &heights_widths_angles);
m_texture_data.set_heights_widths_angles(heights_widths_angles);
@@ -2070,7 +2082,10 @@ void ViewerImpl::update_heights_widths()
void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& camera_position)
{
if (m_segments_shader_id == 0)
// ORCA: realistic view. The shadow caster pass draws depth only.
const unsigned int shader_id = m_rendering_shadow_casters ? m_segments_caster_shader_id : m_segments_shader_id;
const SegmentsUniforms& uni = m_rendering_shadow_casters ? m_uni_segments_caster : m_uni_segments;
if (shader_id == 0)
return;
#ifdef ENABLE_OPENGL_ES
@@ -2087,42 +2102,54 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
const bool curr_cull_face = glIsEnabled(GL_CULL_FACE);
glcheck();
glsafe(glUseProgram(m_segments_shader_id));
glsafe(glUseProgram(shader_id));
glsafe(glUniform1i(m_uni_segments_positions_tex_id, 0));
glsafe(glUniform1i(m_uni_segments_height_width_angle_tex_id, 1));
glsafe(glUniform1i(m_uni_segments_colors_tex_id, 2));
glsafe(glUniform1i(m_uni_segments_segment_index_tex_id, 3));
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()));
// The segments come in print order, bottom layer first. Seen from above, that is back to front,
// and every hidden fragment is shaded before the one that covers it. Drawing them last to first
// lets the depth test reject the hidden ones instead. The camera looks down when the world's
// up axis points towards it, which is the view matrix's (2, 2) entry being positive.
const bool top_down = !m_rendering_shadow_casters && view_matrix[10] > 0.0f;
glsafe(glUniform1i(m_uni_segments_reverse_order_id, top_down ? 1 : 0));
#ifndef ENABLE_OPENGL_ES
glsafe(glUniform1i(m_uni_segments_instance_count_id, static_cast<int>(m_enabled_segments_count)));
#endif // ENABLE_OPENGL_ES
// 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(glUniform4fv(m_uni_segments_clipping_plane_id, 1, m_clipping_plane.data()));
glsafe(glUniform1i(uni.positions_tex, 0));
glsafe(glUniform1i(uni.height_width_angle_tex, 1));
glsafe(glUniform1i(uni.colors_tex, 2));
glsafe(glUniform1i(uni.segment_index_tex, 3));
glsafe(glUniformMatrix4fv(uni.view_matrix, 1, GL_FALSE, view_matrix.data()));
glsafe(glUniformMatrix4fv(uni.projection_matrix, 1, GL_FALSE, projection_matrix.data()));
glsafe(glUniform3fv(uni.camera_position, 1, camera_position.data()));
// ORCA: view_matrix(2,2) > 0 is looking down, where the last segments printed are the nearest.
const bool reverse_order = view_matrix[10] > 0.0f;
glsafe(glUniform1i(uni.reverse_order, reverse_order ? 1 : 0));
glsafe(glUniform4fv(uni.clipping_plane, 1, m_clipping_plane.data()));
if (!m_rendering_shadow_casters) {
// ORCA: realistic view
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_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(glUniform3fv(m_uni_segments_light_top_dir_id, 1, m_light_top_dir.data()));
set_layer_colors(m_uni_segments_layer_colors);
}
glsafe(glDisable(GL_CULL_FACE));
auto draw = [this, &uni](size_t count) {
glsafe(glUniform1i(uni.instances_count, static_cast<int>(count)));
if (!m_rendering_shadow_casters) {
m_segment_template.render(count);
return;
}
// ORCA: realistic view. 6 vertices per caster ribbon.
int curr_vertex_array = 0;
glsafe(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &curr_vertex_array));
glsafe(glBindVertexArray(m_segments_caster_vao_id));
glsafe(glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(6 * count)));
glsafe(glBindVertexArray(curr_vertex_array));
};
#ifdef ENABLE_OPENGL_ES
int curr_bound_texture = 0;
glsafe(glGetIntegerv(GL_TEXTURE_BINDING_2D, &curr_bound_texture));
for (size_t i = 0; i < m_texture_data.get_count(); ++i) {
const size_t tex_count = m_texture_data.get_count();
for (size_t n = 0; n < tex_count; ++n) {
const size_t i = reverse_order ? tex_count - 1 - n : n;
const auto [id, count] = m_texture_data.get_enabled_segments_tex_id(i);
if (count == 0)
continue;
@@ -2134,7 +2161,7 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
glsafe(glBindTexture(GL_TEXTURE_2D, m_texture_data.get_colors_tex_id(i).first));
glsafe(glActiveTexture(GL_TEXTURE3));
glsafe(glBindTexture(GL_TEXTURE_2D, id));
m_segment_template.render(count);
draw(count);
}
#else
std::array<int, 4> curr_bound_texture = { 0, 0, 0, 0 };
@@ -2157,7 +2184,7 @@ void ViewerImpl::render_segments(const Mat4x4& view_matrix, const Mat4x4& projec
glsafe(glBindTexture(GL_TEXTURE_BUFFER, m_enabled_segments_tex_id));
glsafe(glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, m_enabled_segments_buf_id));
m_segment_template.render(m_enabled_segments_count);
draw(m_enabled_segments_count);
#endif // ENABLE_OPENGL_ES
if (curr_cull_face)
@@ -2203,6 +2230,7 @@ void ViewerImpl::render_options(const Mat4x4& view_matrix, const Mat4x4& project
glsafe(glUniformMatrix4fv(m_uni_options_view_matrix_id, 1, GL_FALSE, view_matrix.data()));
glsafe(glUniformMatrix4fv(m_uni_options_projection_matrix_id, 1, GL_FALSE, projection_matrix.data()));
glsafe(glUniform4fv(m_uni_options_clipping_plane_id, 1, m_clipping_plane.data()));
set_layer_colors(m_uni_options_layer_colors);
glsafe(glEnable(GL_CULL_FACE));
+46 -18
View File
@@ -91,6 +91,7 @@ public:
void set_tone(float exposure, float saturation);
// ORCA: section view, see Viewer::set_clipping_plane()
void set_clipping_plane(const std::array<float, 4>& plane) { m_clipping_plane = plane; }
void set_light_top_dir(const Vec3& direction) { m_light_top_dir = direction; }
EViewType get_view_type() const { return m_settings.view_type; }
void set_view_type(EViewType type);
@@ -264,9 +265,10 @@ private:
//
std::vector<uint32_t> m_layer_first_vertex;
//
// Scratch buffer for update_colors_texture(), kept alive across slider steps
// ORCA: whether the layer ids never decrease along the vertices, so that each layer's vertices
// follow m_layer_first_vertex. Not so for a print by object, whose layers start over per object.
//
std::vector<float> m_colors_scratch;
bool m_layers_in_vertex_order{ false };
//
// Detected travel moves times
//
@@ -349,6 +351,9 @@ private:
// OpenGL shaders ids
//
unsigned int m_segments_shader_id{ 0 };
// ORCA: realistic view. Depth-only ribbons for the shadow caster pass, and the empty vertex array they draw with.
unsigned int m_segments_caster_shader_id{ 0 };
unsigned int m_segments_caster_vao_id{ 0 };
unsigned int m_options_shader_id{ 0 };
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
unsigned int m_cog_marker_shader_id{ 0 };
@@ -357,25 +362,44 @@ private:
//
// Caches for OpenGL uniforms id for segments shader
//
int m_uni_segments_view_matrix_id{ -1 };
int m_uni_segments_projection_matrix_id{ -1 };
int m_uni_segments_camera_position_id{ -1 };
int m_uni_segments_positions_tex_id{ -1 };
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_reverse_order_id{ -1 };
int m_uni_segments_instance_count_id{ -1 };
// ORCA: the ones the shaded and the shadow caster programs share.
struct SegmentsUniforms
{
int view_matrix{ -1 };
int projection_matrix{ -1 };
int camera_position{ -1 };
int positions_tex{ -1 };
int height_width_angle_tex{ -1 };
int colors_tex{ -1 };
int segment_index_tex{ -1 };
int reverse_order{ -1 };
int instances_count{ -1 };
int clipping_plane{ -1 };
void init(unsigned int shader_id);
};
SegmentsUniforms m_uni_segments;
SegmentsUniforms m_uni_segments_caster;
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 };
int m_uni_segments_clipping_plane_id{ -1 };
int m_uni_segments_light_top_dir_id{ -1 };
// ORCA: the layers greyed or dimmed around the one the sliders show, in the segments and options shaders.
struct LayerColorsUniforms
{
int lit_layers{ -1 };
int grey_below_layer{ -1 };
int dim_brightness{ -1 };
int kept_vertex{ -1 };
void init(unsigned int shader_id);
};
LayerColorsUniforms m_uni_segments_layer_colors;
//
// Caches for OpenGL uniforms id for options shader
// Caches for OpenGL uniforms id for options shader
//
int m_uni_options_view_matrix_id{ -1 };
int m_uni_options_projection_matrix_id{ -1 };
@@ -384,6 +408,7 @@ private:
int m_uni_options_colors_tex_id{ -1 };
int m_uni_options_segment_index_tex_id{ -1 };
int m_uni_options_clipping_plane_id{ -1 };
LayerColorsUniforms m_uni_options_layer_colors;
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
//
// Caches for OpenGL uniforms id for cog marker shader
@@ -407,8 +432,8 @@ private:
{
public:
void init(size_t vertices_count);
void set_positions(const std::vector<Vec3>& positions);
void set_heights_widths_angles(const std::vector<Vec3>& heights_widths_angles);
void set_positions(const std::vector<Vec4>& positions);
void set_heights_widths_angles(const std::vector<Vec4>& heights_widths_angles);
void set_colors(const std::vector<float>& colors);
void set_enabled_segments(const std::vector<uint32_t>& enabled_segments);
void set_enabled_options(const std::vector<uint32_t>& enabled_options);
@@ -516,8 +541,7 @@ private:
//
// 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.
// shader. m_rendering_shadow_casters switches render_segments() to the depth-only program.
//
// 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.
@@ -533,6 +557,8 @@ private:
//
float m_exposure{ 1.0f };
float m_saturation{ 1.0f };
// ORCA: the light the segments shader shades with, in eye space.
Vec3 m_light_top_dir{ -0.4574957f, 0.4574957f, 0.7624929f };
// ORCA: section view
std::array<float, 4> m_clipping_plane{ 0.0f, 0.0f, 0.0f, 1.0f };
@@ -543,6 +569,8 @@ private:
void update_heights_widths();
void render_segments(const Mat4x4& view_matrix, const Mat4x4& projection_matrix, const Vec3& camera_position);
void render_options(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
// ORCA: the program using uni must be current.
void set_layer_colors(const LayerColorsUniforms& uni) const;
#if VGCODE_ENABLE_COG_AND_TOOL_MARKERS
void render_cog_marker(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);
void render_tool_marker(const Mat4x4& view_matrix, const Mat4x4& projection_matrix);