Show blue dot on texture mapping zones that are used on the currently selected objects.
- Reduce filament region triangle subdivision when using image projection
This commit is contained in:
@@ -938,6 +938,16 @@ static float triangle_max_edge_length(const std::array<Vec3f, 3> &vertices)
|
||||
(vertices[0] - vertices[2]).norm() });
|
||||
}
|
||||
|
||||
static float transformed_triangle_max_edge_length(const Transform3d &matrix, const std::array<Vec3f, 3> &vertices)
|
||||
{
|
||||
const std::array<Vec3f, 3> transformed_vertices = {
|
||||
(matrix * vertices[0].cast<double>()).cast<float>(),
|
||||
(matrix * vertices[1].cast<double>()).cast<float>(),
|
||||
(matrix * vertices[2].cast<double>()).cast<float>()
|
||||
};
|
||||
return triangle_max_edge_length(transformed_vertices);
|
||||
}
|
||||
|
||||
static float mesh_max_axis_span(const indexed_triangle_set &its)
|
||||
{
|
||||
if (its.vertices.empty())
|
||||
@@ -981,6 +991,7 @@ static constexpr float TRUE_COLOR_BRUSH_SUBDIVISION_FRACTION = 1.f / 8.f;
|
||||
static constexpr float TRUE_COLOR_BRUSH_MIN_SUBDIVISION_EDGE_MM = 0.1f;
|
||||
static constexpr float IMAGE_PROJECTION_RGB_TARGET_TRIANGLE_IMAGE_FRACTION = 1.f / 128.f;
|
||||
static constexpr float IMAGE_PROJECTION_RGB_MIN_TARGET_TRIANGLE_IMAGE_PX = 2.f;
|
||||
static constexpr float IMAGE_PROJECTION_REGION_TARGET_EDGE_MM = 0.5f;
|
||||
|
||||
static float true_color_brush_subdivision_target(float brush_radius)
|
||||
{
|
||||
@@ -6519,6 +6530,7 @@ static std::array<std::array<Vec3f, 3>, 4> projection_region_split_triangle(cons
|
||||
}
|
||||
|
||||
using ProjectionRegionStateSampler = std::function<unsigned int(size_t, const Vec3f &, const Vec3f &)>;
|
||||
using ProjectionRegionTrianglePredicate = std::function<bool(const std::array<Vec3f, 3> &)>;
|
||||
|
||||
static bool projection_region_append_sampled_triangle(TriangleSelector::TriangleSplittingData &data,
|
||||
const ProjectionRegionStateSampler &sampler,
|
||||
@@ -6526,8 +6538,15 @@ static bool projection_region_append_sampled_triangle(TriangleSelector::Triangle
|
||||
const std::array<Vec3f, 3> &vertices,
|
||||
const std::array<Vec3f, 3> &barycentrics,
|
||||
int depth,
|
||||
int target_depth)
|
||||
int target_depth,
|
||||
const ProjectionRegionTrianglePredicate &fully_projected = {},
|
||||
unsigned int fully_projected_state = 0)
|
||||
{
|
||||
if (depth > 0 && fully_projected && fully_projected(vertices)) {
|
||||
projection_region_append_leaf(data, fully_projected_state);
|
||||
return fully_projected_state != 0;
|
||||
}
|
||||
|
||||
if (depth < target_depth) {
|
||||
projection_region_append_nibble(data.bitstream, 3u);
|
||||
const std::array<std::array<Vec3f, 3>, 4> child_vertices = projection_region_split_triangle(vertices);
|
||||
@@ -6540,7 +6559,9 @@ static bool projection_region_append_sampled_triangle(TriangleSelector::Triangle
|
||||
child_vertices[size_t(child_idx)],
|
||||
child_barycentrics[size_t(child_idx)],
|
||||
depth + 1,
|
||||
target_depth);
|
||||
target_depth,
|
||||
fully_projected,
|
||||
fully_projected_state);
|
||||
return has_painted_state;
|
||||
}
|
||||
|
||||
@@ -6808,6 +6829,27 @@ static bool project_texture_mapping_zone_to_regions(ModelObject &obj
|
||||
if (tri_idx < rgb_depths.size())
|
||||
target_depth = std::max(target_depth, rgb_depths[tri_idx]);
|
||||
target_depth = std::clamp(target_depth, 0, 7);
|
||||
target_depth = std::min(target_depth,
|
||||
texture_mapping_depth_from_span(transformed_triangle_max_edge_length(world_matrix, vertices),
|
||||
IMAGE_PROJECTION_REGION_TARGET_EDGE_MM,
|
||||
7));
|
||||
|
||||
const ProjectionRegionTrianglePredicate fully_projected_subtriangle =
|
||||
[&context,
|
||||
&world_matrix,
|
||||
pass_through_model,
|
||||
volume_idx,
|
||||
tri_idx,
|
||||
&visibility,
|
||||
&paintable_mask](const std::array<Vec3f, 3> &sub_vertices) {
|
||||
return projection_region_triangle_is_fully_projected(context,
|
||||
visibility,
|
||||
paintable_mask,
|
||||
world_matrix,
|
||||
sub_vertices,
|
||||
projection_visibility_triangle_key(volume_idx, tri_idx),
|
||||
pass_through_model);
|
||||
};
|
||||
|
||||
const size_t bitstream_start = new_data.bitstream.size();
|
||||
new_data.triangles_to_split.emplace_back(int(tri_idx), int(bitstream_start));
|
||||
@@ -6817,7 +6859,9 @@ static bool project_texture_mapping_zone_to_regions(ModelObject &obj
|
||||
vertices,
|
||||
root_barycentrics,
|
||||
0,
|
||||
target_depth)) {
|
||||
target_depth,
|
||||
fully_projected_subtriangle,
|
||||
texture_mapping_filament_id)) {
|
||||
new_data.triangles_to_split.pop_back();
|
||||
new_data.bitstream.resize(bitstream_start);
|
||||
}
|
||||
@@ -13123,6 +13167,7 @@ void GLGizmoMmuSegmentation::update_model_object()
|
||||
const ModelObjectPtrs &mos = wxGetApp().model().objects;
|
||||
size_t obj_idx = std::find(mos.begin(), mos.end(), mo) - mos.begin();
|
||||
wxGetApp().obj_list()->update_info_items(obj_idx);
|
||||
wxGetApp().sidebar().update_texture_mapping_panel(false);
|
||||
wxGetApp().plater()->get_partplate_list().notify_instance_update(obj_idx, 0);
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
@@ -18536,6 +18581,7 @@ bool GLGizmoImageProjection::project_to_rgb_data(ModelObject *object,
|
||||
void GLGizmoImageProjection::refresh_projected_object(ModelObject *object)
|
||||
{
|
||||
m_parent.update_volumes_colors_by_extruder();
|
||||
wxGetApp().sidebar().update_texture_mapping_panel(false);
|
||||
m_parent.set_as_dirty();
|
||||
m_parent.request_extra_frame();
|
||||
|
||||
@@ -18901,6 +18947,7 @@ void GLGizmoMmuSegmentation::remap_filament_assignments()
|
||||
wxGetApp().plater()->get_notification_manager()->push_notification(
|
||||
_L("Filament remapping finished.").ToStdString());
|
||||
update_model_object();
|
||||
wxGetApp().sidebar().update_texture_mapping_panel(false);
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1146,6 +1146,32 @@ private:
|
||||
bool m_radial_gradient { false };
|
||||
};
|
||||
|
||||
class TextureMappingUsageDot : public wxPanel
|
||||
{
|
||||
public:
|
||||
explicit TextureMappingUsageDot(wxWindow *parent)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, from_dip_for_parent(parent, wxSize(10, 10)), wxBORDER_NONE)
|
||||
{
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
SetMinSize(wxSize(FromDIP(10), FromDIP(10)));
|
||||
SetMaxSize(wxSize(FromDIP(10), FromDIP(10)));
|
||||
Bind(wxEVT_PAINT, &TextureMappingUsageDot::on_paint, this);
|
||||
}
|
||||
|
||||
private:
|
||||
void on_paint(wxPaintEvent &)
|
||||
{
|
||||
wxAutoBufferedPaintDC dc(this);
|
||||
dc.SetBackground(wxBrush(GetBackgroundColour()));
|
||||
dc.Clear();
|
||||
const wxSize size = GetClientSize();
|
||||
const int radius = std::max(2, std::min(size.x, size.y) / 2 - FromDIP(1));
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(wxBrush(wxColour(0, 122, 255)));
|
||||
dc.DrawCircle(wxPoint(size.x / 2, size.y / 2), radius);
|
||||
}
|
||||
};
|
||||
|
||||
class LinearGradientStopsBar : public wxPanel
|
||||
{
|
||||
public:
|
||||
@@ -7282,6 +7308,36 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
return object_idxs;
|
||||
};
|
||||
|
||||
const std::set<unsigned int> selected_texture_mapping_zone_ids = [this, &selected_texture_mapping_object_idxs, mgr_ptr]() {
|
||||
std::set<unsigned int> zone_ids;
|
||||
if (p->plater == nullptr || mgr_ptr == nullptr)
|
||||
return zone_ids;
|
||||
const Model &model = p->plater->model();
|
||||
auto add_zone_id = [&zone_ids, mgr_ptr](int filament_id) {
|
||||
if (filament_id > 0 && mgr_ptr->is_texture_mapping_zone_id(unsigned(filament_id)))
|
||||
zone_ids.insert(unsigned(filament_id));
|
||||
};
|
||||
for (const size_t obj_idx : selected_texture_mapping_object_idxs()) {
|
||||
if (obj_idx >= model.objects.size() || model.objects[obj_idx] == nullptr)
|
||||
continue;
|
||||
const ModelObject *object = model.objects[obj_idx];
|
||||
if (const ConfigOption *opt = object->config.option("extruder"); opt != nullptr)
|
||||
add_zone_id(opt->getInt());
|
||||
for (const ModelVolume *volume : object->volumes) {
|
||||
if (volume == nullptr || !volume->is_model_part())
|
||||
continue;
|
||||
add_zone_id(volume->extruder_id());
|
||||
if (volume->mmu_segmentation_facets.empty())
|
||||
continue;
|
||||
const std::vector<bool> &used_states = volume->mmu_segmentation_facets.get_data().used_states;
|
||||
for (size_t state_idx = 1; state_idx < used_states.size(); ++state_idx)
|
||||
if (used_states[state_idx])
|
||||
add_zone_id(int(state_idx));
|
||||
}
|
||||
}
|
||||
return zone_ids;
|
||||
}();
|
||||
|
||||
auto texture_mapping_zone_affects_scene = [print_cfg](unsigned int zone_id) {
|
||||
const Plater *plater = wxGetApp().plater();
|
||||
return plater != nullptr && model_uses_texture_mapping_zone_id(plater->model(), print_cfg, zone_id);
|
||||
@@ -7317,13 +7373,29 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
swatch->set_data(parse_texture_mapping_color(entry.display_color), zone_id);
|
||||
header_sizer->Add(swatch, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
|
||||
auto *title = new wxStaticText(header, wxID_ANY, _L("Texture Mapping"));
|
||||
title->SetForegroundColour(text_fg);
|
||||
header_sizer->Add(title, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
auto *label_panel = new wxPanel(header, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
|
||||
label_panel->SetBackgroundColour(row_bg);
|
||||
auto *label_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
label_panel->SetSizer(label_sizer);
|
||||
|
||||
auto *summary = new wxStaticText(header, wxID_ANY, texture_mapping_summary(entry, num_physical));
|
||||
auto *title = new wxStaticText(label_panel, wxID_ANY, _L("Texture Mapping"));
|
||||
title->SetForegroundColour(text_fg);
|
||||
label_sizer->Add(title, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto *summary = new wxStaticText(label_panel, wxID_ANY, texture_mapping_summary(entry, num_physical));
|
||||
summary->SetForegroundColour(summary_fg);
|
||||
header_sizer->Add(summary, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
label_sizer->Add(summary, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
|
||||
TextureMappingUsageDot *usage_dot = nullptr;
|
||||
if (selected_texture_mapping_zone_ids.count(zone_id) != 0) {
|
||||
usage_dot = new TextureMappingUsageDot(label_panel);
|
||||
usage_dot->SetBackgroundColour(row_bg);
|
||||
usage_dot->SetToolTip(_L("Used by selected objects"));
|
||||
label_sizer->Add(usage_dot, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, std::max(FromDIP(2), gap / 2));
|
||||
}
|
||||
|
||||
label_sizer->AddStretchSpacer();
|
||||
header_sizer->Add(label_panel, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, gap);
|
||||
|
||||
auto *menu_btn = new ScalableButton(header, wxID_ANY, "menu_filament");
|
||||
menu_btn->SetToolTip(_L("Texture map actions"));
|
||||
@@ -8437,7 +8509,9 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
win->Bind(wxEVT_LEFT_UP, [toggle_editor](wxMouseEvent &) { toggle_editor(); });
|
||||
};
|
||||
bind_toggle(header);
|
||||
bind_toggle(label_panel);
|
||||
bind_toggle(title);
|
||||
bind_toggle(usage_dot);
|
||||
bind_toggle(summary);
|
||||
bind_toggle(swatch);
|
||||
bind_toggle(preview);
|
||||
@@ -8484,8 +8558,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
const unsigned int zone_id = rows[zone_index].zone_id;
|
||||
if (zone_id == 0 || obj_list() == nullptr)
|
||||
return;
|
||||
if (obj_list()->assign_extruder_to_objects(object_idxs, int(zone_id), evt.GetId() == assign_selected_objects_erase_id))
|
||||
if (obj_list()->assign_extruder_to_objects(object_idxs, int(zone_id), evt.GetId() == assign_selected_objects_erase_id)) {
|
||||
refresh_texture_mapping_preview();
|
||||
CallAfter([this]() { update_texture_mapping_panel(false); });
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (evt.GetId() == duplicate_id) {
|
||||
@@ -12184,6 +12260,9 @@ void Plater::priv::selection_changed()
|
||||
} else {
|
||||
view3D->render();
|
||||
}
|
||||
|
||||
if (sidebar != nullptr)
|
||||
sidebar->update_texture_mapping_panel(false);
|
||||
}
|
||||
|
||||
void Plater::priv::object_list_changed()
|
||||
@@ -12210,6 +12289,8 @@ void Plater::priv::select_curr_plate_all()
|
||||
{
|
||||
view3D->select_curr_plate_all();
|
||||
this->sidebar->obj_list()->update_selections();
|
||||
if (sidebar != nullptr)
|
||||
sidebar->update_texture_mapping_panel(false);
|
||||
}
|
||||
|
||||
void Plater::priv::remove_curr_plate_all()
|
||||
@@ -12223,6 +12304,8 @@ void Plater::priv::select_all()
|
||||
{
|
||||
view3D->select_all();
|
||||
this->sidebar->obj_list()->update_selections();
|
||||
if (sidebar != nullptr)
|
||||
sidebar->update_texture_mapping_panel(false);
|
||||
}
|
||||
|
||||
void Plater::priv::deselect_all()
|
||||
@@ -16622,6 +16705,8 @@ void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bo
|
||||
this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot);
|
||||
|
||||
wxGetApp().obj_list()->update_after_undo_redo();
|
||||
if (sidebar != nullptr)
|
||||
sidebar->update_texture_mapping_panel(false);
|
||||
|
||||
if (wxGetApp().get_mode() == comSimple && model_has_advanced_features(this->model)) {
|
||||
// If the user jumped to a snapshot that require user interface with advanced features, switch to the advanced mode without asking.
|
||||
|
||||
Reference in New Issue
Block a user