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:
parent
e5804dc607
commit
e21c21bbf9
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue