Array Brush: Support array editing with the voxel remesher
This commit is contained in:
parent
89897140cf
commit
c1f5ac7cfe
|
@ -62,6 +62,7 @@ void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *sour
|
|||
void BKE_remesh_reproject_vertex_paint(struct Mesh *target, struct Mesh *source);
|
||||
void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source);
|
||||
void BKE_remesh_reproject_materials(struct Mesh *target, struct Mesh *source);
|
||||
void BKE_mesh_remesh_sculpt_array_update(struct Object *ob, struct Mesh *target, struct Mesh *source);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -492,6 +492,8 @@ typedef struct SculptArray {
|
|||
int *copy_index;
|
||||
int *symmetry_pass;
|
||||
|
||||
float *smooth_strength;
|
||||
|
||||
} SculptArray;
|
||||
|
||||
typedef struct SculptFakeNeighbors {
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh_remesh_voxel.h" /* own include */
|
||||
#include "BKE_mesh_runtime.h"
|
||||
#include "BKE_paint.h"
|
||||
|
||||
#include "bmesh_tools.h"
|
||||
|
||||
|
@ -352,6 +353,79 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source)
|
|||
free_bvhtree_from_mesh(&bvhtree);
|
||||
}
|
||||
|
||||
void BKE_mesh_remesh_sculpt_array_update(Object *ob, Mesh *target, Mesh *source)
|
||||
{
|
||||
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
if (!ss) {
|
||||
return;
|
||||
}
|
||||
|
||||
SculptArray *array = ss->array;
|
||||
if (!array) {
|
||||
return;
|
||||
}
|
||||
|
||||
BVHTreeFromMesh bvhtree = {
|
||||
.nearest_callback = NULL,
|
||||
};
|
||||
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2);
|
||||
MVert *target_verts = CustomData_get_layer(&target->vdata, CD_MVERT);
|
||||
|
||||
const int target_totvert = target->totvert;
|
||||
|
||||
int *target_copy_index = MEM_malloc_arrayN(sizeof(int), target_totvert, "target_copy_index");
|
||||
int *target_symmertry = MEM_malloc_arrayN(sizeof(int), target_totvert, "target_copy_index");
|
||||
float (*target_orco)[3] = MEM_malloc_arrayN(target->totvert, sizeof(float) * 3, "array orco");
|
||||
|
||||
for (int i = 0; i < target_totvert; i++) {
|
||||
target_copy_index[i] = -1;
|
||||
target_symmertry[i] = 0;
|
||||
copy_v3_v3(target_orco, target->mvert[i].co);
|
||||
}
|
||||
|
||||
for (int i = 0; i < target->totvert; i++) {
|
||||
float from_co[3];
|
||||
BVHTreeNearest nearest;
|
||||
nearest.index = -1;
|
||||
nearest.dist_sq = FLT_MAX;
|
||||
copy_v3_v3(from_co, target_verts[i].co);
|
||||
BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
|
||||
if (nearest.index != -1) {
|
||||
target_copy_index[i] = array->copy_index[nearest.index];
|
||||
target_symmertry[i] = array->symmetry_pass[nearest.index];
|
||||
}
|
||||
}
|
||||
free_bvhtree_from_mesh(&bvhtree);
|
||||
|
||||
MEM_freeN(array->copy_index);
|
||||
MEM_freeN(array->symmetry_pass);
|
||||
MEM_freeN(array->orco);
|
||||
|
||||
array->copy_index = target_copy_index;
|
||||
array->symmetry_pass = target_symmertry;
|
||||
array->orco = target_orco;
|
||||
|
||||
for (int i = 0; i < target->totvert; i++) {
|
||||
int array_index = target_copy_index[i];
|
||||
int array_symm_pass = target_symmertry[i];
|
||||
if (array_index == -1) {
|
||||
continue;
|
||||
}
|
||||
SculptArrayCopy *copy = &array->copies[array_symm_pass][array_index];
|
||||
float co[3];
|
||||
float source_origin_symm[3];
|
||||
copy_v3_v3(co, target->mvert[i].co);
|
||||
/* TODO: MAke symmetry work here. */
|
||||
//flip_v3_v3(source_origin_symm, array->source_origin, array_symm_pass);
|
||||
mul_v3_m4v3(co, array->source_imat, co);
|
||||
mul_v3_m4v3(co, copy->imat, co);
|
||||
sub_v3_v3v3(co, co, source_origin_symm);
|
||||
copy_v3_v3(array->orco[i], co);
|
||||
}
|
||||
}
|
||||
|
||||
void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source)
|
||||
{
|
||||
BVHTreeFromMesh bvhtree = {
|
||||
|
|
|
@ -195,6 +195,10 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op)
|
|||
BKE_remesh_reproject_vertex_paint(new_mesh, mesh);
|
||||
}
|
||||
|
||||
if (ob->mode == OB_MODE_SCULPT) {
|
||||
BKE_mesh_remesh_sculpt_array_update(ob, new_mesh, mesh);
|
||||
}
|
||||
|
||||
BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob, &CD_MASK_MESH, true);
|
||||
|
||||
if (smooth_normals) {
|
||||
|
|
|
@ -513,7 +513,6 @@ static void sculpt_array_update(Object *ob, Brush *brush, SculptArray *array) {
|
|||
}
|
||||
for (int copy_index = 0; copy_index < array->num_copies; copy_index++) {
|
||||
SculptArrayCopy *copy = &array->copies[symm_pass][copy_index];
|
||||
print_m4("cosa", copy->mat);
|
||||
invert_m4_m4(copy->imat, copy->mat);
|
||||
}
|
||||
}
|
||||
|
@ -581,6 +580,104 @@ static void sculpt_array_deform(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
|
|||
0, totnode, &data, do_array_deform_task_cb_ex, &settings);
|
||||
}
|
||||
|
||||
|
||||
static void do_array_smooth_task_cb_ex(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
SculptThreadedTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
SculptArray *array = ss->array;
|
||||
|
||||
Mesh *mesh = BKE_object_get_original_mesh(data->ob);
|
||||
|
||||
bool any_modified = false;
|
||||
|
||||
PBVHVertexIter vd;
|
||||
BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) {
|
||||
int array_index = ARRAY_INSTANCE_ORIGINAL;
|
||||
int array_symm_pass = 0;
|
||||
sculpt_vertex_array_data_get(array, vd.index, &array_index, &array_symm_pass);
|
||||
|
||||
const float fade = array->smooth_strength[vd.index];
|
||||
|
||||
if (fade == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float smooth_co[3];
|
||||
SCULPT_neighbor_coords_average(ss, smooth_co, vd.index);
|
||||
float disp[3];
|
||||
sub_v3_v3v3(disp, smooth_co, vd.co);
|
||||
mul_v3_fl(disp, fade);
|
||||
add_v3_v3(vd.co, disp);
|
||||
|
||||
|
||||
/*
|
||||
if (array_index == ARRAY_INSTANCE_ORIGINAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool do_smooth = false;
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) {
|
||||
int neighbor_array_index = ARRAY_INSTANCE_ORIGINAL;
|
||||
int neighbor_symm_pass = 0;
|
||||
sculpt_vertex_array_data_get(array, ni.index, &neighbor_array_index,&neighbor_symm_pass);
|
||||
if (neighbor_array_index != array_index) {
|
||||
do_smooth = true;
|
||||
}
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
|
||||
if (!do_smooth) {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
any_modified = true;
|
||||
|
||||
|
||||
if (vd.mvert) {
|
||||
vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
|
||||
}
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
|
||||
if (any_modified) {
|
||||
BKE_pbvh_node_mark_update(data->nodes[n]);
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_array_smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) {
|
||||
|
||||
|
||||
|
||||
/* Threaded loop over nodes. */
|
||||
SculptSession *ss = ob->sculpt;
|
||||
SculptArray *array = ss->array;
|
||||
|
||||
if (!array) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!array->smooth_strength) {
|
||||
return;
|
||||
}
|
||||
SculptThreadedTaskData data = {
|
||||
.sd = sd,
|
||||
.ob = ob,
|
||||
.nodes = nodes,
|
||||
};
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
BLI_task_parallel_range(
|
||||
0, totnode, &data, do_array_smooth_task_cb_ex, &settings);
|
||||
}
|
||||
|
||||
static void sculpt_array_ensure_original_coordinates(Object *ob, SculptArray *array){
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Mesh *sculpt_mesh = BKE_object_get_original_mesh(ob);
|
||||
|
@ -690,9 +787,56 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
}
|
||||
|
||||
if (SCULPT_stroke_is_first_brush_step(ss->cache)) {
|
||||
SculptArray *array = ss->array;
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
|
||||
|
||||
/* Rebuild smooth strength cache. */
|
||||
MEM_SAFE_FREE(array->smooth_strength);
|
||||
array->smooth_strength = MEM_calloc_arrayN(sizeof(float), totvert, "smooth_strength");
|
||||
|
||||
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
int array_index = ARRAY_INSTANCE_ORIGINAL;
|
||||
int array_symm_pass = 0;
|
||||
sculpt_vertex_array_data_get(array, i, &array_index, &array_symm_pass);
|
||||
|
||||
if (array_index == ARRAY_INSTANCE_ORIGINAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* TODO: this can be cached. */
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
|
||||
int neighbor_array_index = ARRAY_INSTANCE_ORIGINAL;
|
||||
int neighbor_symm_pass = 0;
|
||||
sculpt_vertex_array_data_get(array, ni.index, &neighbor_array_index,&neighbor_symm_pass);
|
||||
if (neighbor_array_index != array_index) {
|
||||
array->smooth_strength[i] = 1.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
}
|
||||
|
||||
for(int smooth_iterations = 0; smooth_iterations < 4; smooth_iterations++) {
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
float avg = array->smooth_strength[i];
|
||||
int count = 1;
|
||||
SculptVertexNeighborIter ni;
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, i, ni) {
|
||||
avg += array->smooth_strength[ni.index];
|
||||
count++;
|
||||
}
|
||||
SCULPT_VERTEX_NEIGHBORS_ITER_END(ni);
|
||||
array->smooth_strength[i] = avg / count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Update Array Path Orco. */
|
||||
SculptArray *array = ss->array;
|
||||
for (int i = 0; i < array->path.tot_points; i++) {
|
||||
ScultpArrayPathPoint *point = &array->path.points[i];
|
||||
copy_v3_v3(point->orco, point->co);
|
||||
|
@ -700,7 +844,6 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
array->initial_radial_angle = array->radial_angle;
|
||||
|
||||
/* Update Geometry Orco. */
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
for (int i = 0; i < totvert; i++) {
|
||||
int array_index = ARRAY_INSTANCE_ORIGINAL;
|
||||
int array_symm_pass = 0;
|
||||
|
@ -715,9 +858,9 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
float source_origin_symm[3];
|
||||
copy_v3_v3(co, SCULPT_vertex_co_get(ss, i));
|
||||
flip_v3_v3(source_origin_symm, array->source_origin, array_symm_pass);
|
||||
mul_v3_m4v3(co, array->source_imat, co);
|
||||
mul_v3_m4v3(co, copy->imat, co);
|
||||
sub_v3_v3v3(co, co, source_origin_symm);
|
||||
mul_v3_m4v3(co, array->source_imat, co);
|
||||
//sub_v3_v3v3(co, co, source_origin_symm);
|
||||
|
||||
copy_v3_v3(array->orco[i], co);
|
||||
}
|
||||
|
@ -757,12 +900,13 @@ void SCULPT_do_array_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
normalize_v3(brush_co);
|
||||
normalize_v3_v3(array_disp_co, sculpt_array_delta_from_path(array));
|
||||
array->radial_angle = angle_signed_on_axis_v3v3_v3(brush_co, array_disp_co, array->normal);
|
||||
|
||||
|
||||
}
|
||||
|
||||
sculpt_array_update(ob, brush, ss->array);
|
||||
sculpt_array_deform(sd, ob, nodes, totnode);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
sculpt_array_smooth(sd, ob, nodes, totnode);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
|
|
Loading…
Reference in New Issue