Merge branch 'lh_mm_gizmo_rendering'

This commit is contained in:
Lukáš Hejl 2021-07-13 11:36:42 +02:00
commit ce59e68be1
8 changed files with 307 additions and 99 deletions

View file

@ -1,5 +1,19 @@
#version 110
#define INTENSITY_CORRECTION 0.6
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
#define LIGHT_TOP_SHININESS 20.0
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
#define INTENSITY_AMBIENT 0.3
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
const vec3 GREEN = vec3(0.0, 0.7, 0.0);
const vec3 YELLOW = vec3(0.5, 0.7, 0.0);
@ -42,14 +56,42 @@ vec3 sinking_color(vec3 color)
return (mod(model_pos.x + model_pos.y + model_pos.z, BANDS_WIDTH) < (0.5 * BANDS_WIDTH)) ? mix(color, ZERO, 0.6666) : color;
}
uniform bool compute_triangle_normals_in_fs;
void main()
{
if (any(lessThan(clipping_planes_dots, ZERO)))
discard;
vec3 color = uniform_color.rgb;
vec3 color = uniform_color.rgb;
float alpha = uniform_color.a;
if (slope.actived && world_normal_z < slope.normal_z - EPSILON)
{
vec2 intensity_fs = intensity;
vec3 eye_normal_fs = eye_normal;
float world_normal_z_fs = world_normal_z;
if (compute_triangle_normals_in_fs) {
vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz)));
// First transform the normal into camera space and normalize the result.
eye_normal_fs = normalize(gl_NormalMatrix * triangle_normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal_fs, LIGHT_TOP_DIR), 0.0);
intensity_fs = vec2(0.0, 0.0);
intensity_fs.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec3 position = (gl_ModelViewMatrix * model_pos).xyz;
intensity_fs.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal_fs)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal_fs, LIGHT_FRONT_DIR), 0.0);
intensity_fs.x += NdotL * LIGHT_FRONT_DIFFUSE;
// z component of normal vector in world coordinate used for slope shading
world_normal_z_fs = slope.actived ? (normalize(slope.volume_world_normal_matrix * triangle_normal)).z : 0.0;
}
if (slope.actived && world_normal_z_fs < slope.normal_z - EPSILON) {
color = vec3(0.7, 0.7, 1.0);
alpha = 1.0;
}
@ -60,8 +102,8 @@ void main()
color = (abs(world_pos_z) < 0.05) ? WHITE : sinking_color(color);
#ifdef ENABLE_ENVIRONMENT_MAP
if (use_environment_tex)
gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity.x, alpha);
gl_FragColor = vec4(0.45 * texture2D(environment_tex, normalize(eye_normal_fs).xy * 0.5 + 0.5).xyz + 0.8 * color * intensity_fs.x, alpha);
else
#endif
gl_FragColor = vec4(vec3(intensity.y) + color * intensity.x, alpha);
gl_FragColor = vec4(vec3(intensity_fs.y) + color * intensity_fs.x, alpha);
}

View file

@ -54,22 +54,26 @@ varying float world_pos_z;
varying float world_normal_z;
varying vec3 eye_normal;
uniform bool compute_triangle_normals_in_fs;
void main()
{
// First transform the normal into camera space and normalize the result.
eye_normal = normalize(gl_NormalMatrix * gl_Normal);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
if (!compute_triangle_normals_in_fs) {
// First transform the normal into camera space and normalize the result.
eye_normal = normalize(gl_NormalMatrix * gl_Normal);
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Compute the cos of the angle between the normal and lights direction. The light is directional so the direction is constant for every vertex.
// Since these two are normalized the cosine is the dot product. We also need to clamp the result to the [0,1] range.
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
vec3 position = (gl_ModelViewMatrix * gl_Vertex).xyz;
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
// Perform the same lighting calculation for the 2nd light source (no specular applied).
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
}
model_pos = gl_Vertex;
// Point in homogenous coordinates.
@ -77,19 +81,17 @@ void main()
world_pos_z = world_pos.z;
// compute deltas for out of print volume detection (world coordinates)
if (print_box.actived)
{
if (print_box.actived) {
delta_box_min = world_pos.xyz - print_box.min;
delta_box_max = world_pos.xyz - print_box.max;
}
else
{
} else {
delta_box_min = ZERO;
delta_box_max = ZERO;
}
// z component of normal vector in world coordinate used for slope shading
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0;
if (!compute_triangle_normals_in_fs)
world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0;
gl_Position = ftransform();
// Fill in the scalars for fragment shader clipping. Fragments with any of these components lower than zero are discarded.

View file

@ -170,6 +170,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
}
@ -285,13 +286,12 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
// Now calculate dot product of vert_direction and facets' normals.
int idx = -1;
for (const stl_facet& facet : mv->mesh().stl.facet_start) {
for (const stl_facet &facet : mv->mesh().stl.facet_start) {
++idx;
if (facet.normal.dot(down) > dot_limit)
m_triangle_selectors[mesh_id]->set_facet(idx,
block
? EnforcerBlockerType::BLOCKER
: EnforcerBlockerType::ENFORCER);
if (facet.normal.dot(down) > dot_limit) {
m_triangle_selectors[mesh_id]->set_facet(idx, block ? EnforcerBlockerType::BLOCKER : EnforcerBlockerType::ENFORCER);
m_triangle_selectors.back()->request_update_render_data();
}
}
}
@ -346,6 +346,7 @@ void GLGizmoFdmSupports::update_from_model_object()
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
m_triangle_selectors.back()->deserialize(mv->supported_facets.get_data());
m_triangle_selectors.back()->request_update_render_data();
}
}

