Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPablo Dobarro <pablodp606@gmail.com>2019-09-25 15:54:34 +0300
committerPablo Dobarro <pablodp606@gmail.com>2019-09-26 17:43:35 +0300
commite5c9bf3aa28af3d1edddecb909b5a95fe029e18e (patch)
tree99fa83ad3bb8f6980ee2dc21abc9509327e542a4 /source/blender/editors/object/object_remesh.c
parentb7f27996e7fcd514d76acb45a3199821988d7615 (diff)
Quadriflow: Symmetry support
This patch adds paint symmetry support to Quadriflow. It bisects and mirrors the input and the output from the remesher to build the final mesh using the preserve boundary option. This is also an important performance improvement in Quadriflow because it only needs to process half of the mesh with half the resolution. Reviewed By: jbakker Differential Revision: https://developer.blender.org/D5855
Diffstat (limited to 'source/blender/editors/object/object_remesh.c')
-rw-r--r--source/blender/editors/object/object_remesh.c121
1 files changed, 118 insertions, 3 deletions
diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c
index 6075867b552..f8ca3b268cc 100644
--- a/source/blender/editors/object/object_remesh.c
+++ b/source/blender/editors/object/object_remesh.c
@@ -40,10 +40,12 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
-#include "BKE_library.h"
+#include "BKE_mirror.h"
+#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_report.h"
@@ -170,14 +172,26 @@ enum {
/****************** quadriflow remesh operator *********************/
+#define QUADRIFLOW_MIRROR_BISECT_TOLERANCE 0.005f
+
+typedef enum eSymmetryAxes {
+ SYMMETRY_AXES_X = (1 << 0),
+ SYMMETRY_AXES_Y = (1 << 1),
+ SYMMETRY_AXES_Z = (1 << 2),
+} eSymmetryAxes;
+
typedef struct QuadriFlowJob {
/* from wmJob */
struct Object *owner;
+ struct Main *bmain;
short *stop, *do_update;
float *progress;
int target_faces;
int seed;
+ bool use_paint_symmetry;
+ eSymmetryAxes symmetry_axes;
+
bool use_preserve_sharp;
bool use_preserve_boundary;
bool use_mesh_curvature;
@@ -228,6 +242,66 @@ static void quadriflow_update_job(void *customdata, float progress, int *cancel)
*(qj->progress) = progress;
}
+static Mesh *remesh_symmetry_bisect(Main *bmain, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+
+ Mesh *mesh_bisect, *mesh_bisect_temp;
+ mesh_bisect = BKE_mesh_copy(bmain, mesh);
+
+ int axis;
+ float plane_co[3], plane_no[3];
+ zero_v3(plane_co);
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_BISECT_AXIS_X << i;
+ zero_v3(plane_no);
+ plane_no[axis] = -1.0f;
+ mesh_bisect_temp = mesh_bisect;
+ mesh_bisect = BKE_mirror_bisect_on_mirror_plane(&mmd, mesh_bisect, axis, plane_co, plane_no);
+ if (mesh_bisect_temp != mesh_bisect) {
+ BKE_id_free(bmain, mesh_bisect_temp);
+ }
+ }
+ }
+
+ BKE_id_free(bmain, mesh);
+
+ return mesh_bisect;
+}
+
+static Mesh *remesh_symmetry_mirror(Object *ob, Mesh *mesh, eSymmetryAxes symmetry_axes)
+{
+ MirrorModifierData mmd = {0};
+ mmd.tolerance = QUADRIFLOW_MIRROR_BISECT_TOLERANCE;
+ Mesh *mesh_mirror, *mesh_mirror_temp;
+
+ mesh_mirror = mesh;
+
+ int axis;
+
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (symmetry_axes & symm_it) {
+ axis = i;
+ mmd.flag = 0;
+ mmd.flag &= MOD_MIR_AXIS_X << i;
+ mesh_mirror_temp = mesh_mirror;
+ mesh_mirror = BKE_mirror_apply_mirror_on_axis(&mmd, NULL, ob, mesh_mirror, axis);
+ if (mesh_mirror_temp != mesh_mirror) {
+ BKE_id_free(NULL, mesh_mirror_temp);
+ }
+ }
+ }
+
+ return mesh_mirror;
+}
+
static void quadriflow_start_job(void *customdata, short *stop, short *do_update, float *progress)
{
QuadriFlowJob *qj = customdata;
@@ -242,16 +316,27 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
Object *ob = qj->owner;
Mesh *mesh = ob->data;
Mesh *new_mesh;
+ Mesh *bisect_mesh;
+
+ /* Run Quadriflow bisect operations on a copy of the mesh to keep the code readable without
+ * freeing the original ID */
+ bisect_mesh = BKE_mesh_copy(qj->bmain, mesh);
+
+ /* Bisect the input mesh using the paint symmetry settings */
+ bisect_mesh = remesh_symmetry_bisect(qj->bmain, bisect_mesh, qj->symmetry_axes);
- new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(mesh,
+ new_mesh = BKE_mesh_remesh_quadriflow_to_mesh_nomain(bisect_mesh,
qj->target_faces,
qj->seed,
qj->use_preserve_sharp,
- qj->use_preserve_boundary,
+ qj->use_preserve_boundary ||
+ qj->use_paint_symmetry,
qj->use_mesh_curvature,
quadriflow_update_job,
(void *)qj);
+ BKE_id_free(qj->bmain, bisect_mesh);
+
if (!new_mesh) {
*do_update = true;
*stop = 0;
@@ -262,6 +347,11 @@ static void quadriflow_start_job(void *customdata, short *stop, short *do_update
return;
}
+ /* Mirror the Quadriflow result to build the final mesh */
+ if (new_mesh) {
+ new_mesh = remesh_symmetry_mirror(qj->owner, new_mesh, qj->symmetry_axes);
+ }
+
if (ob->mode == OB_MODE_SCULPT) {
ED_sculpt_undo_geometry_begin(ob);
}
@@ -314,10 +404,13 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
QuadriFlowJob *job = MEM_mallocN(sizeof(QuadriFlowJob), "QuadriFlowJob");
job->owner = CTX_data_active_object(C);
+ job->bmain = CTX_data_main(C);
job->target_faces = RNA_int_get(op->ptr, "target_faces");
job->seed = RNA_int_get(op->ptr, "seed");
+ job->use_paint_symmetry = RNA_boolean_get(op->ptr, "use_paint_symmetry");
+
job->use_preserve_sharp = RNA_boolean_get(op->ptr, "use_preserve_sharp");
job->use_preserve_boundary = RNA_boolean_get(op->ptr, "use_preserve_boundary");
@@ -326,6 +419,22 @@ static int quadriflow_remesh_exec(bContext *C, wmOperator *op)
job->preserve_paint_mask = RNA_boolean_get(op->ptr, "preserve_paint_mask");
job->smooth_normals = RNA_boolean_get(op->ptr, "smooth_normals");
+ /* Update the target face count if symmetry is enabled */
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ if (sd && job->use_paint_symmetry) {
+ job->symmetry_axes = (eSymmetryAxes)(sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL);
+ for (char i = 0; i < 3; i++) {
+ eSymmetryAxes symm_it = (eSymmetryAxes)(1 << i);
+ if (job->symmetry_axes & symm_it) {
+ job->target_faces = job->target_faces / 2;
+ }
+ }
+ }
+ else {
+ job->use_paint_symmetry = false;
+ job->symmetry_axes = 0;
+ }
+
wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C),
CTX_wm_window(C),
CTX_data_scene(C),
@@ -450,6 +559,12 @@ void OBJECT_OT_quadriflow_remesh(wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna,
+ "use_paint_symmetry",
+ true,
+ "Use Paint Symmetry",
+ "Generates a symmetrycal mesh using the paint symmetry configuration");
+
+ RNA_def_boolean(ot->srna,
"use_preserve_sharp",
false,
"Preserve Sharp",