Sculpt Dyntopo: fix bug in dyntopo brush spacing.

This commit is contained in:
Joseph Eagar 2021-06-25 11:49:28 -07:00
parent 17d4c7abb1
commit d293de425f
7 changed files with 122 additions and 77 deletions

View File

@ -817,7 +817,7 @@ BMVert *BKE_pbvh_vert_create_bmesh(
PBVHNode *BKE_pbvh_node_from_face_bmesh(PBVH *pbvh, BMFace *f)
{
return BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
return pbvh->nodes + BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
}
BMFace *BKE_pbvh_face_create_bmesh(PBVH *pbvh,
@ -1537,7 +1537,7 @@ typedef struct EdgeQueueThreadData {
int size;
} EdgeQueueThreadData;
void edge_thread_data_insert(EdgeQueueThreadData *tdata, BMEdge *e)
static void edge_thread_data_insert(EdgeQueueThreadData *tdata, BMEdge *e)
{
if (tdata->size <= tdata->totedge) {
tdata->size = (tdata->totedge + 1) << 1;
@ -1859,9 +1859,9 @@ static void long_edge_queue_edge_add_recursive_2(EdgeQueueThreadData *tdata,
}
}
void long_edge_queue_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
static void long_edge_queue_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
EdgeQueueThreadData *tdata = ((EdgeQueueThreadData *)userdata) + n;
PBVHNode *node = tdata->node;
@ -2246,16 +2246,6 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
mv_new->flag |= DYNVERT_BOUNDARY;
}
/* update paint mask */
if (eq_ctx->cd_dyn_vert != -1) {
float mask_v1 = DYNTOPO_MASK(eq_ctx->cd_dyn_vert, e->v1);
float mask_v2 = DYNTOPO_MASK(eq_ctx->cd_dyn_vert, e->v2);
float mask_v_new = 0.5f * (mask_v1 + mask_v2);
// BM_ELEM_CD_SET_FLOAT(v_new, eq_ctx->cd_vert_mask_offset, mask_v_new);
}
/* For each face, add two new triangles and delete the original */
for (int i = 0; i < (int)edge_loops->count; i++) {
BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
@ -2850,7 +2840,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts");
double time = PIL_check_seconds_timer();
RNG *rng = BLI_rng_new(time * 1000.0f);
RNG *rng = BLI_rng_new((unsigned int)(time * 1000.0f));
//#define TEST_COLLAPSE
#ifdef TEST_COLLAPSE
@ -3637,26 +3627,33 @@ bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
return modified;
}
static bool cleanup_valence_3_4(PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
const bool use_projected)
// this function is being buggy under clang's optimizer, at least on windows
#ifdef __clang__
# define CLANG_OPT_BUG __attribute__((optnone))
#else
# define CLANG_OPT_BUG
#endif
CLANG_OPT_BUG static bool cleanup_valence_3_4(PBVH *pbvh,
const float center[3],
const float view_normal[3],
float radius,
const bool use_frontface,
const bool use_projected)
{
bool modified = false;
BMVert **relink_verts = NULL;
BLI_array_staticdeclare(relink_verts, 1024);
float radius2 = radius * 1.25;
float rsqr = radius2 * radius2;
GSet *vset = BLI_gset_ptr_new("vset");
for (int n = 0; n < pbvh->totnode; n++) {
PBVHNode *node = pbvh->nodes + n;
/* Check leaf nodes marked for topology update */
bool ok = (node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology);
ok = ok && !(node->flag & PBVH_FullyHidden);
ok = ok && !(node->flag & (PBVH_FullyHidden | PBVH_Delete));
if (!ok) {
continue;
@ -3665,12 +3662,12 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
BMVert *v;
TGSET_ITER (v, node->bm_unique_verts) {
if (len_squared_v3v3(v->co, center) >= rsqr) {
if (len_squared_v3v3(v->co, center) >= rsqr || !v->e) {
continue;
}
const int val = BM_vert_edge_count(v);
if (val < 3 || val > 4) {
if (val != 4 && val != 3) {
continue;
}
@ -3678,7 +3675,6 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
BMLoop *l;
BMLoop *ls[4];
BMVert *vs[4];
BMEdge *es[4];
l = v->e->l;
@ -3729,14 +3725,12 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
continue;
}
pbvh_bmesh_vert_remove(pbvh, v);
BM_log_vert_removed(pbvh->bm_log, v, pbvh->cd_vert_mask_offset);
BLI_array_clear(relink_verts);
BMFace *f;
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
int ni2 = BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset);
if (ni2 != DYNTOPO_NODE_NONE) {
PBVHNode *node2 = pbvh->nodes + ni2;
@ -3747,6 +3741,8 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
}
}
// pbvh_bmesh_vert_remove(pbvh, v);
modified = true;
l = v->e->l;
@ -3761,6 +3757,9 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
normal_tri_v3(
f1->no, f1->l_first->v->co, f1->l_first->next->v->co, f1->l_first->prev->v->co);
}
else {
printf("eek!\n");
}
if (val == 4 && vs[0] != vs[2] && vs[2] != vs[3] && vs[0] != vs[3]) {
vs[0] = ls[0]->v;
@ -3779,6 +3778,9 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
f2->no, f2->l_first->v->co, f2->l_first->next->v->co, f2->l_first->prev->v->co);
BM_log_face_added(pbvh->bm_log, f2);
}
else {
printf("eek2!\n");
}
if (f1) {
SWAP(void *, f1->l_first->head.data, ls[0]->head.data);
@ -3789,23 +3791,11 @@ static bool cleanup_valence_3_4(PBVH *pbvh,
}
BM_vert_kill(pbvh->bm, v);
#if 0
for (int j = 0; j < pbvh->totnode; j++) {
PBVHNode *node2 = pbvh->nodes + j;
if (!node2->bm_unique_verts || !node2->bm_other_verts) { //(node2->flag & PBVH_Leaf)) {
continue;
}
BLI_table_gset_remove(node2->bm_unique_verts, v, NULL);
BLI_table_gset_remove(node2->bm_other_verts, v, NULL);
}
#endif
}
TGSET_ITER_END
}
BLI_array_free(relink_verts);
BLI_gset_free(vset, NULL);
if (modified) {
pbvh->bm->elem_index_dirty |= BM_VERT | BM_FACE | BM_EDGE;
@ -4308,7 +4298,6 @@ static void pbvh_bmesh_join_subnodes(PBVH *pbvh, PBVHNode *node, PBVHNode *paren
static void BKE_pbvh_bmesh_correct_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *parent)
{
const int size_lower = pbvh->leaf_limit - (pbvh->leaf_limit >> 1);
const int size_higher = pbvh->leaf_limit + (pbvh->leaf_limit >> 1);
if (node->flag & PBVH_Leaf) {
// pbvh_bmesh_node_limit_ensure(pbvh, (int)(node - pbvh->nodes));
@ -4524,8 +4513,6 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
bvh->totnode = j;
BMVert *v;
// set vert/face node indices again
for (int i = 0; i < bvh->totnode; i++) {
PBVHNode *n = bvh->nodes + i;

View File

@ -68,9 +68,7 @@ typedef struct BMThreadData {
# define ELEM_NEXT(type, ptr, size) ((type *)(((char *)ptr) + size))
ATTR_NO_OPT void bm_vert_task(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
void bm_vert_task(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls)
{
BMThreadData *data = userdata;
BMesh *bm = data->bm;
@ -306,10 +304,10 @@ static void bm_mesh_cd_flag_apply(BMesh *bm, const char cd_flag)
}
}
ATTR_NO_OPT BMesh *BM_mesh_bm_from_me_threaded(BMesh *bm,
Object *ob,
const Mesh *me,
const struct BMeshFromMeshParams *params)
BMesh *BM_mesh_bm_from_me_threaded(BMesh *bm,
Object *ob,
const Mesh *me,
const struct BMeshFromMeshParams *params)
{
if (!bm) {
bm = MEM_callocN(sizeof(BMesh), "BM_mesh_bm_from_me_threaded bm");

View File

@ -846,14 +846,14 @@ static bool modifier_apply_obdata(
return true;
}
ATTR_NO_OPT bool ED_object_modifier_apply(Main *bmain,
ReportList *reports,
Depsgraph *depsgraph,
Scene *scene,
Object *ob,
ModifierData *md,
int mode,
bool keep_modifier)
bool ED_object_modifier_apply(Main *bmain,
ReportList *reports,
Depsgraph *depsgraph,
Scene *scene,
Object *ob,
ModifierData *md,
int mode,
bool keep_modifier)
{
if (BKE_object_is_in_editmode(ob)) {
BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in edit mode");
@ -1395,8 +1395,7 @@ void OBJECT_OT_modifier_move_to_index(wmOperatorType *ot)
/** \name Apply Modifier Operator
* \{ */
#include "BLI_compiler_attrs.h"
ATTR_NO_OPT static bool modifier_apply_poll_ex(bContext *C, bool allow_shared)
static bool modifier_apply_poll_ex(bContext *C, bool allow_shared)
{
if (!edit_modifier_poll_generic(C, &RNA_Modifier, 0, false, false)) {
return false;

View File

@ -718,6 +718,58 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor)
return 1.0f / max;
}
static float paint_space_get_final_size_intern(
bContext *C, const Scene *scene, PaintStroke *stroke, float pressure, float dpressure)
{
ePaintMode mode = BKE_paintmode_get_active_from_context(C);
float size = BKE_brush_size_get(scene, stroke->brush) * pressure;
if (paint_stroke_use_scene_spacing(stroke->brush, mode)) {
if (!BKE_brush_use_locked_size(scene, stroke->brush)) {
float last_object_space_position[3];
mul_v3_m4v3(
last_object_space_position, stroke->vc.obact->imat, stroke->last_world_space_position);
size = paint_calc_object_space_radius(&stroke->vc, last_object_space_position, size);
}
else {
size = BKE_brush_unprojected_radius_get(scene, stroke->brush) * pressure;
}
}
return size;
}
static float paint_space_get_final_size(bContext *C,
const Scene *scene,
PaintStroke *stroke,
float pressure,
float dpressure,
float length)
{
if (BKE_brush_use_size_pressure(stroke->brush)) {
/* use pressure to modify size. set spacing so that at 100%, the circles
* are aligned nicely with no overlap. for this the spacing needs to be
* the average of the previous and next size. */
float s = paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
float q = s * dpressure / (2.0f * length);
float pressure_fac = (1.0f + q) / (1.0f - q);
float last_size_pressure = stroke->last_pressure;
float new_size_pressure = stroke->last_pressure * pressure_fac;
/* average spacing */
float last_size = paint_space_get_final_size_intern(
C, scene, stroke, last_size_pressure, pressure);
float new_size = paint_space_get_final_size_intern(
C, scene, stroke, new_size_pressure, pressure);
return 0.5f * (last_size + new_size);
}
else {
return paint_space_get_final_size_intern(C, scene, stroke, 1.0, 0.0);
}
}
static float paint_space_stroke_spacing_variable(bContext *C,
const Scene *scene,
PaintStroke *stroke,
@ -748,6 +800,8 @@ static float paint_space_stroke_spacing_variable(bContext *C,
return paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure);
}
#include "BLI_compiler_attrs.h"
/* For brushes with stroke spacing enabled, moves mouse in steps
* towards the final mouse location. */
static int paint_space_stroke(bContext *C,
@ -817,9 +871,16 @@ static int paint_space_stroke(bContext *C,
ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush,
spacing / no_pressure_spacing);
if (use_scene_spacing) {
float size = paint_space_get_final_size(C, scene, stroke, pressure, dpressure, length);
stroke->stroke_distance += spacing / stroke->zoom_2d;
stroke->stroke_distance_t += (spacing / stroke->zoom_2d) / stroke->ups->pixel_radius;
stroke->stroke_distance += stroke->ups->pixel_radius * spacing / size;
stroke->stroke_distance_t += spacing / size;
}
else {
stroke->stroke_distance += spacing / stroke->zoom_2d;
stroke->stroke_distance_t += (spacing / stroke->zoom_2d) / stroke->ups->pixel_radius;
}
paint_brush_stroke_add_step(C, op, mouse, pressure);

View File

@ -6658,7 +6658,7 @@ typedef struct DynTopoAutomaskState {
SculptSession *ss;
} DynTopoAutomaskState;
ATTR_NO_OPT static float sculpt_topology_automasking_cb(SculptVertRef vertex, void *vdata)
static float sculpt_topology_automasking_cb(SculptVertRef vertex, void *vdata)
{
DynTopoAutomaskState *state = (DynTopoAutomaskState *)vdata;
float mask = SCULPT_automasking_factor_get(state->cache, state->ss, vertex);
@ -6667,7 +6667,7 @@ ATTR_NO_OPT static float sculpt_topology_automasking_cb(SculptVertRef vertex, vo
return mask * mask2;
}
ATTR_NO_OPT static float sculpt_topology_automasking_mask_cb(SculptVertRef vertex, void *vdata)
static float sculpt_topology_automasking_mask_cb(SculptVertRef vertex, void *vdata)
{
DynTopoAutomaskState *state = (DynTopoAutomaskState *)vdata;
return 1.0f - SCULPT_vertex_mask_get(state->ss, vertex);

View File

@ -148,9 +148,9 @@ static bool SCULPT_automasking_needs_factors_cache(const Sculpt *sd, const Brush
return false;
}
ATTR_NO_OPT float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
SculptSession *ss,
SculptVertRef vert)
float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
SculptSession *ss,
SculptVertRef vert)
{
float mask = 1.0f;
bool do_concave;
@ -453,7 +453,7 @@ static void SCULPT_concavity_automasking_init(Object *ob,
// BKE_pbvh_vertex_iter_begin
}
ATTR_NO_OPT AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob)
AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob)
{
SculptSession *ss = ob->sculpt;
const int totvert = SCULPT_vertex_count_get(ss);

View File

@ -239,10 +239,10 @@ static int gpu_comp_map[] = {
4 // GPU_COMP_I10,
};
ATTR_NO_OPT static void convert_gpu_data(void *src,
void *dst,
GPUVertCompType srcType,
GPUVertCompType dstType)
static void convert_gpu_data(void *src,
void *dst,
GPUVertCompType srcType,
GPUVertCompType dstType)
{
if (srcType == dstType) {
memcpy(dst, src, gpu_comp_map[(int)srcType]);
@ -309,7 +309,7 @@ ATTR_NO_OPT static void convert_gpu_data(void *src,
GPU_vertbuf_attr_set(vert_buf, g_vbo_id.pos, v_index, v->co);
*/
ATTR_NO_OPT static void set_cd_data_bmesh(
static void set_cd_data_bmesh(
GPUVertBuf *vert_buf, CDAttrLayers *attr_array, int attr_array_len, BMElem *elem, int vertex)
{
for (int i = 0; i < attr_array_len; i++) {