View file

@ -296,8 +296,10 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
if (m_imgui->checkbox(_L("Seed fill"), m_seed_fill_enabled))
if (!m_seed_fill_enabled)
for (auto &triangle_selector : m_triangle_selectors)
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
m_imgui->text(m_desc["seed_fill_angle"] + ":");
ImGui::AlignTextToFramePadding();
@ -319,6 +321,7 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
}
@ -437,8 +440,9 @@ void GLGizmoMmuSegmentation::init_model_triangle_selectors()
const TriangleMesh *mesh = &mv->mesh();
int extruder_idx = (mv->extruder_id() > 0) ? mv->extruder_id() - 1 : 0;
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorMmuGui>(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)]));
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorMmGui>(*mesh, m_modified_extruders_colors, m_original_extruders_colors[size_t(extruder_idx)]));
m_triangle_selectors.back()->deserialize(mv->mmu_segmentation_facets.get_data());
m_triangle_selectors.back()->request_update_render_data();
}
m_original_volumes_extruder_idxs = get_extruder_id_for_volumes(*mo);
}
@ -466,54 +470,60 @@ std::array<float, 4> GLGizmoMmuSegmentation::get_cursor_sphere_right_button_colo
return {color[0], color[1], color[2], 0.25f};
}
void TriangleSelectorMmuGui::render(ImGuiWrapper *imgui)
void TriangleSelectorMmGui::render(ImGuiWrapper *imgui)
{
static constexpr std::array<float, 4> seed_fill_color{0.f, 1.f, 0.44f, 1.f};
for (auto &iva_color : m_iva_colors)
iva_color.release_geometry();
m_iva_seed_fill.release_geometry();
if (m_update_render_data)
update_render_data();
for (const Triangle &tr : m_triangles)
if (tr.valid() && ! tr.is_split()) {
GLIndexedVertexArray *iva = nullptr;
if (tr.is_selected_by_seed_fill())
iva = &m_iva_seed_fill;
else if (int color = int(tr.get_state()); color < int(m_iva_colors.size()))
iva = &m_iva_colors[color];
if (iva) {
if (iva->vertices_and_normals_interleaved.size() + 18 > iva->vertices_and_normals_interleaved.capacity())
iva->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(iva->vertices_and_normals_interleaved.size() + 18));
const Vec3f &n = m_mesh->stl.facet_start[tr.source_triangle].normal;
for (int i = 0; i < 3; ++ i) {
const Vec3f &v = m_vertices[tr.verts_idxs[i]].v;
iva->vertices_and_normals_interleaved.emplace_back(n.x());
iva->vertices_and_normals_interleaved.emplace_back(n.y());
iva->vertices_and_normals_interleaved.emplace_back(n.z());
iva->vertices_and_normals_interleaved.emplace_back(v.x());
iva->vertices_and_normals_interleaved.emplace_back(v.y());
iva->vertices_and_normals_interleaved.emplace_back(v.z());
}
}
}
auto* shader = wxGetApp().get_current_shader();
auto *shader = wxGetApp().get_current_shader();
if (!shader)
return;
assert(shader->get_name() == "gouraud");
ScopeGuard guard([shader]() { if (shader) shader->set_uniform("compute_triangle_normals_in_fs", false);});
shader->set_uniform("compute_triangle_normals_in_fs", true);
for (size_t i = 0; i <= m_iva_colors.size(); ++i)
if (GLIndexedVertexArray &iva = i == m_iva_colors.size() ? m_iva_seed_fill : m_iva_colors[i];
! iva.vertices_and_normals_interleaved.empty()) {
iva.vertices_and_normals_interleaved_size = iva.vertices_and_normals_interleaved.size();
iva.triangle_indices.assign(iva.vertices_and_normals_interleaved_size / 6, 0);
std::iota(iva.triangle_indices.begin(), iva.triangle_indices.end(), 0);
iva.triangle_indices_size = iva.triangle_indices.size();
iva.finalize_geometry(true);
shader->set_uniform("uniform_color",
(i == 0) ? m_default_volume_color : i == m_iva_colors.size() ? seed_fill_color : m_colors[i - 1]);
iva.render();
for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx)
if (m_gizmo_scene.has_VBOs(color_idx)) {
shader->set_uniform("uniform_color", color_idx == 0 ? m_default_volume_color :
color_idx == (m_gizmo_scene.triangle_indices.size() - 1) ? seed_fill_color :
m_colors[color_idx - 1]);
m_gizmo_scene.render(color_idx);
}
m_update_render_data = false;
}
void TriangleSelectorMmGui::update_render_data()
{
m_gizmo_scene.release_geometry();
m_vertices.reserve(m_vertices.size() * 3);
for (const Vertex &vr : m_vertices) {
m_gizmo_scene.vertices.emplace_back(vr.v.x());
m_gizmo_scene.vertices.emplace_back(vr.v.y());
m_gizmo_scene.vertices.emplace_back(vr.v.z());
}
m_gizmo_scene.finalize_vertices();
for (const Triangle &tr : m_triangles)
if (tr.valid() && !tr.is_split()) {
int color = int(tr.get_state());
std::vector<int> &iva = tr.is_selected_by_seed_fill() ? m_gizmo_scene.triangle_indices.back() :
color < int(m_gizmo_scene.triangle_indices.size() - 1) ? m_gizmo_scene.triangle_indices[color] :
m_gizmo_scene.triangle_indices.front();
if (iva.size() + 3 > iva.capacity())
iva.reserve(next_highest_power_of_2(iva.size() + 3));
iva.emplace_back(tr.verts_idxs[0]);
iva.emplace_back(tr.verts_idxs[1]);
iva.emplace_back(tr.verts_idxs[2]);
}
for (size_t color_idx = 0; color_idx < m_gizmo_scene.triangle_indices.size(); ++color_idx)
m_gizmo_scene.triangle_indices_sizes[color_idx] = m_gizmo_scene.triangle_indices[color_idx].size();
m_gizmo_scene.finalize_triangle_indices();
}
wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
@ -528,4 +538,77 @@ wxString GLGizmoMmuSegmentation::handle_snapshot_action_name(bool shift_down, GL
return action_name;
}
void GLMmSegmentationGizmo3DScene::release_geometry() {
if (this->vertices_VBO_id) {
glsafe(::glDeleteBuffers(1, &this->vertices_VBO_id));
this->vertices_VBO_id = 0;
}
for(auto &triangle_indices_VBO_id : triangle_indices_VBO_ids) {
glsafe(::glDeleteBuffers(1, &triangle_indices_VBO_id));
triangle_indices_VBO_id = 0;
}
this->clear();
}
void GLMmSegmentationGizmo3DScene::render(size_t triangle_indices_idx) const
{
assert(triangle_indices_idx < this->triangle_indices_VBO_ids.size());
assert(this->triangle_indices_sizes.size() == this->triangle_indices_VBO_ids.size());
assert(this->vertices_VBO_id != 0);
assert(this->triangle_indices_VBO_ids[triangle_indices_idx] != 0);
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id));
glsafe(::glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), (const void*)(0 * sizeof(float))));
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
// Render using the Vertex Buffer Objects.
if (this->triangle_indices_sizes[triangle_indices_idx] > 0) {
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[triangle_indices_idx]));
glsafe(::glDrawElements(GL_TRIANGLES, GLsizei(this->triangle_indices_sizes[triangle_indices_idx]), GL_UNSIGNED_INT, nullptr));
glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
}
void GLMmSegmentationGizmo3DScene::finalize_vertices()
{
assert(this->vertices_VBO_id == 0);
if (!this->vertices.empty()) {
glsafe(::glGenBuffers(1, &this->vertices_VBO_id));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_VBO_id));
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * 4, this->vertices.data(), GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
this->vertices.clear();
}
}
void GLMmSegmentationGizmo3DScene::finalize_triangle_indices()
{
assert(triangle_indices_idx < this->triangle_indices.size());
assert(std::all_of(triangle_indices_VBO_ids.cbegin(), triangle_indices_VBO_ids.cend(), [](const auto &ti_VBO_id) { return ti_VBO_id == 0; }));
assert(this->triangle_indices.size() == this->triangle_indices_VBO_ids.size());
for (size_t buffer_idx = 0; buffer_idx < this->triangle_indices.size(); ++buffer_idx)
if (!this->triangle_indices[buffer_idx].empty()) {
glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_ids[buffer_idx]));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices_VBO_ids[buffer_idx]));
glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->triangle_indices[buffer_idx].size() * 4, this->triangle_indices[buffer_idx].data(),
GL_STATIC_DRAW));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
this->triangle_indices[buffer_idx].clear();
}
}
void GLMmSegmentationGizmo3DScene::finalize_geometry()
{
assert(this->vertices_VBO_id == 0);
assert(this->triangle_indices.size() == this->triangle_indices_VBO_ids.size());
finalize_vertices();
finalize_triangle_indices();
}
} // namespace Slic3r

