Sculpt-dev: New displacement heal brush
This brush goes through all the grids inside each PBVH node under the brush, converts coordinates to tangent space, filters out extreme displacements and then converts back. Simple, but very effective. TODO: make this into a mesh filter too.
This commit is contained in:
parent
084a967ab4
commit
8f18ee27e7
Binary file not shown.
|
@ -315,6 +315,17 @@ void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg,
|
|||
const SubdivCCGCoord *coord,
|
||||
float r_point[3]);
|
||||
|
||||
void BKE_subdiv_ccg_eval_limit_point_and_derivatives(const SubdivCCG *subdiv_ccg,
|
||||
const SubdivCCGCoord *coord,
|
||||
float r_point[3],
|
||||
float r_dPdu[3],
|
||||
float r_dPdv[3]);
|
||||
|
||||
void BKE_subdiv_ccg_get_tangent_matrix(const SubdivCCG *subdiv_ccg,
|
||||
const SubdivCCGCoord *coord,
|
||||
float mat[3][3],
|
||||
float r_point[3]);
|
||||
|
||||
typedef enum SubdivCCGAdjacencyType {
|
||||
SUBDIV_CCG_ADJACENT_NONE,
|
||||
SUBDIV_CCG_ADJACENT_VERTEX,
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
#include "BLI_math_vector.h"
|
||||
#include "BLI_task.h"
|
||||
|
||||
#include "multires_inline.h"
|
||||
|
||||
#include "BKE_DerivedMesh.h"
|
||||
#include "BKE_ccg.h"
|
||||
#include "BKE_global.h"
|
||||
|
@ -2101,4 +2103,38 @@ void BKE_subdiv_ccg_eval_limit_point(const SubdivCCG *subdiv_ccg,
|
|||
BKE_subdiv_eval_limit_point(subdiv, ptex_face_index, u, v, r_point);
|
||||
}
|
||||
|
||||
void BKE_subdiv_ccg_eval_limit_point_and_derivatives(const SubdivCCG *subdiv_ccg,
|
||||
const SubdivCCGCoord *coord,
|
||||
float r_point[3],
|
||||
float r_dPdu[3],
|
||||
float r_dPdv[3])
|
||||
{
|
||||
Subdiv *subdiv = subdiv_ccg->subdiv;
|
||||
int ptex_face_index;
|
||||
float u, v;
|
||||
subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, &ptex_face_index, &u, &v);
|
||||
BKE_subdiv_eval_limit_point_and_derivatives(
|
||||
subdiv, ptex_face_index, u, v, r_point, r_dPdu, r_dPdv);
|
||||
}
|
||||
|
||||
void BKE_subdiv_ccg_get_tangent_matrix(const SubdivCCG *subdiv_ccg,
|
||||
const SubdivCCGCoord *coord,
|
||||
float mat[3][3],
|
||||
float r_point[3])
|
||||
{
|
||||
int ptex_face_index;
|
||||
float u, v;
|
||||
float du[3], dv[3];
|
||||
|
||||
const int face_index = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, coord->grid_index);
|
||||
const SubdivCCGFace *faces = subdiv_ccg->faces;
|
||||
const SubdivCCGFace *face = &faces[face_index];
|
||||
const float corner = coord->grid_index - face->start_grid_index;
|
||||
|
||||
subdiv_ccg_coord_to_ptex_coord(subdiv_ccg, coord, &ptex_face_index, &u, &v);
|
||||
|
||||
BKE_subdiv_ccg_eval_limit_point_and_derivatives(subdiv_ccg, coord, r_point, du, dv);
|
||||
BKE_multires_construct_tangent_matrix(mat, du, dv, corner);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -202,13 +202,13 @@ extern "C" {
|
|||
|
||||
BLI_lfmempool *BLI_lfmempool_create(int esize, int psize)
|
||||
{
|
||||
LockFreePool *pool = OBJECT_GUARDED_NEW(LockFreePool, esize, psize);
|
||||
LockFreePool *pool = MEM_new<LockFreePool>(__func__, esize, psize);
|
||||
return reinterpret_cast<BLI_lfmempool *>(pool);
|
||||
}
|
||||
|
||||
void BLI_lfmempool_destroy(BLI_lfmempool *pool)
|
||||
{
|
||||
OBJECT_GUARDED_DELETE(cast_pool(pool), LockFreePool);
|
||||
MEM_delete<LockFreePool>(cast_pool(pool));
|
||||
}
|
||||
|
||||
void *BLI_lfmempool_alloc(BLI_lfmempool *pool)
|
||||
|
|
|
@ -752,6 +752,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
|
|||
brush.sculpt.cloth
|
||||
brush.sculpt.crease
|
||||
brush.sculpt.displacement_eraser
|
||||
brush.sculpt.displacement_heal
|
||||
brush.sculpt.displacement_smear
|
||||
brush.sculpt.draw
|
||||
brush.sculpt.draw_face_sets
|
||||
|
|
|
@ -3986,6 +3986,7 @@ static float brush_strength(const Sculpt *sd,
|
|||
case SCULPT_TOOL_LAYER:
|
||||
case SCULPT_TOOL_SYMMETRIZE:
|
||||
return alpha * flip * pressure * overlap * feather;
|
||||
case SCULPT_TOOL_DISPLACEMENT_HEAL:
|
||||
case SCULPT_TOOL_DISPLACEMENT_ERASER:
|
||||
return alpha * pressure * overlap * feather;
|
||||
case SCULPT_TOOL_FAIRING:
|
||||
|
@ -4122,15 +4123,15 @@ static float brush_strength(const Sculpt *sd,
|
|||
}
|
||||
}
|
||||
|
||||
float SCULPT_brush_strength_factor(SculptSession *ss,
|
||||
const Brush *br,
|
||||
const float brush_point[3],
|
||||
const float len,
|
||||
const short vno[3],
|
||||
const float fno[3],
|
||||
const float mask,
|
||||
const SculptVertRef vertex_index,
|
||||
const int thread_id)
|
||||
ATTR_NO_OPT float SCULPT_brush_strength_factor(SculptSession *ss,
|
||||
const Brush *br,
|
||||
const float brush_point[3],
|
||||
const float len,
|
||||
const short vno[3],
|
||||
const float fno[3],
|
||||
const float mask,
|
||||
const SculptVertRef vertex_index,
|
||||
const int thread_id)
|
||||
{
|
||||
StrokeCache *cache = ss->cache;
|
||||
const Scene *scene = cache->vc->scene;
|
||||
|
@ -5486,6 +5487,9 @@ void do_brush_action(
|
|||
SCULPT_enhance_details_brush(
|
||||
sd, ob, nodes, totnode, SCULPT_get_int(ss, enhance_detail_presteps, sd, brush));
|
||||
break;
|
||||
case SCULPT_TOOL_DISPLACEMENT_HEAL:
|
||||
SCULPT_do_displacement_heal_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
}
|
||||
|
||||
bool apply_autosmooth = !ELEM(SCULPT_get_tool(ss, brush),
|
||||
|
@ -6052,6 +6056,8 @@ static void SCULPT_run_command(
|
|||
case SCULPT_TOOL_ENHANCE_DETAILS:
|
||||
SCULPT_enhance_details_brush(
|
||||
sd, ob, nodes, totnode, SCULPT_get_int(ss, enhance_detail_presteps, sd, brush));
|
||||
case SCULPT_TOOL_DISPLACEMENT_HEAL:
|
||||
SCULPT_do_displacement_heal_brush(sd, ob, nodes, totnode);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "BKE_scene.h"
|
||||
#include "BKE_screen.h"
|
||||
#include "BKE_subdiv_ccg.h"
|
||||
#include "BKE_subdiv_eval.h"
|
||||
#include "BKE_subsurf.h"
|
||||
|
||||
#include "DEG_depsgraph.h"
|
||||
|
@ -318,7 +319,6 @@ static void sculpt_project_v3_normal_align(SculptSession *ss,
|
|||
|
||||
/************************************** Brushes ******************************/
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Sculpt Draw Brush
|
||||
* \{ */
|
||||
|
@ -622,7 +622,7 @@ void SCULPT_do_twist_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
|
|||
int totbit = 0;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (ss->cache->mirror_symmetry_pass & (1<<i)) {
|
||||
if (ss->cache->mirror_symmetry_pass & (1 << i)) {
|
||||
totbit++;
|
||||
}
|
||||
}
|
||||
|
@ -1205,9 +1205,9 @@ static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata),
|
|||
join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]);
|
||||
}
|
||||
|
||||
static void do_clay_brush_task_cb_ex(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
ATTR_NO_OPT static void do_clay_brush_task_cb_ex(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
SculptThreadedTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
|
@ -1262,7 +1262,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata,
|
|||
BKE_pbvh_node_mark_update(data->nodes[n]);
|
||||
}
|
||||
|
||||
void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
ATTR_NO_OPT void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
@ -3620,7 +3620,6 @@ void SCULPT_fairing_brush_exec_fairing_for_cache(Sculpt *sd, Object *ob)
|
|||
|
||||
/** \} */
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void SCULPT_do_auto_face_set(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
|
@ -4235,3 +4234,166 @@ void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE SculptVertRef grid_xy_to_vertex(int x, int y, int grid_i, int gridsize)
|
||||
{
|
||||
return (SculptVertRef){.i = grid_i * gridsize * gridsize + y * gridsize + x};
|
||||
}
|
||||
|
||||
typedef struct DisplacementHealTaskData {
|
||||
Object *ob;
|
||||
Brush *brush;
|
||||
Sculpt *sd;
|
||||
PBVHNode **nodes;
|
||||
BLI_bitmap *bitmap;
|
||||
float plane_view[3];
|
||||
float bstrength;
|
||||
} DisplacementHealTaskData;
|
||||
|
||||
static void do_displacement_heal_cb(void *__restrict userdata,
|
||||
const int n,
|
||||
const TaskParallelTLS *__restrict tls)
|
||||
{
|
||||
DisplacementHealTaskData *data = userdata;
|
||||
SculptSession *ss = data->ob->sculpt;
|
||||
|
||||
PBVHNode *node = data->nodes[n];
|
||||
|
||||
CCGElem **grids;
|
||||
|
||||
int *grid_indices, totgrid, maxgrid, gridsize;
|
||||
const float bstrength = data->bstrength;
|
||||
|
||||
BKE_pbvh_node_get_grids(ss->pbvh, node, &grid_indices, &totgrid, &maxgrid, &gridsize, &grids);
|
||||
|
||||
float(*disps)[3] = MEM_calloc_arrayN(gridsize * gridsize, sizeof(float) * 3, __func__);
|
||||
float(*mats)[16] = MEM_calloc_arrayN(gridsize * gridsize, sizeof(float) * 16, __func__);
|
||||
float(*limits)[3] = MEM_calloc_arrayN(gridsize * gridsize, sizeof(float) * 3, __func__);
|
||||
|
||||
bool modified = false;
|
||||
|
||||
for (int i = 0; i < totgrid; i++) {
|
||||
const int grid_i = grid_indices[i];
|
||||
|
||||
for (int x = 0; x < gridsize; x++) {
|
||||
for (int y = 0; y < gridsize; y++) {
|
||||
SculptVertRef vertex = grid_xy_to_vertex(x, y, grid_i, gridsize);
|
||||
|
||||
SubdivCCGCoord coord = {.grid_index = grid_i, .x = x, .y = y};
|
||||
int locali = y * gridsize + x;
|
||||
float mat[3][3], p[3];
|
||||
|
||||
BKE_subdiv_ccg_get_tangent_matrix(ss->subdiv_ccg, &coord, mat, p);
|
||||
copy_m3_m3(mats[locali], mat);
|
||||
|
||||
invert_m3(mat);
|
||||
|
||||
float disp[3];
|
||||
copy_v3_v3(disp, SCULPT_vertex_co_get(ss, vertex));
|
||||
sub_v3_v3(disp, p);
|
||||
mul_v3_m3v3(disp, mat, disp);
|
||||
|
||||
copy_v3_v3(disps[locali], disp);
|
||||
copy_v3_v3(limits[locali], p);
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < gridsize; x++) {
|
||||
for (int y = 0; y < gridsize; y++) {
|
||||
int locali = y * gridsize + x;
|
||||
|
||||
SculptVertRef vertex = grid_xy_to_vertex(x, y, grid_i, gridsize);
|
||||
float *disp = disps[locali];
|
||||
float avg[3] = {0.0f, 0.0f, 0.0f};
|
||||
float tot = 0.0f;
|
||||
|
||||
for (int x2 = x - 1; x2 <= x + 1; x2++) {
|
||||
for (int y2 = y - 1; y2 <= y + 1; y2++) {
|
||||
if (x2 < 0 || y2 < 0 || x2 >= gridsize || y2 >= gridsize) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int local2 = y2 * gridsize + x2;
|
||||
|
||||
add_v3_v3(avg, disps[local2]);
|
||||
tot += 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (tot == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mul_v3_fl(avg, 1.0 / tot);
|
||||
|
||||
if (dot_v3v3(avg, avg) == 0.0f || dot_v3v3(disp, disp) == 0.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float ratio = len_v3(disp) / len_v3(avg);
|
||||
|
||||
if (ratio < 1.0f) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
|
||||
ratio = pow(ratio, 0.1f);
|
||||
float tmp[3];
|
||||
|
||||
copy_v3_v3(tmp, disp);
|
||||
mul_v3_fl(tmp, 1.0f / ratio);
|
||||
mul_v3_m3v3(tmp, mats[locali], tmp);
|
||||
add_v3_v3(tmp, limits[locali]);
|
||||
|
||||
float *co = (float *)SCULPT_vertex_co_get(ss, vertex);
|
||||
|
||||
interp_v3_v3v3(co, co, tmp, bstrength);
|
||||
//copy_v3_v3(co, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(disps);
|
||||
MEM_SAFE_FREE(mats);
|
||||
MEM_SAFE_FREE(limits);
|
||||
|
||||
if (modified) {
|
||||
BKE_pbvh_node_mark_update(node);
|
||||
}
|
||||
}
|
||||
|
||||
void SCULPT_do_displacement_heal_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
|
||||
if (!ss->pbvh || BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
|
||||
return;
|
||||
}
|
||||
|
||||
SCULPT_boundary_info_ensure(ob);
|
||||
|
||||
const int totvert = SCULPT_vertex_count_get(ss);
|
||||
BLI_bitmap *bitmap = BLI_BITMAP_NEW(totvert, __func__);
|
||||
const float bstrength = fabsf(ss->cache->bstrength);
|
||||
|
||||
/* paranoia check */
|
||||
ss->cache->radius_squared = ss->cache->radius * ss->cache->radius;
|
||||
|
||||
/* Threaded loop over nodes. */
|
||||
DisplacementHealTaskData data = {.sd = sd,
|
||||
.ob = ob,
|
||||
.brush = brush,
|
||||
.bstrength = bstrength,
|
||||
.nodes = nodes,
|
||||
.bitmap = bitmap};
|
||||
|
||||
copy_v3_v3(data.plane_view, ss->cache->view_normal);
|
||||
|
||||
TaskParallelSettings settings;
|
||||
BKE_pbvh_parallel_range_settings(&settings, true, totnode);
|
||||
BLI_task_parallel_range(0, totnode, &data, do_displacement_heal_cb, &settings);
|
||||
|
||||
MEM_SAFE_FREE(bitmap);
|
||||
}
|
||||
|
|
|
@ -2333,3 +2333,7 @@ void SCULPT_enhance_details_brush(struct Sculpt *sd,
|
|||
struct PBVHNode **nodes,
|
||||
const int totnode,
|
||||
int presteps);
|
||||
void SCULPT_do_displacement_heal_brush(struct Sculpt *sd,
|
||||
struct Object *ob,
|
||||
struct PBVHNode **nodes,
|
||||
int totnode);
|
||||
|
|
|
@ -510,7 +510,8 @@ typedef enum eBrushSculptTool {
|
|||
SCULPT_TOOL_DYNTOPO = 41,
|
||||
SCULPT_TOOL_AUTO_FSET = 42,
|
||||
SCULPT_TOOL_RELAX = 43,
|
||||
SCULPT_TOOL_ENHANCE_DETAILS = 44
|
||||
SCULPT_TOOL_ENHANCE_DETAILS = 44,
|
||||
SCULPT_TOOL_DISPLACEMENT_HEAL = 45
|
||||
} eBrushSculptTool;
|
||||
|
||||
/* Brush.uv_sculpt_tool */
|
||||
|
|
|
@ -147,6 +147,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = {
|
|||
{SCULPT_TOOL_ARRAY, "ARRAY", ICON_BRUSH_SCULPT_DRAW, "Array", ""},
|
||||
{SCULPT_TOOL_VCOL_BOUNDARY, "VCOL_BOUNDARY", ICON_BRUSH_VCOL_BOUNDARY, "Sharpen Color Boundary", ""},
|
||||
{SCULPT_TOOL_UV_SMOOTH, "UV_SMOOTH", ICON_BRUSH_GRAB, "UV Smooth", ""},
|
||||
{SCULPT_TOOL_DISPLACEMENT_HEAL, "DISPLACEMENT_HEAL", ICON_BRUSH_GRAB, "Displacement Heal", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
/* clang-format on */
|
||||
|
|
Loading…
Reference in New Issue