Sculpt-dev: support area weighted smooth for PBVH_FACES

* This was actually kind of annoying; the
  vertex->face-area-list code is in pbvh and
  relies on edge ordering
  around verts, but that order is non-trivial for
  PBVH_FACES (relying as it does on a vertex->poly
  map).  This ordering was calculated entirely in
  editors/sculpt_paint/sculpt.c, not callable from
  pbvh.
* The solution was to add a helper function to pbvh
  for building vertex->edge lists from vertex->poly
  maps.  This is then used by both sculpt.c and the
  vertex->face-area-list code.

* Also improved boundary bevel smooth a bit.  I'm
  thinking of extracting it from SCULPT_neighbor_coords_average_interior
  into its own function and possibly its own brush.
This commit is contained in:
Joseph Eagar 2021-11-28 01:19:23 -08:00
parent e5804dc607
commit e21c21bbf9
13 changed files with 388 additions and 110 deletions

View File

@ -1350,6 +1350,7 @@ class _defs_sculpt:
layout.prop(props, "hard_edge_mode")
layout.prop(props, "preserve_fset_boundaries")
layout.prop(props, "bound_smooth_radius")
layout.prop(props, "bevel_smooth_fac")
return dict(idname="builtin.mesh_filter",
label="Mesh Filter",

View File

@ -493,6 +493,10 @@ class VIEW3D_PT_tools_brush_color(Panel, View3DPaintPanel):
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
if not settings:
return
brush = settings.brush
draw_color_settings(context, layout, brush, color_type=not context.vertex_paint_object)

View File

@ -743,6 +743,7 @@ typedef struct SculptSession {
float (*orig_cos)[3]; /* Coords of un-deformed mesh. */
float (*deform_cos)[3]; /* Coords of deformed mesh but without stroke displacement. */
float (*deform_imats)[3][3]; /* Crazy-space deformation matrices. */
float *face_areas; /* cached face areas for PBVH_FACES and PBVH_GRIDS */
/* Used to cache the render of the active texture */
unsigned int texcache_side, *texcache, texcache_actual;
@ -890,6 +891,7 @@ bool BKE_sculptsession_customlayer_get(struct Object *ob,
const char *name,
SculptCustomLayer *scl,
SculptLayerParams *params);
bool BKE_sculptsession_customlayer_release(struct Object *ob, SculptCustomLayer *scl);
void BKE_sculptsession_bmesh_attr_update_internal(struct Object *ob);
void BKE_sculptsession_update_attr_refs(struct Object *ob);
int BKE_sculptsession_get_totvert(const SculptSession *ss);

View File

@ -292,7 +292,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
struct CustomData *pdata,
const struct MLoopTri *looptri,
int looptri_num,
bool fast_draw);
bool fast_draw,
float *face_areas,
struct MeshElemMap *pmap);
void BKE_pbvh_build_grids(PBVH *pbvh,
struct CCGElem **grids,
int totgrid,
@ -300,7 +302,8 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
struct DMFlagMat *flagmats,
unsigned int **grid_hidden,
bool fast_draw);
bool fast_draw,
float *face_areas);
void BKE_pbvh_build_bmesh(PBVH *pbvh,
struct Mesh *me,
struct BMesh *bm,
@ -1070,3 +1073,21 @@ void BKE_dyntopo_remesh(DynTopoState *ds,
PBVHTopologyUpdateMode mode);
void BKE_pbvh_bmesh_get_vcol(
struct BMVert *v, float color[4], int vcol_type, AttributeDomain vcol_domain, int vcol_offset);
/*
use pmap to build an array of edge indices surrounding vertex
r_edges, r_edges_size, heap_alloc define an existing array to put data in.
final array is similarly put in these pointers. note that calling code
may pass a stack allocated array (*heap_alloc should be false), and must
check if heap_alloc is true afterwards and free *r_edges.
r_polys is an array of integer pairs and must be same logical size as r_edges
*/
void BKE_pbvh_pmap_to_edges(PBVH *pbvh,
SculptVertRef vertex,
int **r_edges,
int *r_edges_size,
bool *heap_alloc,
int **r_polys);
void BKE_pbvh_set_vemap(PBVH *pbvh, struct MeshElemMap *vemap);

View File

@ -90,6 +90,8 @@ void SCULPT_undo_ensure_bmlog(Object *ob);
static void init_mdyntopo_layer(SculptSession *ss, PBVH *pbvh, int totvert);
const char *face_areas_layer_name = "_sculpt_face_areas";
static void palette_init_data(ID *id)
{
Palette *palette = (Palette *)id;
@ -1455,6 +1457,8 @@ static void sculptsession_free_pbvh(Object *object)
ss->pbvh = NULL;
}
MEM_SAFE_FREE(ss->face_areas);
MEM_SAFE_FREE(ss->pmap);
MEM_SAFE_FREE(ss->pmap_mem);
@ -2444,19 +2448,24 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
BKE_sculptsession_check_mdyntopo(ob->sculpt, pbvh, me->totvert);
MEM_SAFE_FREE(ss->face_areas);
ss->face_areas = MEM_calloc_arrayN(me->totpoly, sizeof(float), "ss->face_areas");
BKE_pbvh_build_mesh(pbvh,
me,
me->mpoly,
me->mloop,
me->mvert,
ob->sculpt->mdyntopo_verts,
ss->mdyntopo_verts,
me->totvert,
&me->vdata,
&me->ldata,
&me->pdata,
looptri,
looptris_num,
ob->sculpt->fast_draw);
ss->fast_draw,
ss->face_areas,
ss->pmap);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets);
@ -2474,6 +2483,8 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect_hide)
{
SculptSession *ss = ob->sculpt;
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
PBVH *pbvh = BKE_pbvh_new();
@ -2482,6 +2493,11 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
Mesh *base_mesh = BKE_mesh_from_object(ob);
BKE_sculpt_sync_face_set_visibility(base_mesh, subdiv_ccg);
int totgridfaces = base_mesh->totpoly * (key.grid_size - 1) * (key.grid_size - 1);
MEM_SAFE_FREE(ss->face_areas);
ss->face_areas = MEM_calloc_arrayN(totgridfaces, sizeof(float), "ss->face_areas");
BKE_pbvh_build_grids(pbvh,
subdiv_ccg->grids,
subdiv_ccg->num_grids,
@ -2489,7 +2505,8 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
(void **)subdiv_ccg->grid_faces,
subdiv_ccg->grid_flag_mats,
subdiv_ccg->grid_hidden,
ob->sculpt->fast_draw);
ob->sculpt->fast_draw,
ss->face_areas);
BKE_sculptsession_check_mdyntopo(ob->sculpt, pbvh, BKE_pbvh_get_grid_num_vertices(pbvh));
@ -3353,3 +3370,54 @@ bool BKE_paint_uses_channels(ePaintMode mode)
{
return mode == PAINT_MODE_SCULPT;
}
bool BKE_sculptsession_customlayer_release(Object *ob, SculptCustomLayer *scl)
{
SculptSession *ss = ob->sculpt;
AttributeDomain domain = scl->domain;
if (scl->released) {
return false;
}
// remove from layers_to_free list if necassary
for (int i = 0; scl->data && i < ss->tot_layers_to_free; i++) {
if (ss->layers_to_free[i] && ss->layers_to_free[i]->data == scl->data) {
MEM_freeN(ss->layers_to_free[i]);
ss->layers_to_free[i] = NULL;
}
}
scl->released = true;
if (!scl->from_bmesh) {
// for now, don't clean up bmesh temp layers
if (scl->is_cdlayer && BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
CustomData *cdata = NULL;
int totelem = 0;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = ss->vdata;
totelem = ss->totvert;
break;
case ATTR_DOMAIN_FACE:
cdata = ss->pdata;
totelem = ss->totfaces;
break;
default:
printf("error, unknown domain in %s\n", __func__);
return false;
}
CustomData_free_layer(cdata, scl->layer->type, totelem, scl->layer - cdata->layers);
BKE_sculptsession_update_attr_refs(ob);
}
else {
MEM_SAFE_FREE(scl->data);
}
scl->data = NULL;
}
return true;
}