View file

@ -5,24 +5,80 @@
namespace Slic3r::GUI {
class TriangleSelectorMmuGui : public TriangleSelectorGUI {
class GLMmSegmentationGizmo3DScene
{
public:
explicit TriangleSelectorMmuGui(const TriangleMesh& mesh, const std::vector<std::array<float, 4>> &colors, const std::array<float, 4> &default_volume_color)
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color) {
// Plus 1 is because the first position is allocated for non-painted triangles.
m_iva_colors = std::vector<GLIndexedVertexArray>(colors.size() + 1);
GLMmSegmentationGizmo3DScene() = delete;
explicit GLMmSegmentationGizmo3DScene(size_t triangle_indices_buffers_count)
{
this->triangle_indices = std::vector<std::vector<int>>(triangle_indices_buffers_count);
this->triangle_indices_sizes = std::vector<size_t>(triangle_indices_buffers_count);
this->triangle_indices_VBO_ids = std::vector<unsigned int>(triangle_indices_buffers_count);
}
~TriangleSelectorMmuGui() override = default;
virtual ~GLMmSegmentationGizmo3DScene() { release_geometry(); }
[[nodiscard]] inline bool has_VBOs(size_t triangle_indices_idx) const
{
assert(triangle_indices_idx < this->triangle_indices.size());
return this->triangle_indices_VBO_ids[triangle_indices_idx] != 0;
}
// Finalize the initialization of the geometry and indices, upload the geometry and indices to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_geometry();
// Release the geometry data, release OpenGL VBOs.
void release_geometry();
// Finalize the initialization of the geometry, upload the geometry to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_vertices();
// Finalize the initialization of the indices, upload the indices to OpenGL VBO objects
// and possibly releasing it if it has been loaded into the VBOs.
void finalize_triangle_indices();
void clear()
{
this->vertices.clear();
for (std::vector<int> &ti : this->triangle_indices)
ti.clear();
for (size_t &triangle_indices_size : this->triangle_indices_sizes)
triangle_indices_size = 0;
}
void render(size_t triangle_indices_idx) const;
std::vector<float> vertices;
std::vector<std::vector<int>> triangle_indices;
// When the triangle indices are loaded into the graphics card as Vertex Buffer Objects,
// the above mentioned std::vectors are cleared and the following variables keep their original length.
std::vector<size_t> triangle_indices_sizes;
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
// Zero if the VBOs are not sent to GPU yet.
unsigned int vertices_VBO_id{0};
std::vector<unsigned int> triangle_indices_VBO_ids;
};
class TriangleSelectorMmGui : public TriangleSelectorGUI {
public:
// Plus 2 in the initialization of m_gizmo_scene is because the first position is allocated for non-painted triangles, and the last position is allocated for seed fill.
explicit TriangleSelectorMmGui(const TriangleMesh &mesh, const std::vector<std::array<float, 4>> &colors, const std::array<float, 4> &default_volume_color)
: TriangleSelectorGUI(mesh), m_colors(colors), m_default_volume_color(default_volume_color), m_gizmo_scene(colors.size() + 2) {}
~TriangleSelectorMmGui() override = default;
// Render current selection. Transformation matrices are supposed
// to be already set.
void render(ImGuiWrapper* imgui) override;
private:
void update_render_data();
const std::vector<std::array<float, 4>> &m_colors;
std::vector<GLIndexedVertexArray> m_iva_colors;
const std::array<float, 4> m_default_volume_color;
GLIndexedVertexArray m_iva_seed_fill;
GLMmSegmentationGizmo3DScene m_gizmo_scene;
};
class GLGizmoMmuSegmentation : public GLGizmoPainterBase

View file

@ -402,6 +402,8 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
} else
m_triangle_selectors[m_rr.mesh_id]->select_patch(m_rr.hit, int(m_rr.facet), camera_pos, m_cursor_radius, m_cursor_type,
new_state, trafo_matrix, m_triangle_splitting_enabled);
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
m_last_mouse_click = mouse_position;
}
@ -428,8 +430,10 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
update_raycast_cache(mouse_position, camera, trafo_matrices);
auto seed_fill_unselect_all = [this]() {
for (auto &triangle_selector : m_triangle_selectors)
for (auto &triangle_selector : m_triangle_selectors) {
triangle_selector->seed_fill_unselect_all_triangles();
triangle_selector->request_update_render_data();
}
};
if (m_rr.mesh_id == -1) {
@ -447,6 +451,7 @@ bool GLGizmoPainterBase::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
assert(m_rr.mesh_id < int(m_triangle_selectors.size()));
m_triangle_selectors[m_rr.mesh_id]->seed_fill_select_triangles(m_rr.hit, int(m_rr.facet), m_seed_fill_angle);
m_triangle_selectors[m_rr.mesh_id]->request_update_render_data();
m_seed_fill_last_mesh_id = m_rr.mesh_id;
return true;
}
@ -589,28 +594,11 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
static constexpr std::array<float, 4> enforcers_color{0.47f, 0.47f, 1.f, 1.f};
static constexpr std::array<float, 4> blockers_color{1.f, 0.44f, 0.44f, 1.f};
int enf_cnt = 0;
int blc_cnt = 0;
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->release_geometry();
for (const Triangle& tr : m_triangles) {
if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE)
continue;
GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers;
int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt;
for (int i = 0; i < 3; ++i)
iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
iva.push_triangle(cnt, cnt + 1, cnt + 2);
cnt += 3;
if (m_update_render_data) {
update_render_data();
m_update_render_data = false;
}
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->finalize_geometry(true);
auto* shader = wxGetApp().get_current_shader();
if (! shader)
return;
@ -635,6 +623,33 @@ void TriangleSelectorGUI::render(ImGuiWrapper* imgui)
void TriangleSelectorGUI::update_render_data()
{
int enf_cnt = 0;
int blc_cnt = 0;
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->release_geometry();
for (const Triangle &tr : m_triangles) {
if (!tr.valid() || tr.is_split() || tr.get_state() == EnforcerBlockerType::NONE)
continue;
GLIndexedVertexArray &iva = tr.get_state() == EnforcerBlockerType::ENFORCER ? m_iva_enforcers : m_iva_blockers;
int & cnt = tr.get_state() == EnforcerBlockerType::ENFORCER ? enf_cnt : blc_cnt;
for (int i = 0; i < 3; ++i)
iva.push_geometry(m_vertices[tr.verts_idxs[i]].v, m_mesh->stl.facet_start[tr.source_triangle].normal);
iva.push_triangle(cnt, cnt + 1, cnt + 2);
cnt += 3;
}
for (auto *iva : {&m_iva_enforcers, &m_iva_blockers})
iva->finalize_geometry(true);
}
#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG
void TriangleSelectorGUI::render_debug(ImGuiWrapper* imgui)
{

View file

@ -38,13 +38,20 @@ public:
virtual void render(ImGuiWrapper *imgui);
void render() { this->render(nullptr); }
void request_update_render_data() { m_update_render_data = true; };
#ifdef PRUSASLICER_TRIANGLE_SELECTOR_DEBUG
void render_debug(ImGuiWrapper* imgui);
bool m_show_triangles{false};
bool m_show_invalid{false};
#endif
protected:
bool m_update_render_data = false;
private:
void update_render_data();
GLIndexedVertexArray m_iva_enforcers;
GLIndexedVertexArray m_iva_blockers;
std::array<GLIndexedVertexArray, 3> m_varrays;

View file

@ -127,6 +127,7 @@ void GLGizmoSeam::on_render_input_window(float x, float y, float bottom_limit)
if (mv->is_model_part()) {
++idx;
m_triangle_selectors[idx]->reset();
m_triangle_selectors[idx]->request_update_render_data();
}
}
@ -257,6 +258,7 @@ void GLGizmoSeam::update_from_model_object()
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorGUI>(*mesh));
m_triangle_selectors.back()->deserialize(mv->seam_facets.get_data());
m_triangle_selectors.back()->request_update_render_data();
}
}