Blender V5.0
MOD_remesh.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 by Nicholas Bishop.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "MEM_guardedalloc.h"
10
11#include "BLI_math_base.h"
12#include "BLI_mutex.hh"
13#include "BLI_utildefines.h"
14
15#include "BLT_translation.hh"
16
17#include "DNA_defaults.h"
18#include "DNA_modifier_types.h"
19#include "DNA_screen_types.h"
20
21#include "BKE_mesh.hh"
23#include "BKE_mesh_runtime.hh"
24
26#include "UI_resources.hh"
27
28#include "RNA_access.hh"
29#include "RNA_prototypes.hh"
30
31#include "MOD_modifiertypes.hh"
32#include "MOD_ui_common.hh"
33
34#include "GEO_randomize.hh"
35
36#include <cstdlib>
37#include <cstring>
38
39#ifdef WITH_MOD_REMESH
40# include "BLI_math_vector.h"
41
42# include "dualcon.h"
43#endif
44
53
54#ifdef WITH_MOD_REMESH
55
56static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
57{
58 memset(input, 0, sizeof(DualConInput));
59
60 input->co = (DualConCo)mesh->vert_positions().data();
61 input->co_stride = sizeof(blender::float3);
62 input->totco = mesh->verts_num;
63
64 input->corner_verts = (DualConCornerVerts)mesh->corner_verts().data();
65 input->corner_verts_stride = sizeof(int);
66
67 input->corner_tris = (DualConTri)mesh->corner_tris().data();
68 input->tri_stride = sizeof(blender::int3);
70
71 const blender::Bounds<blender::float3> bounds = *mesh->bounds_min_max();
72 copy_v3_v3(input->min, bounds.min);
73 copy_v3_v3(input->max, bounds.max);
74}
75
76/* simple structure to hold the output: a CDDM and two counters to
77 * keep track of the current elements */
78struct DualConOutput {
79 Mesh *mesh;
80 blender::float3 *vert_positions;
81 int *face_offsets;
82 int *corner_verts;
83 int curvert, curface;
84};
85
86/* allocate and initialize a DualConOutput */
87static void *dualcon_alloc_output(int totvert, int totquad)
88{
89 DualConOutput *output = MEM_callocN<DualConOutput>(__func__);
90
91 if (!output) {
92 return nullptr;
93 }
94
95 output->mesh = BKE_mesh_new_nomain(totvert, 0, totquad, 4 * totquad);
96 output->vert_positions = output->mesh->vert_positions_for_write().data();
97 output->face_offsets = output->mesh->face_offsets_for_write().data();
98 output->corner_verts = output->mesh->corner_verts_for_write().data();
99
100 return output;
101}
102
103static void dualcon_add_vert(void *output_v, const float co[3])
104{
105 DualConOutput *output = static_cast<DualConOutput *>(output_v);
106
107 BLI_assert(output->curvert < output->mesh->verts_num);
108
109 copy_v3_v3(output->vert_positions[output->curvert], co);
110 output->curvert++;
111}
112
113static void dualcon_add_quad(void *output_v, const int vert_indices[4])
114{
115 DualConOutput *output = static_cast<DualConOutput *>(output_v);
116 Mesh *mesh = output->mesh;
117 int i;
118
119 BLI_assert(output->curface < mesh->faces_num);
120 UNUSED_VARS_NDEBUG(mesh);
121
122 output->face_offsets[output->curface] = output->curface * 4;
123 for (i = 0; i < 4; i++) {
124 output->corner_verts[output->curface * 4 + i] = vert_indices[i];
125 }
126
127 output->curface++;
128}
129
130static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
131{
132 using namespace blender;
134 Mesh *result;
135
136 if (rmd->mode == MOD_REMESH_VOXEL) {
137 /* OpenVDB modes. */
138 if (rmd->voxel_size == 0.0f) {
139 BKE_modifier_set_error(ctx->object, md, "Zero voxel size cannot be solved");
140 return nullptr;
141 }
142 result = BKE_mesh_remesh_voxel(mesh, rmd->voxel_size, rmd->adaptivity, 0.0f, ctx->object, md);
143 if (result == nullptr) {
144 return nullptr;
145 }
146 }
147 else {
148 if (rmd->scale == 0.0f) {
149 BKE_modifier_set_error(ctx->object, md, "Zero scale cannot be solved");
150 return nullptr;
151 }
152
153 DualConOutput *output;
155 DualConFlags flags = DualConFlags(0);
156 DualConMode mode = DualConMode(0);
157
158 /* Dualcon modes. */
159 init_dualcon_mesh(&input, mesh);
160
161 if (rmd->flag & MOD_REMESH_FLOOD_FILL) {
162 flags = DualConFlags(flags | DUALCON_FLOOD_FILL);
163 }
164
165 switch (rmd->mode) {
167 mode = DUALCON_CENTROID;
168 break;
170 mode = DUALCON_MASS_POINT;
171 break;
174 break;
175 case MOD_REMESH_VOXEL:
176 /* Should have been processed before as an OpenVDB operation. */
177 BLI_assert(false);
178 break;
179 }
180 /* TODO(jbakker): Dualcon crashes when run in parallel. Could be related to incorrect
181 * input data or that the library isn't thread safe.
182 * This was identified when changing the task isolation's during #76553. */
183 static blender::Mutex dualcon_mutex;
184 {
185 std::scoped_lock lock(dualcon_mutex);
186 output = static_cast<DualConOutput *>(dualcon(&input,
187 dualcon_alloc_output,
188 dualcon_add_vert,
189 dualcon_add_quad,
190 flags,
191 mode,
192 rmd->threshold,
193 rmd->hermite_num,
194 rmd->scale,
195 rmd->depth));
196 }
197 result = output->mesh;
199 }
200
202
204 bke::mesh_calc_edges(*result, true, false);
205
207
208 return result;
209}
210
211#else /* !WITH_MOD_REMESH */
212
213static Mesh *modify_mesh(ModifierData * /*md*/, const ModifierEvalContext * /*ctx*/, Mesh *mesh)
214{
215 return mesh;
216}
217
218#endif /* !WITH_MOD_REMESH */
219
220static void panel_draw(const bContext * /*C*/, Panel *panel)
221{
222 uiLayout *layout = panel->layout;
223#ifdef WITH_MOD_REMESH
224 uiLayout *row, *col;
225
226 PointerRNA ob_ptr;
228
229 int mode = RNA_enum_get(ptr, "mode");
230
231 layout->prop(ptr, "mode", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
232
233 layout->use_property_split_set(true);
234
235 col = &layout->column(false);
236 if (mode == MOD_REMESH_VOXEL) {
237 col->prop(ptr, "voxel_size", UI_ITEM_NONE, std::nullopt, ICON_NONE);
238 col->prop(ptr, "adaptivity", UI_ITEM_NONE, std::nullopt, ICON_NONE);
239 }
240 else {
241 col->prop(ptr, "octree_depth", UI_ITEM_NONE, std::nullopt, ICON_NONE);
242 col->prop(ptr, "scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
243
244 if (mode == MOD_REMESH_SHARP_FEATURES) {
245 col->prop(ptr, "sharpness", UI_ITEM_NONE, std::nullopt, ICON_NONE);
246 }
247
248 layout->prop(ptr, "use_remove_disconnected", UI_ITEM_NONE, std::nullopt, ICON_NONE);
249 row = &layout->row(false);
250 row->active_set(RNA_boolean_get(ptr, "use_remove_disconnected"));
251 layout->prop(ptr, "threshold", UI_ITEM_NONE, std::nullopt, ICON_NONE);
252 }
253 layout->prop(ptr, "use_smooth_shade", UI_ITEM_NONE, std::nullopt, ICON_NONE);
254
256
257#else /* WITH_MOD_REMESH */
258 layout->label(RPT_("Built without Remesh modifier"), ICON_NONE);
259#endif /* WITH_MOD_REMESH */
260}
261
262static void panel_register(ARegionType *region_type)
263{
265}
266
268 /*idname*/ "Remesh",
269 /*name*/ N_("Remesh"),
270 /*struct_name*/ "RemeshModifierData",
271 /*struct_size*/ sizeof(RemeshModifierData),
272 /*srna*/ &RNA_RemeshModifier,
276 /*icon*/ ICON_MOD_REMESH,
277
278 /*copy_data*/ BKE_modifier_copydata_generic,
279
280 /*deform_verts*/ nullptr,
281 /*deform_matrices*/ nullptr,
282 /*deform_verts_EM*/ nullptr,
283 /*deform_matrices_EM*/ nullptr,
284 /*modify_mesh*/ modify_mesh,
285 /*modify_geometry_set*/ nullptr,
286
287 /*init_data*/ init_data,
288 /*required_data_mask*/ nullptr,
289 /*free_data*/ nullptr,
290 /*is_disabled*/ nullptr,
291 /*update_depsgraph*/ nullptr,
292 /*depends_on_time*/ nullptr,
293 /*depends_on_normals*/ nullptr,
294 /*foreach_ID_link*/ nullptr,
295 /*foreach_tex_link*/ nullptr,
296 /*free_runtime_data*/ nullptr,
297 /*panel_register*/ panel_register,
298 /*blend_write*/ nullptr,
299 /*blend_read*/ nullptr,
300 /*foreach_cache*/ nullptr,
301 /*foreach_working_space_color*/ nullptr,
302};
void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src)
Mesh * BKE_mesh_new_nomain(int verts_num, int edges_num, int faces_num, int corners_num)
Mesh * BKE_mesh_remesh_voxel(const Mesh *mesh, float voxel_size, float adaptivity, float isovalue, const Object *object, ModifierData *modifier_data)
int BKE_mesh_runtime_corner_tris_len(const Mesh *mesh)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_AcceptsCVs
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void BKE_modifier_set_error(const Object *ob, ModifierData *md, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_assert(a)
Definition BLI_assert.h:46
MINLINE void copy_v3_v3(float r[3], const float a[3])
#define UNUSED_VARS_NDEBUG(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define RPT_(msgid)
#define DNA_struct_default_get(struct_name)
struct Mesh Mesh
@ MOD_REMESH_FLOOD_FILL
@ MOD_REMESH_SMOOTH_SHADING
@ MOD_REMESH_VOXEL
@ MOD_REMESH_MASS_POINT
@ MOD_REMESH_SHARP_FEATURES
@ MOD_REMESH_CENTROID
@ eModifierType_Remesh
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void panel_draw(const bContext *, Panel *panel)
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
Definition MOD_array.cc:862
static void init_data(ModifierData *md)
Definition MOD_remesh.cc:45
static void panel_register(ARegionType *region_type)
static void panel_draw(const bContext *, Panel *panel)
static Mesh * modify_mesh(ModifierData *, const ModifierEvalContext *, Mesh *mesh)
ModifierTypeInfo modifierType_Remesh
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
@ UI_ITEM_R_EXPAND
#define UI_ITEM_NONE
volatile int lock
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
DualConMode
Definition dualcon.h:45
@ DUALCON_SHARP_FEATURES
Definition dualcon.h:51
@ DUALCON_CENTROID
Definition dualcon.h:47
@ DUALCON_MASS_POINT
Definition dualcon.h:49
void * dualcon(const DualConInput *input_mesh, DualConAllocOutput alloc_output, DualConAddVert add_vert, DualConAddQuad add_quad, DualConFlags flags, DualConMode mode, float threshold, float hermite_num, float scale, int depth)
unsigned int(* DualConTri)[3]
Definition dualcon.h:14
float(* DualConCo)[3]
Definition dualcon.h:12
DualConFlags
Definition dualcon.h:41
@ DUALCON_FLOOD_FILL
Definition dualcon.h:42
unsigned int * DualConCornerVerts
Definition dualcon.h:16
uint col
#define input
#define output
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void mesh_smooth_set(Mesh &mesh, bool use_smooth, bool keep_sharp_edges=false)
void mesh_calc_edges(Mesh &mesh, bool keep_existing_edges, bool select_new_edges)
void debug_randomize_mesh_order(Mesh *mesh)
Definition randomize.cc:288
VecBase< int32_t, 3 > int3
std::mutex Mutex
Definition BLI_mutex.hh:47
VecBase< float, 3 > float3
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
int faces_num
int verts_num
struct uiLayout * layout
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void active_set(bool active)
uiLayout & row(bool align)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238