View File

@ -22,6 +22,7 @@
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
@ -421,6 +422,7 @@ static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node)
BKE_pbvh_node_mark_rebuild_draw(node);
BKE_pbvh_node_fully_hidden_set(node, !has_visible);
BKE_pbvh_node_mark_update_tri_area(node);
BLI_ghash_free(map, NULL, NULL);
}
@ -493,6 +495,7 @@ static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
pbvh->grid_hidden, node->prim_indices, node->totprim, pbvh->gridkey.grid_size);
BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
BKE_pbvh_node_mark_rebuild_draw(node);
BKE_pbvh_node_mark_update_tri_area(node);
}
static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, int count)
@ -659,18 +662,21 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
const MLoop *mloop,
MVert *verts,
MSculptVert *mdyntopo_verts,
int totvert,
struct CustomData *vdata,
struct CustomData *ldata,
struct CustomData *pdata,
const MLoopTri *looptri,
int looptri_num,
bool fast_draw)
bool fast_draw,
float *face_areas,
struct MeshElemMap *pmap)
{
BBC *prim_bbc = NULL;
BB cb;
pbvh->pmap = pmap;
pbvh->face_areas = face_areas;
pbvh->mesh = mesh;
pbvh->type = PBVH_FACES;
pbvh->mpoly = mpoly;
@ -731,10 +737,12 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
void **gridfaces,
DMFlagMat *flagmats,
BLI_bitmap **grid_hidden,
bool fast_draw)
bool fast_draw,
float *face_areas)
{
const int gridsize = key->grid_size;
pbvh->face_areas = face_areas;
pbvh->type = PBVH_GRIDS;
pbvh->grids = grids;
pbvh->gridfaces = gridfaces;
@ -4257,17 +4265,49 @@ void BKE_pbvh_update_all_tri_areas(PBVH *pbvh)
void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
{
if (!(node->flag & PBVH_UpdateTriAreas) || !node->tribuf || !node->tribuf->tottri) {
if (!(node->flag & PBVH_UpdateTriAreas)) {
return;
}
if (pbvh->type == PBVH_BMESH && (!node->tribuf || !node->tribuf->tottri)) {
return;
}
node->flag &= ~PBVH_UpdateTriAreas;
if (node->flag & PBVH_UpdateTris) {
if (pbvh->type == PBVH_BMESH && (node->flag & PBVH_UpdateTris)) {
BKE_pbvh_bmesh_check_tris(pbvh, node);
}
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES: {
for (int i = 0; i < node->totprim; i++) {
const MLoopTri *lt = &pbvh->looptri[node->prim_indices[i]];
if (pbvh->face_sets[lt->poly] < 0) {
/* Skip hidden faces. */
continue;
}
pbvh->face_areas[lt->poly] = 0.0f;
}
for (int i = 0; i < node->totprim; i++) {
const MLoopTri *lt = &pbvh->looptri[node->prim_indices[i]];
if (pbvh->face_sets[lt->poly] < 0) {
/* Skip hidden faces. */
continue;
}
MVert *mv1 = pbvh->verts + pbvh->mloop[lt->tri[0]].v;
MVert *mv2 = pbvh->verts + pbvh->mloop[lt->tri[1]].v;
MVert *mv3 = pbvh->verts + pbvh->mloop[lt->tri[2]].v;
pbvh->face_areas[lt->poly] += area_tri_v3(mv1->co, mv2->co, mv3->co);
}
break;
}
case PBVH_BMESH: {
BMFace *f;
const int cd_face_area = pbvh->cd_face_area;
@ -4297,51 +4337,204 @@ void BKE_pbvh_check_tri_areas(PBVH *pbvh, PBVHNode *node)
}
}
static void pbvh_pmap_to_edges_add(PBVH *pbvh,
SculptVertRef vertex,
int **r_edges,
int *r_edges_size,
bool *heap_alloc,
int e,
int p,
int *len,
int **r_polys)
{
for (int i = 0; i < *len; i++) {
if ((*r_edges)[i] == e) {
if ((*r_polys)[i * 2 + 1] == -1) {
(*r_polys)[i * 2 + 1] = p;
}
return;
}
}
if (*len >= *r_edges_size) {
int newsize = *len + ((*len) >> 1) + 1;
*heap_alloc = true;
int *r_edges_new = MEM_malloc_arrayN(newsize, sizeof(*r_edges_new), "r_edges_new");
int *r_polys_new = MEM_malloc_arrayN(newsize * 2, sizeof(*r_polys_new), "r_polys_new");
memcpy((void *)r_edges_new, (void *)*r_edges, sizeof(int) * (*r_edges_size));
memcpy((void *)r_polys_new, (void *)(*r_polys), sizeof(int) * 2 * (*r_edges_size));
*r_edges_size = newsize;
if (*heap_alloc) {
MEM_freeN(*r_polys);
MEM_freeN(*r_edges);
}
*r_edges = r_edges_new;
*r_polys = r_polys_new;
*heap_alloc = true;
}
(*r_polys)[*len * 2] = p;
(*r_polys)[*len * 2 + 1] = -1;
(*r_edges)[*len] = e;
(*len)++;
}
void BKE_pbvh_pmap_to_edges(PBVH *pbvh,
SculptVertRef vertex,
int **r_edges,
int *r_edges_size,
bool *r_heap_alloc,
int **r_polys)
{
MeshElemMap *map = pbvh->pmap + vertex.i;
int len = 0;
for (int i = 0; i < map->count; i++) {
const MPoly *mp = pbvh->mpoly + map->indices[i];
const MLoop *ml = pbvh->mloop + mp->loopstart;
if (pbvh->face_sets[map->indices[i]] < 0) {
/* Skip connectivity from hidden faces. */
continue;
}
for (int j = 0; j < mp->totloop; j++, ml++) {
if (ml->v == vertex.i) {
pbvh_pmap_to_edges_add(pbvh,
vertex,
r_edges,
r_edges_size,
r_heap_alloc,
ME_POLY_LOOP_PREV(pbvh->mloop, mp, j)->e,
map->indices[i],
&len,
r_polys);
pbvh_pmap_to_edges_add(pbvh,
vertex,
r_edges,
r_edges_size,
r_heap_alloc,
ml->e,
map->indices[i],
&len,
r_polys);
}
}
}
*r_edges_size = len;
}
void BKE_pbvh_set_vemap(PBVH *pbvh, MeshElemMap *vemap)
{
pbvh->vemap = vemap;
}
void BKE_pbvh_get_vert_face_areas(PBVH *pbvh, SculptVertRef vertex, float *r_areas, int valence)
{
if (BKE_pbvh_type(pbvh) != PBVH_BMESH) {
// not supported
for (int i = 0; i < valence; i++) {
r_areas[i] = 1.0f;
}
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES: {
int *edges = BLI_array_alloca(edges, 16);
int *polys = BLI_array_alloca(polys, 32);
bool heap_alloc = false;
int len = 16;
return;
}
BKE_pbvh_pmap_to_edges(pbvh, vertex, &edges, &len, &heap_alloc, &polys);
len = MIN2(len, valence);
BMVert *v = (BMVert *)vertex.i;
BMEdge *e = v->e;
if (pbvh->vemap) {
/* sort poly references by vemap edge ordering */
MeshElemMap *emap = pbvh->vemap + vertex.i;
if (!e) {
for (int i = 0; i < valence; i++) {
r_areas[i] = 1.0f;
}
int *polys_old = BLI_array_alloca(polys, len * 2);
memcpy((void *)polys_old, (void *)polys, sizeof(int) * len * 2);
return;
}
/* note that wire edges will break this, but
should only result in incorrect weights
and isn't worth fixing */
const int cd_face_area = pbvh->cd_face_area;
int j = 0;
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
if (emap->indices[i] == edges[j]) {
polys[i * 2] = polys_old[j * 2];
polys[i * 2 + 1] = polys_old[j * 2 + 1];
}
}
}
}
for (int i = 0; i < len; i++) {
r_areas[i] = pbvh->face_areas[polys[i * 2]];
do {
float w = 0.0f;
if (polys[i * 2 + 1] != -1) {
r_areas[i] += pbvh->face_areas[polys[i * 2 + 1]];
r_areas[i] *= 0.5f;
}
}
if (!e->l) {
w = 0.0f;
}
else {
w += BM_ELEM_CD_GET_FLOAT(e->l->f, cd_face_area) * 0.5f;
w += BM_ELEM_CD_GET_FLOAT(e->l->radial_next->f, cd_face_area) * 0.5f;
}
if (heap_alloc) {
MEM_freeN(edges);
MEM_freeN(polys);
}
if (j >= valence) {
printf("%s: error, corrupt edge cycle\n", __func__);
break;
}
case PBVH_BMESH: {
BMVert *v = (BMVert *)vertex.i;
BMEdge *e = v->e;
r_areas[j++] = w;
if (!e) {
for (int i = 0; i < valence; i++) {
r_areas[i] = 1.0f;
}
e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
} while (e != v->e);
return;
}
const int cd_face_area = pbvh->cd_face_area;
int j = 0;
do {
float w = 0.0f;
if (!e->l) {
w = 0.0f;
}
else {
w += BM_ELEM_CD_GET_FLOAT(e->l->f, cd_face_area) * 0.5f;
w += BM_ELEM_CD_GET_FLOAT(e->l->radial_next->f, cd_face_area) * 0.5f;
}
if (j >= valence) {
printf("%s: error, corrupt edge cycle\n", __func__);
break;
}
r_areas[j++] = w;
e = v == e->v1 ? e->v1_disk_link.next : e->v2_disk_link.next;
} while (e != v->e);
for (; j < valence; j++) {
r_areas[j] = 1.0f;
}
break;
}
default:
// not supported
for (int i = 0; i < valence; i++) {
r_areas[i] = 1.0f;
}
break;
}
}
void BKE_pbvh_set_stroke_id(PBVH *pbvh, int stroke_id)

View File

@ -158,6 +158,7 @@ struct PBVH {
int depth_limit;
/* Mesh data */
struct MeshElemMap *pmap, *vemap;
const struct Mesh *mesh;
MVert *verts;
const MPoly *mpoly;
@ -171,6 +172,7 @@ struct PBVH {
int face_sets_color_seed;
int face_sets_color_default;
int *face_sets;
float *face_areas;
/* Grid Data */
CCGKey gridkey;

View File

@ -1517,6 +1517,16 @@ static void bm_log_face_values_swap(BMLog *log,
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
BMFace *f = bm_log_face_from_id(log, lf->id);
if (!f) {
fprintf(stderr, "%s: Failed to find face %d!\n", __func__, (int)lf->id);
continue;
}
if (f->head.htype != BM_FACE) {
fprintf(stderr, "%s: Got non-face for face ID %d, type was %d\n", __func__, (int)lf->id, (int)f->head.htype);
continue;
}
swap_v3_v3(f->no, lf->no);
SWAP(char, f->head.hflag, lf->hflag);
SWAP(short, f->mat_nr, lf->mat_nr);

View File

@ -24,6 +24,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_array.h"
#include "BLI_blenlib.h"
#include "BLI_dial_2d.h"
@ -879,52 +880,7 @@ bool SCULPT_temp_customlayer_has(SculptSession *ss,
bool SCULPT_temp_customlayer_release(SculptSession *ss, Object *ob, SculptCustomLayer *scl)
{
AttributeDomain domain = scl->domain;
if (scl->released) {
return false;
}
// remove from layers_to_free list if necassary
for (int i = 0; scl->data && i < ss->tot_layers_to_free; i++) {
if (ss->layers_to_free[i] && ss->layers_to_free[i]->data == scl->data) {
MEM_freeN(ss->layers_to_free[i]);
ss->layers_to_free[i] = NULL;
}
}
scl->released = true;
if (!scl->from_bmesh) {
// for now, don't clean up bmesh temp layers
if (scl->is_cdlayer && BKE_pbvh_type(ss->pbvh) != PBVH_GRIDS) {
CustomData *cdata = NULL;
int totelem = 0;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = ss->vdata;
totelem = ss->totvert;
break;
case ATTR_DOMAIN_FACE:
cdata = ss->pdata;
totelem = ss->totfaces;
break;
default:
printf("error, unknown domain in %s\n", __func__);
return false;
}
CustomData_free_layer(cdata, scl->layer->type, totelem, scl->layer - cdata->layers);
SCULPT_update_customdata_refs(ss, ob);
}
else {
MEM_SAFE_FREE(scl->data);
}
scl->data = NULL;
}
return true;
return BKE_sculptsession_customlayer_release(ob, scl);
}
bool SCULPT_temp_customlayer_get(SculptSession *ss,
@ -1906,7 +1862,6 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
{
int index = BKE_pbvh_vertex_index_to_table(ss->pbvh, vertex);
MeshElemMap *vert_map = &ss->pmap[index];
iter->size = 0;
iter->num_duplicates = 0;
iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
@ -1916,6 +1871,26 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
iter->has_edge = true;
iter->no_free = false;
int *edges = BLI_array_alloca(edges, SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY);
int *unused_polys = BLI_array_alloca(unused_polys, SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY * 2);
bool heap_alloc = false;
int len = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
BKE_pbvh_pmap_to_edges(ss->pbvh, vertex, &edges, &len, &heap_alloc, &unused_polys);
/* length of array is now in len */
for (int i = 0; i < len; i++) {
MEdge *e = ss->medge + edges[i];
int v2 = e->v1 == vertex.i ? e->v2 : e->v1;
sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v2), BKE_pbvh_make_eref(edges[i]), v2);
}
if (heap_alloc) {
MEM_freeN(unused_polys);
MEM_freeN(edges);
}
#if 0
for (int i = 0; i < ss->pmap[index].count; i++) {
if (ss->face_sets[vert_map->indices[i]] < 0) {
/* Skip connectivity from hidden faces. */
@ -1950,6 +1925,7 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
}
}
}
#endif
if (ss->fake_neighbors.use_fake_neighbors) {
BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
@ -2166,6 +2142,7 @@ static NeighborCacheItem *neighbor_cache_get(const SculptSession *ss,
case PBVH_FACES:
// use vemap if it exists, so result is in disk cycle order
if (ss->vemap) {
BKE_pbvh_set_vemap(ss->pbvh, ss->vemap);
sculpt_vertex_neighbors_get_faces_vemap(ss, vertex, &ni);
}
else {
@ -2231,8 +2208,9 @@ void SCULPT_vertex_neighbors_get(const SculptSession *ss,
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
// use vemap if it exists, so result is in disk cycle order
/* use vemap if it exists, so result is in disk cycle order */
if (ss->vemap) {
BKE_pbvh_set_vemap(ss->pbvh, ss->vemap);
sculpt_vertex_neighbors_get_faces_vemap(ss, vertex, iter);
}
else {
@ -6152,7 +6130,8 @@ static void SCULPT_run_commandlist(
float radius;
if (BRUSHSET_GET_INT(cmd->params_final, radius_unit, NULL)) {
radius = BRUSHSET_GET_FLOAT(cmd->params_final, unprojected_radius, &ss->cache->input_mapping);
radius = BRUSHSET_GET_FLOAT(
cmd->params_final, unprojected_radius, &ss->cache->input_mapping);
}
else {
radius = BRUSHSET_GET_FLOAT(cmd->params_final, radius, &ss->cache->input_mapping);

View File

@ -337,6 +337,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
// const float hard_edge_fac = ss->filter_cache->hard_edge_fac;
const bool hard_edge_mode = ss->filter_cache->hard_edge_mode;
const float bound_smooth_radius = ss->filter_cache->bound_smooth_radius;
const float bevel_smooth_fac = ss->filter_cache->bevel_smooth_fac;
if (ELEM(filter_type,
MESH_FILTER_SMOOTH,
@ -403,6 +404,7 @@ static void mesh_filter_task_cb(void *__restrict userdata,
.preserve_fset_boundaries = preserve_fset_boundaries,
.do_weighted_smooth = weighted,
.bound_smooth_radius = bound_smooth_radius,
.bevel_smooth_factor = bevel_smooth_fac,
.bound_scl = bsmooth > 0.0f ? ss->custom_layers[SCULPT_SCL_SMOOTH_BDIS] : NULL}));
sub_v3_v3v3(val, avg, orig_co);
@ -909,6 +911,7 @@ static int sculpt_mesh_filter_invoke(bContext *C, wmOperator *op, const wmEvent
// ss->filter_cache->hard_edge_fac = RNA_float_get(op->ptr, "hard_edge_fac");
ss->filter_cache->hard_edge_mode = RNA_boolean_get(op->ptr, "hard_edge_mode");
ss->filter_cache->bound_smooth_radius = RNA_float_get(op->ptr, "bound_smooth_radius");
ss->filter_cache->bevel_smooth_fac = RNA_float_get(op->ptr, "bevel_smooth_fac");
if (filter_type == MESH_FILTER_SMOOTH && ss->filter_cache->bound_smooth_radius != 0.0f) {
/*ensure ss->custom_layers[SCULPT_SCL_SMOOTH_BDIS] exists*/
@ -1034,4 +1037,6 @@ void SCULPT_OT_mesh_filter(struct wmOperatorType *ot)
"Radius to bevel hard edges, 0 disables",
0.0f,
5.0f);
RNA_def_float(
ot->srna, "bevel_smooth_fac", 0.0f, 0.0f, 1.0f, "Bevel Smoothness", "", 0.0f, 1.0f);
}

View File

@ -408,6 +408,7 @@ typedef struct SculptSmoothArgs {
float bound_smooth_radius; // if 0, ss->cache->radius will be used
float vel_smooth_fac;
SculptCustomLayer *vel_scl;
float bevel_smooth_factor;
} SculptSmoothArgs;
/* Utils. */
@ -1718,6 +1719,7 @@ typedef struct FilterCache {
float hard_edge_fac;
bool hard_edge_mode;
float bound_smooth_radius;
float bevel_smooth_fac;
} FilterCache;
void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache,

View File

@ -867,7 +867,7 @@ static bool sculpt_mask_by_color_contiguous_floodfill_cb(
int to_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, to_v);
int from_v_i = BKE_pbvh_vertex_index_to_table(ss->pbvh, from_v);
const float current_color[4];
float current_color[4];
SCULPT_vertex_color_get(ss, to_v, current_color);

View File

@ -409,6 +409,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float avg[3] = {0.0f, 0.0f, 0.0f};
const float bevel_smooth_factor = 1.0f - args->bevel_smooth_factor;
float projection = args->projection;
float slide_fset = args->slide_fset;
float bound_smooth = args->bound_smooth;
@ -472,6 +473,8 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
BKE_pbvh_get_vert_face_areas(ss->pbvh, vertex, areas, val);
/* normalize areas, then apply a 0.25/val floor */
float totarea = 0.0f;
for (int i = 0; i < val; i++) {
@ -640,20 +643,14 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
float radius;
if (!args->bound_smooth_radius && ss->cache) {
radius = ss->cache->radius * 1.0f;
radius = ss->cache->radius;
}
else {
radius = args->bound_smooth_radius * 1.0f;
radius = args->bound_smooth_radius;
}
radius = radius == 0.0f ? 0.0001f : radius;
float th = radius - b1_orig;
th = MAX2(th, 0.0f);
th /= radius;
// th = 1.0 - th;
#if 0
float color[4];
SCULPT_vertex_color_get(ss,ni.vertex, color);
@ -664,24 +661,18 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
SCULPT_vertex_color_set(ss, ni.vertex, color);
#endif
float fac = bound_smooth;
fac = MIN2(fac * 4.0f, 1.0f);
fac = powf(fac, 0.2);
// th *= fac;
// th *= shell_angle_to_dist(shellth * 1.0) * 0.5;
/* jump above the v,no2 plane, using distance from plane (which doubles after this)*/
// sub_v3_v3(tmp, co);
// madd_v3_v3fl(tmp, no2, th * dot_v3v3(no2, tmp));
// add_v3_v3(tmp, co);
th = min_ff(b1_orig / radius, 1.0f);
float th = min_ff(b1_orig / radius, bevel_smooth_factor);
/*ok this bit smoothes the bevel edges. why? hit on it
by accident.*/
/*smooth bevel edges slightly to avoid artifacts.
not entire sure why this works.*/
float shellth = saacos(dot_v3v3(no, no2));
shellth = safe_shell_angle_to_dist(shellth * 2.0);
th /= 0.00001 + shellth;
shellth = safe_shell_angle_to_dist(shellth * 2.0f);
th /= 0.00001f + shellth;
sub_v3_v3v3(tmp, co2, co);
madd_v3_v3fl(tmp, no, -dot_v3v3(no, tmp) * th);