103{
104 struct OnExit
105 {
106 std::function<void()> fn;
107 ~OnExit() { if (fn) fn(); }
109
110 if (canceled || eptr)
111 return;
112
113
114
115
116
117
118 const auto moved = [this](size_t i) {
119 const TriangleMesh &result =
m_results[i].mesh;
120 if (result.empty())
121 return false;
122 const indexed_triangle_set &out = result.its;
123 const indexed_triangle_set &base =
m_input.volumes[i].base_mesh;
124 bool unchanged = out.indices.size() == base.indices.size() && out.vertices.size() == base.vertices.size();
125 for (size_t v = 0; unchanged && v < out.vertices.size(); ++v)
126 unchanged = (out.vertices[v] - base.vertices[v]).cwiseAbs().maxCoeff() < 1e-5f;
127 return !unchanged;
128 };
129
130 std::vector<size_t> to_commit;
131 for (
size_t i = 0; i <
m_results.size(); ++i)
132 if (moved(i))
133 to_commit.push_back(i);
134 if (to_commit.empty()) {
135 show_error(
nullptr,
_u8L(
"The bake produced no displacement, so nothing was changed and the paint was kept. "
136 "Check that the painted layer has a texture and a non-zero depth."));
137 return;
138 }
139
141
142
143
144
145
146
147
148 const auto filaments_for_palette = [
this,
plater, &to_commit]() {
149
150
151 std::vector<char> seen(
m_input.color.palette.size() + 1, 0);
152 std::vector<uint8_t> used;
153 for (const size_t i : to_commit)
154 for (
const uint8_t entry :
m_results[i].triangle_color)
155 if (entry > 0 && size_t(entry) < seen.size() && !seen[size_t(entry)]) {
156 seen[size_t(entry)] = 1;
157 used.push_back(entry);
158 }
161 m_input.color.palette, used, [&sidebar](
const PrintableColor &mix) {
162 return sidebar.ensure_mixed_filament({ unsigned(mix.a + 1), unsigned(mix.b + 1) },
163 { mix.a_percent(), 100 - mix.a_percent() });
164 });
165 };
166
167 const auto commit = [
this,
plater, &to_commit, &filaments_for_palette]() {
168 const std::vector<int> filament_of = filaments_for_palette();
169 ModelObject *object = nullptr;
170
171 for (const size_t i : to_commit) {
173
174
175
176 if (volume == nullptr)
177 continue;
178 const TextureDisplacementBakeVolume &input =
m_input.volumes[i];
179 const std::vector<uint8_t> &triangle_color =
m_results[i].triangle_color;
180
181
182
183
184
185
186
187
188 const bool topology_changed = input.options.pipeline_v2 ||
189 m_results[i].mesh.its.indices.size() != input.base_mesh.indices.size();
190
191
192
193
194
195
196
197
198
199
200
201 std::array<TriangleSelector::TriangleSplittingData, 4> before;
202 if (topology_changed) {
203 before[0] = volume->supported_facets.get_data();
204 before[1] = volume->seam_facets.get_data();
205 before[2] = volume->mmu_segmentation_facets.get_data();
206 before[3] = volume->fuzzy_skin_facets.get_data();
207 }
208
209 volume->set_mesh(std::move(
m_results[i].mesh));
210 volume->set_new_unique_id();
211 volume->calculate_convex_hull();
212
213 if (topology_changed) {
214 const std::array<FacetsAnnotation *, 4> target{ &volume->supported_facets, &volume->seam_facets,
215 &volume->mmu_segmentation_facets,
216 &volume->fuzzy_skin_facets };
217 for (size_t ch = 0; ch < target.size(); ++ch) {
218 const std::vector<uint8_t> state =
220
221
222 if (state.empty()) {
223 target[ch]->reset();
224 continue;
225 }
226 TriangleSelector selector(volume->mesh());
227 bool any = false;
228 for (size_t t = 0; t < state.size(); ++t)
229 if (state[t] != 0) {
231 any = true;
232 }
233 if (any)
234 target[ch]->set(selector);
235 else
236 target[ch]->reset();
237 }
238 }
239
240
241
242
243
244
245
246 if (!triangle_color.empty() && triangle_color.size() == volume->mesh().its.indices.size()) {
247 TriangleSelector selector(volume->mesh());
248 const TriangleSelector::TriangleSplittingData &existing = volume->mmu_segmentation_facets.get_data();
249 if (!existing.bitstream.empty())
250 selector.deserialize(existing, false);
251 for (size_t t = 0; t < triangle_color.size(); ++t) {
252 const size_t entry = size_t(triangle_color[t]);
253 if (entry > 0 && entry <= filament_of.size() && filament_of[entry - 1] >= 0)
255 }
256 volume->mmu_segmentation_facets.set(selector);
257 }
258
259
260
261
262
263
264
265
266
267
268
270 const auto it = std::find_if(input.layers.begin(), input.layers.end(),
271 [slot](const TextureDisplacementLayer &l) { return l.slot == slot; });
272 if (topology_changed || (it != input.layers.end() && !it->empty()))
273 volume->texture_displacement_facet(slot).reset();
274 }
275
276
277
278
279 if (!input.model_uv.empty())
280 volume->texture_uv = topology_changed ?
transfer_uv_channel(input.base_mesh, input.model_uv,
281 volume->mesh().its) :
282 input.model_uv;
283
284 if (object == nullptr)
285 object = volume->get_object();
286 }
287
288 if (object == nullptr)
289 return;
290
293 auto it = std::find(objs.begin(), objs.end(), object);
294 if (it != objs.end())
296 }
297
299 };
300
301
302
303
304
305
308 commit();
309 } else {
310 commit();
311 }
312
313
314
315
316
317
318 size_t refined = 0, budget = 0;
319 for (const size_t i : to_commit)
321 refined +=
m_results[i].stats.triangles_refined;
322 budget +=
m_results[i].stats.triangles_budget;
323 }
324 if (refined > 0) {
325
326 const auto count = [](
size_t n) {
327 return n >= 1000000 ?
Slic3r::format(
"%1$.1f M",
double(n) / 1000000.) :
328 Slic3r::
format(
"%1% k", (n + 500) / 1000);
329 };
330 wxGetApp().notification_manager()->push_notification(
332 Slic3r::format(
_u8L(
"The triangle budget limited the detail: this resolution needs %1% triangles, "
333 "the budget kept %2%. Raise Budget or use a coarser Resolution for the full detail."),
335 }
336}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
static std::vector< int > palette_filaments(const std::vector< PaletteEntry > &palette, const std::vector< uint8_t > &triangle_color, const std::function< int(const PaletteEntry &)> &slot_for_mix)
Definition GLGizmoTextureDisplacement.cpp:5995
@ WarningNotificationLevel
Definition NotificationManager.hpp:224
void update_info_items(size_t obj_idx, wxDataViewItemArray *selections=nullptr, bool added_object=false, bool color_mode_changed=false)
Definition GUI_ObjectList.cpp:4039
void changed_object(ModelObject &object)
Definition Plater.cpp:22227
const Model & model() const
Definition Plater.cpp:16047
Sidebar & sidebar()
Definition Plater.cpp:16046
std::vector< VolumeResult > m_results
Definition TextureDisplacementBakeJob.hpp:88
ModelObjectPtrs objects
Definition Model.hpp:1702
static ObjectList * obj_list()
Definition GUI_Factories.cpp:405
static Plater * plater()
Definition GUI_Factories.cpp:400
void show_error(wxWindow *parent, const wxString &message, bool has_code_excerpts)
Definition GUI.cpp:296
@ CustomNotification
Definition NotificationManager.hpp:66
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:36
static ModelVolume * get_model_volume(const Selection &selection, Model &model)
Definition GLGizmoBrimEars.cpp:66
@ ObjectList
Definition Shortcuts.hpp:21
@ Plater
Definition Shortcuts.hpp:21
@ GizmoAction
Definition UndoRedo.hpp:36
EnforcerBlockerType
Definition TriangleSelector.hpp:24
static constexpr size_t TEXTURE_DISPLACEMENT_MAX_LAYERS
Definition TextureDisplacement.hpp:44
std::vector< uint8_t > transfer_facet_paint(const indexed_triangle_set &src_mesh, const TriangleSelector::TriangleSplittingData &src_paint, const indexed_triangle_set &dst_mesh)
Definition TextureDisplacement.cpp:1902
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:45
std::vector< Vec2f > transfer_uv_channel(const indexed_triangle_set &src_mesh, const std::vector< Vec2f > &src_uv, const indexed_triangle_set &dst_mesh, float max_distance)
Definition TextureDisplacement.cpp:2126
std::vector< ModelObject * > ModelObjectPtrs
Definition CutUtils.hpp:13
#define _u8L(s)
Definition I18N.hpp:11