Add QuadriFlow remesher
This commit is contained in:
@@ -39,6 +39,14 @@ struct Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLeve
|
||||
bool relax_disoriented_triangles);
|
||||
#endif
|
||||
struct Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(struct Mesh *mesh, float voxel_size);
|
||||
struct Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(struct Mesh *mesh,
|
||||
int target_faces,
|
||||
int seed,
|
||||
bool preserve_sharp,
|
||||
bool preserve_boundary,
|
||||
bool adaptive_scale,
|
||||
void *update_cb,
|
||||
void *update_cb_data);
|
||||
|
||||
/* Data reprojection functions */
|
||||
void BKE_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source);
|
||||
|
||||
@@ -620,6 +620,16 @@ if(WITH_OPENVDB)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_QUADRIFLOW)
|
||||
list(APPEND INC
|
||||
../../../intern/quadriflow
|
||||
)
|
||||
list(APPEND LIB
|
||||
bf_intern_quadriflow
|
||||
)
|
||||
add_definitions(-DWITH_QUADRIFLOW)
|
||||
endif()
|
||||
|
||||
## Warnings as errors, this is too strict!
|
||||
#if(MSVC)
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
# include "openvdb_capi.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_QUADRIFLOW
|
||||
# include "quadriflow_capi.hpp"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_OPENVDB
|
||||
struct OpenVDBLevelSet *BKE_mesh_remesh_voxel_ovdb_mesh_to_level_set_create(
|
||||
Mesh *mesh, struct OpenVDBTransform *transform)
|
||||
@@ -146,6 +150,148 @@ Mesh *BKE_mesh_remesh_voxel_ovdb_volume_to_mesh_nomain(struct OpenVDBLevelSet *l
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_QUADRIFLOW
|
||||
static Mesh *BKE_mesh_remesh_quadriflow(Mesh *input_mesh,
|
||||
int target_faces,
|
||||
int seed,
|
||||
bool preserve_sharp,
|
||||
bool preserve_boundary,
|
||||
bool adaptive_scale,
|
||||
void *update_cb,
|
||||
void *update_cb_data)
|
||||
{
|
||||
/* Ensure that the triangulated mesh data is up to data */
|
||||
BKE_mesh_runtime_looptri_recalc(input_mesh);
|
||||
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(input_mesh);
|
||||
|
||||
/* Gather the required data for export to the internal quadiflow mesh format */
|
||||
MVertTri *verttri = MEM_callocN(sizeof(*verttri) * BKE_mesh_runtime_looptri_len(input_mesh),
|
||||
"remesh_looptri");
|
||||
BKE_mesh_runtime_verttri_from_looptri(
|
||||
verttri, input_mesh->mloop, looptri, BKE_mesh_runtime_looptri_len(input_mesh));
|
||||
|
||||
unsigned int totfaces = BKE_mesh_runtime_looptri_len(input_mesh);
|
||||
unsigned int totverts = input_mesh->totvert;
|
||||
float *verts = (float *)MEM_malloc_arrayN(totverts * 3, sizeof(float), "remesh_input_verts");
|
||||
unsigned int *faces = (unsigned int *)MEM_malloc_arrayN(
|
||||
totfaces * 3, sizeof(unsigned int), "remesh_intput_faces");
|
||||
|
||||
for (unsigned int i = 0; i < totverts; i++) {
|
||||
MVert *mvert = &input_mesh->mvert[i];
|
||||
verts[i * 3] = mvert->co[0];
|
||||
verts[i * 3 + 1] = mvert->co[1];
|
||||
verts[i * 3 + 2] = mvert->co[2];
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < totfaces; i++) {
|
||||
MVertTri *vt = &verttri[i];
|
||||
faces[i * 3] = vt->tri[0];
|
||||
faces[i * 3 + 1] = vt->tri[1];
|
||||
faces[i * 3 + 2] = vt->tri[2];
|
||||
}
|
||||
|
||||
/* Fill out the required input data */
|
||||
QuadriflowRemeshData qrd;
|
||||
|
||||
qrd.totfaces = totfaces;
|
||||
qrd.totverts = totverts;
|
||||
qrd.verts = verts;
|
||||
qrd.faces = faces;
|
||||
qrd.target_faces = target_faces;
|
||||
|
||||
qrd.preserve_sharp = preserve_sharp;
|
||||
qrd.preserve_boundary = preserve_boundary;
|
||||
qrd.adaptive_scale = adaptive_scale;
|
||||
qrd.minimum_cost_flow = 0;
|
||||
qrd.aggresive_sat = 0;
|
||||
qrd.rng_seed = seed;
|
||||
|
||||
qrd.out_faces = NULL;
|
||||
|
||||
/* Run the remesher */
|
||||
QFLOW_quadriflow_remesh(&qrd, update_cb, update_cb_data);
|
||||
|
||||
MEM_freeN(verts);
|
||||
MEM_freeN(faces);
|
||||
MEM_freeN(verttri);
|
||||
|
||||
if (qrd.out_faces == NULL) {
|
||||
/* The remeshing was canceled */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qrd.out_totfaces == 0) {
|
||||
/* Meshing failed */
|
||||
MEM_freeN(qrd.out_faces);
|
||||
MEM_freeN(qrd.out_verts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Construct the new output mesh */
|
||||
Mesh *mesh = BKE_mesh_new_nomain(
|
||||
qrd.out_totverts, 0, 0, (qrd.out_totfaces * 4), qrd.out_totfaces);
|
||||
|
||||
for (int i = 0; i < qrd.out_totverts; i++) {
|
||||
copy_v3_v3(mesh->mvert[i].co, &qrd.out_verts[i * 3]);
|
||||
}
|
||||
|
||||
MPoly *mp = mesh->mpoly;
|
||||
MLoop *ml = mesh->mloop;
|
||||
for (int i = 0; i < qrd.out_totfaces; i++, mp++, ml += 4) {
|
||||
mp->loopstart = (int)(ml - mesh->mloop);
|
||||
mp->totloop = 4;
|
||||
|
||||
ml[0].v = qrd.out_faces[i * 4];
|
||||
ml[1].v = qrd.out_faces[i * 4 + 1];
|
||||
ml[2].v = qrd.out_faces[i * 4 + 2];
|
||||
ml[3].v = qrd.out_faces[i * 4 + 3];
|
||||
}
|
||||
|
||||
BKE_mesh_calc_edges(mesh, false, false);
|
||||
BKE_mesh_calc_normals(mesh);
|
||||
|
||||
MEM_freeN(qrd.out_faces);
|
||||
MEM_freeN(qrd.out_verts);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
#endif
|
||||
|
||||
Mesh *BKE_mesh_remesh_quadriflow_to_mesh_nomain(Mesh *mesh,
|
||||
int target_faces,
|
||||
int seed,
|
||||
bool preserve_sharp,
|
||||
bool preserve_boundary,
|
||||
bool adaptive_scale,
|
||||
void *update_cb,
|
||||
void *update_cb_data)
|
||||
{
|
||||
Mesh *new_mesh = NULL;
|
||||
#ifdef WITH_QUADRIFLOW
|
||||
if (target_faces <= 0) {
|
||||
target_faces = -1;
|
||||
}
|
||||
new_mesh = BKE_mesh_remesh_quadriflow(mesh,
|
||||
target_faces,
|
||||
seed,
|
||||
preserve_sharp,
|
||||
preserve_boundary,
|
||||
adaptive_scale,
|
||||
update_cb,
|
||||
update_cb_data);
|
||||
#else
|
||||
UNUSED_VARS(mesh,
|
||||
target_faces,
|
||||
seed,
|
||||
preserve_sharp,
|
||||
preserve_boundary,
|
||||
adaptive_scale,
|
||||
update_cb,
|
||||
update_cb_data);
|
||||
#endif
|
||||
return new_mesh;
|
||||
}
|
||||
|
||||
Mesh *BKE_mesh_remesh_voxel_to_mesh_nomain(Mesh *mesh, float voxel_size)
|
||||
{
|
||||
Mesh *new_mesh = NULL;
|
||||
|
||||
@@ -281,6 +281,7 @@ void TRANSFORM_OT_vertex_random(struct wmOperatorType *ot);
|
||||
|
||||
/* object_remesh.c */
|
||||
void OBJECT_OT_voxel_remesh(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_quadriflow_remesh(struct wmOperatorType *ot);
|
||||
|
||||
/* object_transfer_data.c */
|
||||
void OBJECT_OT_data_transfer(struct wmOperatorType *ot);
|
||||
|
||||
@@ -259,6 +259,7 @@ void ED_operatortypes_object(void)
|
||||
WM_operatortype_append(OBJECT_OT_hide_collection);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_voxel_remesh);
|
||||
WM_operatortype_append(OBJECT_OT_quadriflow_remesh);
|
||||
}
|
||||
|
||||
void ED_operatormacros_object(void)
|
||||
|
||||
@@ -88,7 +88,6 @@ static bool object_remesh_poll(bContext *C)
|
||||
static int voxel_remesh_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
Main *bmain = CTX_data_main(C);
|
||||
|
||||
Mesh *mesh = ob->data;
|
||||
Mesh *new_mesh;
|
||||
@@ -134,7 +133,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
|
||||
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
|
||||
DEG_relations_tag_update(bmain);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
|
||||
|
||||
@@ -156,3 +154,391 @@ void OBJECT_OT_voxel_remesh(wmOperatorType *ot)
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
enum {
|
||||
QUADRIFLOW_REMESH_RATIO = 1,
|
||||
QUADRIFLOW_REMESH_EDGE_LENGTH,
|
||||
QUADRIFLOW_REMESH_FACES,
|
||||
};
|
||||
|
||||
/****************** quadriflow remesh operator *********************/
|
||||
|
||||
typedef struct QuadriFlowJob {
|
||||
/* from wmJob */
|
||||
struct Object *owner;
|
||||
short *stop, *do_update;
|
||||
float *progress;
|
||||
|
||||
int target_faces;
|
||||
int seed;
|
||||
bool use_preserve_sharp;
|
||||
bool use_preserve_boundary;
|
||||
bool use_mesh_curvature;
|
||||
|
||||
bool preserve_paint_mask;
|
||||
bool smooth_normals;
|
||||
|
||||
int success;
|
||||
} QuadriFlowJob;
|
||||
|
||||
static void quadriflow_free_job(void *customdata)
|
||||
{
|
||||
QuadriFlowJob *qj = customdata;
|
||||
MEM_freeN(qj);
|
||||
}
|
||||
|
||||
/* called by quadriflowjob, only to check job 'stop' value */
|
||||
static int quadriflow_break_job(void *customdata)
|
||||
{
|
||||
QuadriFlowJob *qj = (QuadriFlowJob *)customdata;
|
||||
// return *(qj->stop);
|
||||
|
||||
/* this is not nice yet, need to make the jobs list template better
|
||||
* for identifying/acting upon various different jobs */
|
||||
/* but for now we'll reuse the render break... */
|
||||
bool should_break = (G.is_break);
|
||||
|
||||
if (should_break) {
|
||||
qj->success = -1;
|
||||
}
|
||||
|
||||
return should_break;
|
||||
}
|
||||
|
||||
/* called by oceanbake, wmJob sends notifier */
|
||||
static void quadriflow_update_job(void *customdata, float progress, int *cancel)
|
||||
{
|
||||
QuadriFlowJob *qj = customdata;
|
||||
|
||||
if (quadriflow_break_job(qj)) {
|
||||
*cancel = 1;
|
||||
}
|
||||
else {
|
||||
*cancel = 0;
|
||||
}
|
||||
|
||||
*(qj->do_update) = true;
|
||||
*(qj->progress) = progress;
|
||||
}
|
||||
|
||||
static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
|
||||
{
|
||||
QuadriFlowJob *qj = customdata;
|
||||
|
||||
qj->stop = stop;
|
||||
qj->do_update = do_update;
|
||||
qj->progress = progress;
|
||||
qj->success = 1;
|
||||
|
||||
G.is_break = false; /* XXX shared with render - replace with job 'stop' switch */
|
||||
|
||||
Object *ob = qj->owner;
|
||||
Mesh *mesh = ob->data;
|
||||
Mesh *new_mesh;
|
||||
|
||||
new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(mesh,
|
||||
qj->target_faces,
|
||||
qj->seed,
|
||||
qj->use_preserve_sharp,
|
||||
qj->use_preserve_boundary,
|
||||
qj->use_mesh_curvature,
|
||||
quadriflow_update_job,
|
||||
(void *)qj);
|
||||
|
||||
if (!new_mesh) {
|
||||
*do_update = true;
|
||||
*stop = 0;
|
||||
if (qj->success == 1) {
|
||||
/* This is not a user cancelation event */
|
||||
qj->success = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (ob->mode == OB_MODE_SCULPT) {
|
||||
ED_sculpt_undo_geometry_begin(ob);
|
||||
}
|
||||
|
||||
Mesh *obj_mesh_copy = NULL;
|
||||
if (qj->preserve_paint_mask) {
|
||||
obj_mesh_copy = BKE_mesh_new_nomain_from_template(mesh, mesh->totvert, 0, 0, 0, 0);
|
||||
CustomData_copy(
|
||||
&mesh->vdata, &obj_mesh_copy->vdata, CD_MASK_MESH.vmask, CD_DUPLICATE, mesh->totvert);
|
||||
for (int i = 0; i < mesh->totvert; i++) {
|
||||
copy_v3_v3(obj_mesh_copy->mvert[i].co, mesh->mvert[i].co);
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
|
||||
|
||||
if (qj->preserve_paint_mask) {
|
||||
BKE_remesh_reproject_paint_mask(mesh, obj_mesh_copy);
|
||||
BKE_mesh_free(obj_mesh_copy);
|
||||
}
|
||||
|
||||
if (qj->smooth_normals) {
|
||||
BKE_mesh_smooth_flag_set(ob->data, true);
|
||||
}
|
||||
|
||||
if (ob->mode == OB_MODE_SCULPT) {
|
||||
ED_sculpt_undo_geometry_end(ob);
|
||||
}
|
||||
|
||||
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
|
||||
|
||||
*do_update = true;
|
||||
*stop = 0;
|
||||
}
|
||||
|
||||
static void quadriflow_end_job(void *customdata)
|
||||
{
|
||||
QuadriFlowJob *qj = customdata;
|
||||
|
||||
Object *ob = qj->owner;
|
||||
|
||||
WM_set_locked_interface(G_MAIN->wm.first, false);
|
||||
|
||||
if (qj->success > 0) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
WM_reportf(RPT_INFO, "QuadriFlow: Completed remeshing!");
|
||||
}
|
||||
else {
|
||||
if (qj->success == 0) {
|
||||
WM_reportf(RPT_ERROR, "QuadriFlow: remeshing failed!");
|
||||
}
|
||||
else {
|
||||
WM_report(RPT_WARNING, "QuadriFlow: remeshing canceled!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
|
||||
|
||||
job->owner = CTX_data_active_object(C);
|
||||
|
||||
job->target_faces = RNA_int_get(op->ptr, "target_faces");
|
||||
job->seed = RNA_int_get(op->ptr, "seed");
|
||||
|
||||
job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
|
||||
job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
|
||||
|
||||
job->use_mesh_curvature = RNA_boolean_get(op->ptr, "use_mesh_curvature");
|
||||
|
||||
job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
|
||||
job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
|
||||
|
||||
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
|
||||
CTX_wm_window(C),
|
||||
CTX_data_scene(C),
|
||||
"QuadriFlow Remesh",
|
||||
WM_JOB_PROGRESS,
|
||||
WM_JOB_TYPE_QUADRIFLOW_REMESH);
|
||||
|
||||
WM_jobs_customdata_set(wm_job, job, quadriflow_free_job);
|
||||
WM_jobs_timer(wm_job, 0.1, NC_GEOM | ND_DATA, NC_GEOM | ND_DATA);
|
||||
WM_jobs_callbacks(wm_job, quadriflow_start_job, NULL, NULL, quadriflow_end_job);
|
||||
|
||||
WM_set_locked_interface(CTX_wm_manager(C), true);
|
||||
|
||||
WM_jobs_start(CTX_wm_manager(C), wm_job);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static bool quadriflow_check(bContext *C, wmOperator *op)
|
||||
{
|
||||
int mode = RNA_enum_get(op->ptr, "mode");
|
||||
|
||||
if (mode == QUADRIFLOW_REMESH_EDGE_LENGTH) {
|
||||
float area = RNA_float_get(op->ptr, "mesh_area");
|
||||
if (area < 0.0f) {
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
area = BKE_mesh_calc_area(ob->data);
|
||||
RNA_float_set(op->ptr, "mesh_area", area);
|
||||
}
|
||||
int num_faces;
|
||||
float edge_len = RNA_float_get(op->ptr, "target_edge_length");
|
||||
|
||||
num_faces = area / (edge_len * edge_len);
|
||||
RNA_int_set(op->ptr, "target_faces", num_faces);
|
||||
}
|
||||
else if (mode == QUADRIFLOW_REMESH_RATIO) {
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
Mesh *mesh = ob->data;
|
||||
|
||||
int num_faces;
|
||||
float ratio = RNA_float_get(op->ptr, "target_ratio");
|
||||
|
||||
num_faces = mesh->totpoly * ratio;
|
||||
|
||||
RNA_int_set(op->ptr, "target_faces", num_faces);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Hide the target variables if they are not active */
|
||||
static bool quadriflow_poll_property(const bContext *C, wmOperator *op, const PropertyRNA *prop)
|
||||
{
|
||||
const char *prop_id = RNA_property_identifier(prop);
|
||||
|
||||
if (STRPREFIX(prop_id, "target")) {
|
||||
int mode = RNA_enum_get(op->ptr, "mode");
|
||||
|
||||
if (STREQ(prop_id, "target_edge_length") && mode != QUADRIFLOW_REMESH_EDGE_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
else if (STREQ(prop_id, "target_faces")) {
|
||||
if (mode != QUADRIFLOW_REMESH_FACES) {
|
||||
/* Make sure we can edit the target_faces value even if it doesn't start as EDITABLE */
|
||||
float area = RNA_float_get(op->ptr, "mesh_area");
|
||||
if (area < -0.8f) {
|
||||
area += 0.2f;
|
||||
/* Make sure we have up to date values from the start */
|
||||
RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
|
||||
quadriflow_check((bContext *)C, op);
|
||||
}
|
||||
|
||||
/* Only disable input */
|
||||
RNA_def_property_clear_flag((PropertyRNA *)prop, PROP_EDITABLE);
|
||||
}
|
||||
else {
|
||||
RNA_def_property_flag((PropertyRNA *)prop, PROP_EDITABLE);
|
||||
}
|
||||
}
|
||||
else if (STREQ(prop_id, "target_ratio") && mode != QUADRIFLOW_REMESH_RATIO) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const EnumPropertyItem mode_type_items[] = {
|
||||
{QUADRIFLOW_REMESH_RATIO,
|
||||
"RATIO",
|
||||
0,
|
||||
"Ratio",
|
||||
"Specify target number of faces relative to the current mesh"},
|
||||
{QUADRIFLOW_REMESH_EDGE_LENGTH,
|
||||
"EDGE",
|
||||
0,
|
||||
"Edge Length",
|
||||
"Input target edge length in the new mesh"},
|
||||
{QUADRIFLOW_REMESH_FACES, "FACES", 0, "Faces", "Input target number of faces in the new mesh"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "QuadriFlow Remesh";
|
||||
ot->description =
|
||||
"Create a new quad based mesh using the surface data of the current mesh. All data "
|
||||
"layers will be lost";
|
||||
ot->idname = "OBJECT_OT_quadriflow_remesh";
|
||||
|
||||
/* api callbacks */
|
||||
ot->poll = object_remesh_poll;
|
||||
ot->poll_property = quadriflow_poll_property;
|
||||
ot->check = quadriflow_check;
|
||||
ot->invoke = WM_operator_props_popup_confirm;
|
||||
ot->exec = quadriflow_remesh_exec;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* properties */
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_preserve_sharp",
|
||||
false,
|
||||
"Preserve Sharp",
|
||||
"Try to preserve sharp features on the mesh");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_preserve_boundary",
|
||||
false,
|
||||
"Preserve Mesh Boundary",
|
||||
"Try to preserve mesh boundary on the mesh");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"use_mesh_curvature",
|
||||
false,
|
||||
"Use Mesh Curvature",
|
||||
"Take the mesh curvature into account when remeshing");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"preserve_paint_mask",
|
||||
false,
|
||||
"Preserve Paint Mask",
|
||||
"Reproject the paint mask onto the new mesh");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"smooth_normals",
|
||||
false,
|
||||
"Smooth Normals",
|
||||
"Set the output mesh normals to smooth");
|
||||
|
||||
RNA_def_enum(ot->srna,
|
||||
"mode",
|
||||
mode_type_items,
|
||||
0,
|
||||
"Mode",
|
||||
"How to specify the amount of detail for the new mesh");
|
||||
|
||||
prop = RNA_def_float(ot->srna,
|
||||
"target_ratio",
|
||||
1,
|
||||
0,
|
||||
FLT_MAX,
|
||||
"Ratio",
|
||||
"Relative number of faces compared to the current mesh",
|
||||
0.0f,
|
||||
1.0f);
|
||||
|
||||
prop = RNA_def_float(ot->srna,
|
||||
"target_edge_length",
|
||||
0.1f,
|
||||
0.0000001f,
|
||||
FLT_MAX,
|
||||
"Edge Length",
|
||||
"Target edge length in the new mesh",
|
||||
0.00001f,
|
||||
1.0f);
|
||||
|
||||
prop = RNA_def_int(ot->srna,
|
||||
"target_faces",
|
||||
1,
|
||||
1,
|
||||
INT_MAX,
|
||||
"Number of Faces",
|
||||
"Approximate number of faces (quads) in the new mesh",
|
||||
1,
|
||||
INT_MAX);
|
||||
|
||||
prop = RNA_def_float(
|
||||
ot->srna,
|
||||
"mesh_area",
|
||||
-1.0f,
|
||||
-FLT_MAX,
|
||||
FLT_MAX,
|
||||
"Old Object Face Area",
|
||||
"This property is only used to cache the object area for later calculations",
|
||||
0.0f,
|
||||
FLT_MAX);
|
||||
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||
|
||||
RNA_def_int(ot->srna,
|
||||
"seed",
|
||||
0,
|
||||
0,
|
||||
INT_MAX,
|
||||
"Seed",
|
||||
"Random seed to use with the solver. Different seeds will cause the remesher to "
|
||||
"come up with different quad layouts on the mesh",
|
||||
0,
|
||||
255);
|
||||
}
|
||||
|
||||
@@ -193,7 +193,8 @@ typedef struct Mesh {
|
||||
short totcol;
|
||||
|
||||
float remesh_voxel_size;
|
||||
char _pad1[4];
|
||||
char remesh_mode;
|
||||
char _pad1[3];
|
||||
/** Deprecated multiresolution modeling data, only keep for loading old files. */
|
||||
struct Multires *mr DNA_DEPRECATED;
|
||||
|
||||
@@ -261,6 +262,12 @@ enum {
|
||||
ME_CDFLAG_EDGE_CREASE = 1 << 2,
|
||||
};
|
||||
|
||||
/* me->remesh_mode */
|
||||
enum {
|
||||
REMESH_VOXEL = 0,
|
||||
REMESH_QUAD = 1,
|
||||
};
|
||||
|
||||
/* Subsurf Type */
|
||||
enum {
|
||||
ME_CC_SUBSURF = 0,
|
||||
|
||||
@@ -55,6 +55,12 @@ const EnumPropertyItem rna_enum_mesh_delimit_mode_items[] = {
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_mesh_remesh_mode_items[] = {
|
||||
{REMESH_VOXEL, "VOXEL", 0, "Voxel", "Use the voxel remesher"},
|
||||
{REMESH_QUAD, "QUAD", 0, "Quad", "Use the quad remesher"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
# include "DNA_scene_types.h"
|
||||
@@ -3012,6 +3018,13 @@ static void rna_def_mesh(BlenderRNA *brna)
|
||||
RNA_def_property_boolean_default(prop, false);
|
||||
RNA_def_property_ui_text(prop, "Preserve Paint Mask", "Keep the current mask on the new mesh");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
|
||||
|
||||
prop = RNA_def_property(srna, "remesh_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "remesh_mode");
|
||||
RNA_def_property_enum_items(prop, rna_enum_mesh_remesh_mode_items);
|
||||
RNA_def_property_ui_text(prop, "Remesh Mode", "");
|
||||
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
|
||||
|
||||
/* End remesh */
|
||||
|
||||
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
|
||||
|
||||
@@ -686,6 +686,7 @@ enum {
|
||||
WM_JOB_TYPE_STUDIOLIGHT,
|
||||
WM_JOB_TYPE_LIGHT_BAKE,
|
||||
WM_JOB_TYPE_FSMENU_BOOKMARK_VALIDATE,
|
||||
WM_JOB_TYPE_QUADRIFLOW_REMESH,
|
||||
/* add as needed, bake, seq proxy build
|
||||
* if having hard coded values is a problem */
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user