From 7bce69f9c76da9ae90d0b737f216fe59174b3439 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Mon, 18 Jan 2021 09:59:05 +0100 Subject: ENABLE_SPLITTED_VERTEX_BUFFER - fixed cracks in toolpaths when splitting vertex and index buffers --- src/libslic3r/Technologies.hpp | 1 + src/slic3r/GUI/GCodeViewer.cpp | 221 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 219 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 1ebfd7b3a..f61de0dc6 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -114,6 +114,7 @@ #define ENABLE_2_3_1 1 #define ENABLE_SPLITTED_VERTEX_BUFFER (1 && ENABLE_2_3_1) +#define ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING (1 && ENABLE_SPLITTED_VERTEX_BUFFER) #endif // _prusaslicer_technologies_h_ diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index b3794175e..510aa2529 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1219,6 +1219,65 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) }; // format data into the buffers to be rendered as solid +#if ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING + auto add_vertices_as_solid = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, unsigned int vbuffer_id, VertexBuffer& vertices, size_t move_id) { + auto store_vertex = [](VertexBuffer& vertices, const Vec3f& position, const Vec3f& normal) { + // append position + vertices.push_back(position[0]); + vertices.push_back(position[1]); + vertices.push_back(position[2]); + // append normal + vertices.push_back(normal[0]); + vertices.push_back(normal[1]); + vertices.push_back(normal[2]); + }; + + if (prev.type != curr.type || !buffer.paths.back().matches(curr)) { + buffer.add_path(curr, vbuffer_id, vertices.size(), move_id - 1); + buffer.paths.back().sub_paths.back().first.position = prev.position; + } + + Path& last_path = buffer.paths.back(); + + Vec3f dir = (curr.position - prev.position).normalized(); + Vec3f right = Vec3f(dir[1], -dir[0], 0.0f).normalized(); + Vec3f left = -right; + Vec3f up = right.cross(dir); + Vec3f down = -up; + float half_width = 0.5f * last_path.width; + float half_height = 0.5f * last_path.height; + Vec3f prev_pos = prev.position - half_height * up; + Vec3f curr_pos = curr.position - half_height * up; + Vec3f d_up = half_height * up; + Vec3f d_down = -half_height * up; + Vec3f d_right = half_width * right; + Vec3f d_left = -half_width * right; + + // vertices 1st endpoint + if (last_path.vertices_count() == 1 || vertices.empty()) { + // 1st segment or restart into a new vertex buffer + // =============================================== + store_vertex(vertices, prev_pos + d_up, up); + store_vertex(vertices, prev_pos + d_right, right); + store_vertex(vertices, prev_pos + d_down, down); + store_vertex(vertices, prev_pos + d_left, left); + } + else { + // any other segment + // ================= + store_vertex(vertices, prev_pos + d_right, right); + store_vertex(vertices, prev_pos + d_left, left); + } + + // vertices 2nd endpoint + store_vertex(vertices, curr_pos + d_up, up); + store_vertex(vertices, curr_pos + d_right, right); + store_vertex(vertices, curr_pos + d_down, down); + store_vertex(vertices, curr_pos + d_left, left); + + last_path.sub_paths.back().last = { vbuffer_id, vertices.size(), move_id, curr.position }; + }; +#else auto add_vertices_as_solid = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, VertexBuffer& vertices, size_t move_id) { static Vec3f prev_dir; static Vec3f prev_up; @@ -1293,7 +1352,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) } Vec3f displacement_vec = displacement * prev_dir; - bool can_displace = displacement > 0.0f && displacement < prev_length&& displacement < length; + bool can_displace = displacement > 0.0f && displacement < prev_length && displacement < length; size_t prev_right_id = (starting_vertices_size - 3) * buffer.vertices.vertex_size_floats(); size_t prev_left_id = (starting_vertices_size - 1) * buffer.vertices.vertex_size_floats(); @@ -1366,6 +1425,7 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) prev_up = up; prev_length = length; }; +#endif // ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING auto add_indices_as_solid = [](const GCodeProcessor::MoveVertex& prev, const GCodeProcessor::MoveVertex& curr, TBuffer& buffer, size_t& vbuffer_size, unsigned int ibuffer_id, IndexBuffer& indices, size_t move_id) { static Vec3f prev_dir; @@ -1573,8 +1633,19 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) // if adding the vertices for the current segment exceeds the threshold size of the current vertex buffer // add another vertex buffer +#if ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING + if (v_multibuffer.back().size() * sizeof(float) > VBUFFER_THRESHOLD_BYTES - t_buffer.max_vertices_per_segment_size_bytes()) { + v_multibuffer.push_back(VertexBuffer()); + if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) { + Path& last_path = t_buffer.paths.back(); + if (prev.type == curr.type && last_path.matches(curr)) + last_path.add_sub_path(prev, static_cast(v_multibuffer.size()) - 1, 0, i - 1); + } + } +#else if (v_multibuffer.back().size() * sizeof(float) > VBUFFER_THRESHOLD_BYTES - t_buffer.max_vertices_per_segment_size_bytes()) v_multibuffer.push_back(VertexBuffer()); +#endif // ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING VertexBuffer& v_buffer = v_multibuffer.back(); @@ -1582,7 +1653,11 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) { case TBuffer::ERenderPrimitiveType::Point: { add_vertices_as_point(curr, v_buffer); break; } case TBuffer::ERenderPrimitiveType::Line: { add_vertices_as_line(prev, curr, v_buffer); break; } +#if ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING + case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, static_cast(v_multibuffer.size()) - 1, v_buffer, i); break; } +#else case TBuffer::ERenderPrimitiveType::Triangle: { add_vertices_as_solid(prev, curr, t_buffer, v_buffer, i); break; } +#endif // ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING } // collect options zs for later use @@ -1593,6 +1668,138 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) } } +#if ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING + // smooth toolpaths corners for the given TBuffer using triangles + auto smooth_triangle_toolpaths_corners = [&gcode_result](const TBuffer& t_buffer, MultiVertexBuffer& v_multibuffer) { + auto extract_position_at = [](const VertexBuffer& vertices, size_t offset) { + return Vec3f(vertices[offset + 0], vertices[offset + 1], vertices[offset + 2]); + }; + auto update_position_at = [](VertexBuffer& vertices, size_t offset, const Vec3f& position) { + vertices[offset + 0] = position[0]; + vertices[offset + 1] = position[1]; + vertices[offset + 2] = position[2]; + }; + + size_t vertex_size_floats = t_buffer.vertices.vertex_size_floats(); + for (const Path& path : t_buffer.paths) { + // the two segments of the path sharing the current vertex may belong + // to two different vertex buffers + size_t prev_sub_path_id = 0; + size_t next_sub_path_id = 0; + size_t path_vertices_count = path.vertices_count(); + float half_width = 0.5f * path.width; + for (size_t j = 1; j < path_vertices_count - 1; ++j) { + size_t curr_s_id = path.sub_paths.front().first.s_id + j; + const Vec3f& prev = gcode_result.moves[curr_s_id - 1].position; + const Vec3f& curr = gcode_result.moves[curr_s_id].position; + const Vec3f& next = gcode_result.moves[curr_s_id + 1].position; + + // select the subpaths which contains the previous/next segments + if (!path.sub_paths[prev_sub_path_id].contains(curr_s_id)) + ++prev_sub_path_id; + if (!path.sub_paths[next_sub_path_id].contains(curr_s_id + 1)) + ++next_sub_path_id; + const Path::Sub_Path& prev_sub_path = path.sub_paths[prev_sub_path_id]; + const Path::Sub_Path& next_sub_path = path.sub_paths[next_sub_path_id]; + + Vec3f prev_dir = (curr - prev).normalized(); + Vec3f prev_right = Vec3f(prev_dir[1], -prev_dir[0], 0.0f).normalized(); + Vec3f prev_up = prev_right.cross(prev_dir); + + Vec3f next_dir = (next - curr).normalized(); + Vec3f next_right = Vec3f(next_dir[1], -next_dir[0], 0.0f).normalized(); + Vec3f next_up = next_right.cross(next_dir); + + bool is_right_turn = prev_up.dot(prev_dir.cross(next_dir)) <= 0.0f; + float cos_dir = prev_dir.dot(next_dir); + // whether the angle between adjacent segments is greater than 45 degrees + bool is_sharp = cos_dir < 0.7071068f; + + float displacement = 0.0f; + if (cos_dir > -0.9998477f) { + // if the angle between adjacent segments is smaller than 179 degrees + Vec3f med_dir = (prev_dir + next_dir).normalized(); + displacement = half_width * ::tan(::acos(std::clamp(next_dir.dot(med_dir), -1.0f, 1.0f))); + } + + float sq_prev_length = (curr - prev).squaredNorm(); + float sq_next_length = (next - curr).squaredNorm(); + float sq_displacement = sqr(displacement); + bool can_displace = displacement > 0.0f && sq_displacement < sq_prev_length&& sq_displacement < sq_next_length; + + if (can_displace) { + Vec3f displacement_vec = displacement * prev_dir; + // matches inner corner vertices + if (is_right_turn) { + // offset into the vertex buffer of the right vertex of the previous segment + size_t prev_right_offset = prev_sub_path.last.i_id - ((prev_sub_path.last.s_id - curr_s_id) * 6 + 3) * vertex_size_floats; + // new position of the right vertices + Vec3f shared_right = extract_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_right_offset) - displacement_vec; + // update previous segment + update_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_right_offset, shared_right); + // offset into the vertex buffer of the right vertex of the next segment + size_t r_offset = (curr_s_id == next_sub_path.first.i_id) ? 1 : 0; + size_t next_right_offset = next_sub_path.last.i_id - ((next_sub_path.last.s_id - curr_s_id) * 6 - r_offset) * vertex_size_floats; + // update next segment + update_position_at(v_multibuffer[next_sub_path.first.b_id], next_right_offset, shared_right); + } + else { + // offset into the vertex buffer of the left vertex of the previous segment + size_t prev_left_offset = prev_sub_path.last.i_id - ((prev_sub_path.last.s_id - curr_s_id) * 6 + 1) * vertex_size_floats; + // new position of the left vertices + Vec3f shared_left = extract_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_left_offset) - displacement_vec; + // update previous segment + update_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_left_offset, shared_left); + // offset into the vertex buffer of the left vertex of the next segment + size_t l_offset = (curr_s_id == next_sub_path.first.i_id) ? 3 : 1; + size_t next_left_offset = next_sub_path.last.i_id - ((next_sub_path.last.s_id - curr_s_id) * 6 - l_offset) * vertex_size_floats; + // update next segment + update_position_at(v_multibuffer[next_sub_path.first.b_id], next_left_offset, shared_left); + } + + if (!is_sharp) { + // matches outer corner vertices + if (is_right_turn) { + // offset into the vertex buffer of the left vertex of the previous segment + size_t prev_left_offset = prev_sub_path.last.i_id - ((prev_sub_path.last.s_id - curr_s_id) * 6 + 1) * vertex_size_floats; + // new position of the left vertices + Vec3f shared_left = extract_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_left_offset) + displacement_vec; + // update previous segment + update_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_left_offset, shared_left); + // offset into the vertex buffer of the left vertex of the next segment + size_t l_offset = (curr_s_id == next_sub_path.first.i_id) ? 3 : 1; + size_t next_left_offset = next_sub_path.last.i_id - ((next_sub_path.last.s_id - curr_s_id) * 6 - l_offset) * vertex_size_floats; + // update next segment + update_position_at(v_multibuffer[next_sub_path.first.b_id], next_left_offset, shared_left); + } + else { + // offset into the vertex buffer of the right vertex of the previous segment + size_t prev_right_offset = prev_sub_path.last.i_id - ((prev_sub_path.last.s_id - curr_s_id) * 6 + 3) * vertex_size_floats; + // new position of the right vertices + Vec3f shared_right = extract_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_right_offset) + displacement_vec; + // update previous segment + update_position_at(v_multibuffer[prev_sub_path.first.b_id], prev_right_offset, shared_right); + // offset into the vertex buffer of the right vertex of the next segment + size_t r_offset = (curr_s_id == next_sub_path.first.i_id) ? 1 : 0; + size_t next_right_offset = next_sub_path.last.i_id - ((next_sub_path.last.s_id - curr_s_id) * 6 - r_offset) * vertex_size_floats; + // update next segment + update_position_at(v_multibuffer[next_sub_path.first.b_id], next_right_offset, shared_right); + } + } + } + } + } + }; + + // smooth toolpaths corners for TBuffers using triangles + for (size_t i = 0; i < m_buffers.size(); ++i) { + const TBuffer& t_buffer = m_buffers[i]; + if (t_buffer.render_primitive_type == TBuffer::ERenderPrimitiveType::Triangle) { + smooth_triangle_toolpaths_corners(t_buffer, vertices[i]); + } + } +#endif // ENABLE_TOOLPATHS_ALTERNATE_SMOOTHING + for (MultiVertexBuffer& v_multibuffer : vertices) { for (VertexBuffer& v_buffer : v_multibuffer) { v_buffer.shrink_to_fit(); @@ -1693,7 +1900,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) vbo_index_list.push_back(t_buffer.vertices.vbos[curr_vertex_buffer.first]); if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) { Path& last_path = t_buffer.paths.back(); - --last_path.sub_paths.back().last.s_id; last_path.add_sub_path(prev, static_cast(i_multibuffer.size()) - 1, 0, i - 1); } } @@ -1709,7 +1915,6 @@ void GCodeViewer::load_toolpaths(const GCodeProcessor::Result& gcode_result) if (t_buffer.render_primitive_type != TBuffer::ERenderPrimitiveType::Point) { Path& last_path = t_buffer.paths.back(); - --last_path.sub_paths.back().last.s_id; last_path.add_sub_path(prev, static_cast(i_multibuffer.size()) - 1, 0, i - 1); } } @@ -2819,6 +3024,16 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool delta_1st *= buffer->indices_per_segment(); render_path->offsets.push_back(static_cast((sub_path.first.i_id + delta_1st) * sizeof(unsigned int))); + +#if 0 + // check sizes and offsets against index buffer size on gpu + GLint buffer_size; + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->indices[render_path->index_buffer_id].ibo)); + glsafe(::glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &buffer_size)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); + if (render_path->offsets.back() + render_path->sizes.back() * sizeof(unsigned int) > buffer_size) + BOOST_LOG_TRIVIAL(error) << "GCodeViewer::refresh_render_paths: Invalid render path data"; +#endif } // set sequential data to their final value -- cgit v1.2.3