Fix infinite loop bug

This commit is contained in:
Joseph Eagar 2021-04-13 01:08:05 -07:00
parent e07a95b86d
commit ed15d0c1b9
7 changed files with 511 additions and 310 deletions

View File

@ -33,11 +33,13 @@
extern "C" {
#endif
typedef struct {
int64_t i;
typedef struct SculptVertRef {
intptr_t i;
} SculptVertRef;
typedef SculptVertRef SculptFaceRef;
typedef struct SculptFaceRef {
intptr_t i;
} SculptFaceRef;
BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
{
@ -51,6 +53,23 @@ BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
return ret;
}
typedef struct PBVHTri {
int v[3]; // references into PBVHTriBuf->verts
float no[3];
SculptFaceRef f;
} PBVHTri;
typedef struct PBVHTriBuf {
PBVHTri *tris;
SculptVertRef *verts;
int tottri, totvert;
//private field
intptr_t *loops;
int totloop;
} PBVHTriBuf;
struct BMLog;
struct BMesh;
struct BMVert;
@ -175,7 +194,8 @@ typedef enum {
PBVH_UpdateTopology = 1 << 13,
PBVH_UpdateColor = 1 << 14,
PBVH_Delete = 1 << 15,
PBVH_UpdateCurvatureDir = 1 << 16
PBVH_UpdateCurvatureDir = 1 << 16,
PBVH_UpdateTris = 1 << 17
} PBVHNodeFlags;
typedef struct PBVHFrustumPlanes {
@ -234,10 +254,17 @@ void BKE_pbvh_free(PBVH *pbvh);
/** update original data, only data whose r_** parameters are passed in will be updated*/
void BKE_pbvh_bmesh_update_origvert(
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color);
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo);
void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node);
/**
checks if original data needs to be updated for v, and if so updates it. Stroke_id
is provided by the sculpt code and is used to detect updates. The reason we do it
inside the verts and not in the nodes is to allow splitting of the pbvh during the stroke.
*/
bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, struct BMVert *v, int stroke_id);
/* Hierarchical Search in the BVH, two methods:
* - for each hit calling a callback
* - gather nodes in an array (easy to multithread) */
@ -261,7 +288,8 @@ void BKE_pbvh_raycast(PBVH *pbvh,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original);
bool original,
int stroke_id);
bool BKE_pbvh_node_raycast(PBVH *pbvh,
PBVHNode *node,
@ -273,9 +301,11 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
float *depth,
SculptVertRef *active_vertex_index,
SculptFaceRef *active_face_grid_index,
float *face_normal);
float *face_normal,
int stroke_id);
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
bool BKE_pbvh_bmesh_node_raycast_detail(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
@ -300,7 +330,8 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq);
float *dist_sq,
int stroke_id);
/* Drawing */
@ -355,7 +386,7 @@ void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_
typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
PBVH_Cleanup = 4, //dissolve verts surrounded by either 3 or 4 triangles then triangulate
PBVH_Cleanup = 4, // dissolve verts surrounded by either 3 or 4 triangles then triangulate
} PBVHTopologyUpdateMode;
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
@ -422,7 +453,8 @@ bool BKE_pbvh_node_frustum_exclude_AABB(PBVHNode *node, void *frustum);
struct TableGSet *BKE_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct TableGSet *BKE_pbvh_bmesh_node_other_verts(PBVHNode *node);
struct TableGSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node);
void BKE_pbvh_bmesh_node_save_ortri(struct BMesh *bm, PBVHNode *node);
// now generated PBVHTris
void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh);
/* Update Bounding Box/Redraw and clear flags */
@ -622,10 +654,6 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
void BKE_pbvh_node_free_proxies(PBVHNode *node);
PBVHProxyNode *BKE_pbvh_node_add_proxy(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_gather_proxies(PBVH *pbvh, PBVHNode ***r_array, int *r_tot);
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
float (**r_orco_coords)[3]);
bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node);
@ -661,6 +689,10 @@ bool BKE_pbvh_curvature_update_get(PBVHNode *node);
int BKE_pbvh_get_totnodes(PBVH *pbvh);
void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node);
PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node);
void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node);
#ifdef __cplusplus
}
#endif

View File

@ -250,7 +250,7 @@ void pbvh_grow_nodes(PBVH *pbvh, int totnode)
pbvh->totnode = totnode;
for (int i=0; i<pbvh->totnode; i++) {
for (int i = 0; i < pbvh->totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
if (!node->id) {
@ -1866,19 +1866,23 @@ void BKE_pbvh_node_mark_normals_update(PBVHNode *node)
node->flag |= PBVH_UpdateNormals | PBVH_UpdateCurvatureDir;
}
void BKE_pbvh_node_mark_curvature_update(PBVHNode *node) {
void BKE_pbvh_node_mark_curvature_update(PBVHNode *node)
{
node->flag |= PBVH_UpdateCurvatureDir;
}
void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state) {
void BKE_pbvh_curvature_update_set(PBVHNode *node, bool state)
{
if (state) {
node->flag |= PBVH_UpdateCurvatureDir;
} else {
}
else {
node->flag &= ~PBVH_UpdateCurvatureDir;
}
}
bool BKE_pbvh_curvature_update_get(PBVHNode *node) {
bool BKE_pbvh_curvature_update_get(PBVHNode *node)
{
return node->flag & PBVH_UpdateCurvatureDir;
}
@ -2073,16 +2077,6 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
}
}
void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node,
int (**r_orco_tris)[3],
int *r_orco_tris_num,
float (**r_orco_coords)[3])
{
*r_orco_tris = node->bm_ortri;
*r_orco_tris_num = node->bm_tot_ortri;
*r_orco_coords = node->bm_orco;
}
/**
* \note doing a full search on all vertices here seems expensive,
* however this is important to avoid having to recalculate bound-box & sync the buffers to the
@ -2111,6 +2105,7 @@ bool BKE_pbvh_node_vert_update_check_any(PBVH *pbvh, PBVHNode *node)
typedef struct {
struct IsectRayAABB_Precalc ray;
bool original;
int stroke_id;
} RaycastData;
static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
@ -2137,12 +2132,14 @@ void BKE_pbvh_raycast(PBVH *pbvh,
void *data,
const float ray_start[3],
const float ray_normal[3],
bool original)
bool original,
int stroke_id)
{
RaycastData rcd;
isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
rcd.original = original;
rcd.stroke_id = stroke_id;
BKE_pbvh_search_callback_occluded(pbvh, ray_aabb_intersect, &rcd, cb, data);
}
@ -2431,7 +2428,8 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
float *depth,
SculptVertRef *active_vertex_index,
SculptFaceRef *active_face_grid_index,
float *face_normal)
float *face_normal,
int stroke_id)
{
bool hit = false;
@ -2466,7 +2464,9 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
break;
case PBVH_BMESH:
// BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT);
hit = pbvh_bmesh_node_raycast(node,
hit = pbvh_bmesh_node_raycast(pbvh,
node,
ray_start,
ray_normal,
isect_precalc,
@ -2474,7 +2474,8 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh,
use_origco,
active_vertex_index,
active_face_grid_index,
face_normal);
face_normal,
stroke_id);
break;
}
@ -2689,7 +2690,8 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq)
float *dist_sq,
int stroke_id)
{
bool hit = false;
@ -2708,7 +2710,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh,
break;
case PBVH_BMESH:
hit = pbvh_bmesh_node_nearest_to_ray(
node, ray_start, ray_normal, depth, dist_sq, use_origco);
pbvh, node, ray_start, ray_normal, depth, dist_sq, use_origco, stroke_id);
break;
}
@ -3240,7 +3242,8 @@ int BKE_pbvh_get_node_index(PBVH *pbvh, PBVHNode *node)
return (int)(node - pbvh->nodes);
}
int BKE_pbvh_get_totnodes(PBVH *pbvh) {
int BKE_pbvh_get_totnodes(PBVH *pbvh)
{
return pbvh->totnode;
}

View File

@ -308,10 +308,10 @@ static void pbvh_bmesh_node_finalize(PBVH *pbvh,
BKE_pbvh_node_mark_rebuild_draw(n);
BKE_pbvh_node_fully_hidden_set(n, !has_visible);
n->flag |= PBVH_UpdateNormals | PBVH_UpdateTopology | PBVH_UpdateCurvatureDir;
n->flag |= PBVH_UpdateNormals | PBVH_UpdateTopology | PBVH_UpdateCurvatureDir | PBVH_UpdateTris;
if (add_orco) {
BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, n);
BKE_pbvh_bmesh_check_tris(pbvh, n);
}
}
@ -515,7 +515,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index)
/* Likely this is already dirty. */
pbvh->bm->elem_index_dirty |= BM_FACE;
pbvh_bmesh_node_split(pbvh, bbc_array, node_index, pbvh->nodes[node_index].bm_ortri != NULL, 0);
pbvh_bmesh_node_split(pbvh, bbc_array, node_index, false, 0);
MEM_freeN(bbc_array);
@ -619,7 +619,7 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh,
BLI_table_gset_insert(node->bm_unique_verts, v);
BM_ELEM_CD_SET_INT(v, pbvh->cd_vert_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris;
/* Log the new vertex */
BM_log_vert_added(pbvh->bm_log, v, cd_vert_mask_offset);
@ -659,7 +659,7 @@ static BMFace *pbvh_bmesh_face_create(PBVH *pbvh,
BM_ELEM_CD_SET_INT(f, pbvh->cd_face_node_offset, node_index);
/* mark node for update */
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateTris;
node->flag &= ~PBVH_FullyHidden;
/* Log the new face */
@ -676,7 +676,7 @@ static BMFace *pbvh_bmesh_face_create(PBVH *pbvh,
BLI_table_gset_add(node->bm_unique_verts, l->v);
BM_ELEM_CD_SET_INT(l->v, cd_vert_node, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris;
}
else {
BLI_table_gset_add(node->bm_other_verts, l->v);
@ -831,7 +831,7 @@ static void pbvh_bmesh_vert_remove(PBVH *pbvh, BMVert *v)
f_node_index_prev = f_node_index;
PBVHNode *f_node = &pbvh->nodes[f_node_index];
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB | PBVH_UpdateTris;
/* Remove current ownership */
BLI_table_gset_remove(f_node->bm_other_verts, v, NULL);
@ -885,7 +885,7 @@ static void pbvh_bmesh_face_remove(PBVH *pbvh, BMFace *f)
BM_log_face_removed(pbvh->bm_log, f);
/* mark node for update */
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateTris;
}
static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
@ -904,19 +904,6 @@ static void pbvh_bmesh_edge_loops(BLI_Buffer *buf, BMEdge *e)
}
}
static void pbvh_bmesh_node_drop_orig(PBVHNode *node)
{
if (node->bm_orco) {
MEM_freeN(node->bm_orco);
}
if (node->bm_ortri) {
MEM_freeN(node->bm_ortri);
}
node->bm_orco = NULL;
node->bm_ortri = NULL;
node->bm_tot_ortri = 0;
}
/****************************** EdgeQueue *****************************/
struct EdgeQueue;
@ -2543,7 +2530,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
* note that we can often get-away without this but causes T48779 */
BM_LOOPS_OF_VERT_ITER_BEGIN (l, v_conn) {
PBVHNode *f_node = pbvh_bmesh_node_from_face(pbvh, l->f);
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB;
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB |
PBVH_UpdateTris;
}
BM_LOOPS_OF_VERT_ITER_END;
}
@ -2561,13 +2549,15 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
}
void BKE_pbvh_bmesh_update_origvert(
PBVH *pbvh, BMVert *v, float **r_co, float **r_no, float **r_color)
PBVH *pbvh, BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo)
{
float *co = NULL, *no = NULL;
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
BM_log_vert_before_modified(pbvh->bm_log, v, pbvh->cd_vert_mask_offset, r_color != NULL);
if (log_undo) {
BM_log_vert_before_modified(pbvh->bm_log, v, pbvh->cd_vert_mask_offset, r_color != NULL);
}
if (r_co || r_no) {
@ -2707,7 +2697,23 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
/************************* Called from pbvh.c *************************/
bool pbvh_bmesh_node_raycast(PBVHNode *node,
bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, BMVert *v, int stroke_id)
{
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
if (mv->stroke_id != stroke_id) {
void *dummy;
BKE_pbvh_bmesh_update_origvert(pbvh, v, &dummy, &dummy, &dummy, false);
mv->stroke_id = stroke_id;
return true;
}
return false;
}
bool pbvh_bmesh_node_raycast(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
@ -2715,57 +2721,83 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
bool use_original,
SculptVertRef *r_active_vertex_index,
SculptFaceRef *r_active_face_index,
float *r_face_normal)
float *r_face_normal,
int stroke_id)
{
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
float nearest_vertex_dist = 1e17;
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
BKE_pbvh_bmesh_check_tris(pbvh, node);
bool hit2 = ray_face_intersection_tri(ray_start,
isect_precalc,
node->bm_orco[t[0]],
node->bm_orco[t[1]],
node->bm_orco[t[2]],
depth);
PBVHTriBuf *tribuf = node->tribuf;
const int cd_dyn_vert = pbvh->cd_dyn_vert;
for (int i = 0; i < node->tribuf->tottri; i++) {
PBVHTri *tri = tribuf->tris + i;
BMVert *v1 = (BMVert *)tribuf->verts[tri->v[0]].i;
BMVert *v2 = (BMVert *)tribuf->verts[tri->v[1]].i;
BMVert *v3 = (BMVert *)tribuf->verts[tri->v[2]].i;
BMFace *f = (BMFace *)tri->f.i;
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
float *co1, *co2, *co3;
if (use_original) {
BKE_pbvh_bmesh_check_origdata(pbvh, v1, stroke_id);
BKE_pbvh_bmesh_check_origdata(pbvh, v2, stroke_id);
BKE_pbvh_bmesh_check_origdata(pbvh, v3, stroke_id);
co1 = BKE_PBVH_DYNVERT(cd_dyn_vert, v1)->origco;
co2 = BKE_PBVH_DYNVERT(cd_dyn_vert, v2)->origco;
co3 = BKE_PBVH_DYNVERT(cd_dyn_vert, v3)->origco;
}
else {
co1 = v1->co;
co2 = v2->co;
co3 = v3->co;
}
bool hit2 = ray_face_intersection_tri(ray_start, isect_precalc, co1, co2, co3, depth);
if (hit2) {
// ensure sculpt active vertex is set r_active_vertex_index
if (hit2) {
int k = 0;
BMFace *f = NULL;
TGSET_ITER_INDEX(f, node->bm_faces, k)
{
if (k == i) {
break;
for (int j = 0; j < 3; j++) {
BMVert *v = (BMVert *)tribuf->verts[tri->v[j]].i;
float *co = BKE_PBVH_DYNVERT(cd_dyn_vert, v)->origco;
float dist = len_squared_v3v3(co, ray_start);
if (dist < nearest_vertex_dist) {
nearest_vertex_dist = dist;
copy_v3_v3(nearest_vertex_co, co);
hit = true;
if (r_active_vertex_index) {
*r_active_vertex_index = tribuf->verts[tri->v[j]];
}
}
TGSET_ITER_INDEX_END
if (!f) {
continue;
}
if (r_active_face_index) {
*r_active_face_index = tri->f;
}
BMLoop *l = f->l_first;
if (r_face_normal) {
float no[3];
for (int j = 0; j < 3; j++, l = l->next) {
float dist = len_squared_v3v3(node->bm_orco[t[j]], ray_start);
if (!hit || dist < len_squared_v3v3(ray_start, nearest_vertex_co)) {
int idx = t[j];
hit = true;
copy_v3_v3(nearest_vertex_co, node->bm_orco[t[j]]);
if (r_active_vertex_index) {
*r_active_vertex_index = BKE_pbvh_make_vref((intptr_t)l->v);
if (use_original) {
copy_v3_v3(no, BKE_PBVH_DYNVERT(cd_dyn_vert, v1)->origno);
add_v3_v3(no, BKE_PBVH_DYNVERT(cd_dyn_vert, v2)->origno);
add_v3_v3(no, BKE_PBVH_DYNVERT(cd_dyn_vert, v3)->origno);
normalize_v3(no);
}
else {
copy_v3_v3(no, tri->no);
}
if (r_active_face_index) {
*r_active_face_index = BKE_pbvh_make_fref((intptr_t)l->f);
}
copy_v3_v3(r_face_normal, no);
}
}
}
@ -2773,133 +2805,99 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node,
hit = true;
}
}
else {
BMFace *f;
TGSET_ITER (f, node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
BM_face_as_array_vert_tri(f, v_tri);
bool hit2;
if (hit2 = ray_face_intersection_tri(
ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth)) {
if (r_face_normal) {
normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
}
if (r_active_vertex_index) {
float location[3] = {0.0f};
madd_v3_v3v3fl(location, ray_start, ray_normal, *depth);
for (int j = 0; j < 3; j++) {
if (!hit || len_squared_v3v3(location, v_tri[j]->co) <
len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, v_tri[j]->co);
SculptVertRef vref = {(intptr_t)v_tri[j]}; // BM_elem_index_get(v_tri[j]);
*r_active_vertex_index = vref;
if (r_active_face_index) {
*r_active_face_index = BKE_pbvh_make_fref((intptr_t)f);
}
}
}
}
hit = true;
}
}
}
TGSET_ITER_END
}
return hit;
}
bool BKE_pbvh_bmesh_node_raycast_detail(PBVHNode *node,
bool BKE_pbvh_bmesh_node_raycast_detail(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
struct IsectRayPrecalc *isect_precalc,
float *depth,
float *r_edge_length)
{
if (node->flag & PBVH_FullyHidden) {
return 0;
return false;
}
BMFace *f;
bool hit = false;
BMFace *f_hit = NULL;
TGSET_ITER (f, node->bm_faces) {
BLI_assert(f->len == 3);
BKE_pbvh_bmesh_check_tris(pbvh, node);
for (int i = 0; i < node->tribuf->tottri; i++) {
PBVHTri *tri = node->tribuf + i;
BMVert *v1 = (BMVert *)node->tribuf->verts[tri->v[0]].i;
BMVert *v2 = (BMVert *)node->tribuf->verts[tri->v[1]].i;
BMVert *v3 = (BMVert *)node->tribuf->verts[tri->v[2]].i;
BMFace *f = (BMFace *)tri->f.i;
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
bool hit_local;
BM_face_as_array_vert_tri(f, v_tri);
hit_local = ray_face_intersection_tri(
ray_start, isect_precalc, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth);
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
if (hit_local) {
f_hit = f;
hit = true;
}
bool hit_local = ray_face_intersection_tri(
ray_start, isect_precalc, v1->co, v2->co, v3->co, depth);
if (hit_local) {
float len1 = len_squared_v3v3(v1->co, v2->co);
float len2 = len_squared_v3v3(v2->co, v3->co);
float len3 = len_squared_v3v3(v3->co, v1->co);
/* detail returned will be set to the maximum allowed size, so take max here */
*r_edge_length = sqrtf(max_fff(len1, len2, len3));
return true;
}
}
TGSET_ITER_END
if (hit) {
BMVert *v_tri[3];
BM_face_as_array_vert_tri(f_hit, v_tri);
float len1 = len_squared_v3v3(v_tri[0]->co, v_tri[1]->co);
float len2 = len_squared_v3v3(v_tri[1]->co, v_tri[2]->co);
float len3 = len_squared_v3v3(v_tri[2]->co, v_tri[0]->co);
/* detail returned will be set to the maximum allowed size, so take max here */
*r_edge_length = sqrtf(max_fff(len1, len2, len3));
}
return hit;
return false;
}
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq,
bool use_original)
bool use_original,
int stroke_id)
{
bool hit = false;
if (use_original && node->bm_tot_ortri) {
for (int i = 0; i < node->bm_tot_ortri; i++) {
const int *t = node->bm_ortri[i];
hit |= ray_face_nearest_tri(ray_start,
ray_normal,
node->bm_orco[t[0]],
node->bm_orco[t[1]],
node->bm_orco[t[2]],
depth,
dist_sq);
}
}
else {
BMFace *f;
BKE_pbvh_bmesh_check_tris(pbvh, node);
PBVHTriBuf *tribuf = node->tribuf;
const int cd_dyn_vert = pbvh->cd_dyn_vert;
TGSET_ITER (f, node->bm_faces) {
BLI_assert(f->len == 3);
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
BMVert *v_tri[3];
for (int i = 0; i < tribuf->tottri; i++) {
PBVHTri *tri = tribuf + i;
BMFace *f = (BMFace *)tri->f.i;
BM_face_as_array_vert_tri(f, v_tri);
hit |= ray_face_nearest_tri(
ray_start, ray_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co, depth, dist_sq);
}
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
TGSET_ITER_END
BMVert *v1 = (BMVert *)tribuf->verts[tri->v[0]].i;
BMVert *v2 = (BMVert *)tribuf->verts[tri->v[1]].i;
BMVert *v3 = (BMVert *)tribuf->verts[tri->v[2]].i;
float *co1, *co2, *co3;
if (use_original) {
BKE_pbvh_bmesh_check_origdata(pbvh, v1, stroke_id);
BKE_pbvh_bmesh_check_origdata(pbvh, v2, stroke_id);
BKE_pbvh_bmesh_check_origdata(pbvh, v3, stroke_id);
co1 = BKE_PBVH_DYNVERT(cd_dyn_vert, v1)->origco;
co2 = BKE_PBVH_DYNVERT(cd_dyn_vert, v2)->origco;
co3 = BKE_PBVH_DYNVERT(cd_dyn_vert, v3)->origco;
}
else {
co1 = v1->co;
co2 = v2->co;
co3 = v3->co;
}
hit |= ray_face_nearest_tri(ray_start, ray_normal, co1, co2, co3, depth, dist_sq);
}
return hit;
@ -3122,7 +3120,7 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
bool has_visible = false;
n->flag = PBVH_Leaf;
n->flag = PBVH_Leaf | PBVH_UpdateTris;
n->bm_faces = BLI_table_gset_new_ex("bm_faces", node->totface);
/* Create vert hash sets */
@ -3318,7 +3316,6 @@ bool BKE_pbvh_bmesh_update_topology_nodes(PBVH *pbvh,
undopush(node, searchdata);
BKE_pbvh_node_mark_topology_update(pbvh->nodes + i);
BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, pbvh->nodes + i);
}
}
@ -3612,24 +3609,21 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
}
#endif
for (int i = 0; i < pbvh->totnode; i++) {
//avoid potential infinite loops
const int totnode = pbvh->totnode;
for (int i = 0; i < totnode; i++) {
PBVHNode *node = pbvh->nodes + i;
if ((node->flag & PBVH_Leaf) && (node->flag & PBVH_UpdateTopology) &&
!(node->flag & PBVH_FullyHidden)) {
node->flag &= ~PBVH_UpdateTopology;
pbvh_bmesh_node_drop_orig(node);
node->flag &= ~PBVH_UpdateTopology;
/* Recursively split nodes that have gotten too many
* elements */
if (updatePBVH) {
if (!pbvh_bmesh_node_limit_ensure(pbvh, i)) {
BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, pbvh->nodes + i);
}
}
else {
BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, pbvh->nodes + i);
pbvh_bmesh_node_limit_ensure(pbvh, i);
}
}
}
@ -3654,77 +3648,224 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
return modified;
}
PBVHTriBuf *BKE_pbvh_bmesh_get_tris(PBVH *pbvh, PBVHNode *node)
{
BKE_pbvh_bmesh_check_tris(pbvh, node);
return node->tribuf;
}
void BKE_pbvh_bmesh_free_tris(PBVH *pbvh, PBVHNode *node)
{
if (node->tribuf) {
MEM_SAFE_FREE(node->tribuf->verts);
MEM_SAFE_FREE(node->tribuf->tris);
MEM_SAFE_FREE(node->tribuf->loops);
MEM_freeN(node->tribuf);
node->tribuf = NULL;
}
}
/*
generate triangle buffers with split uv islands.
currently unused (and untested).
*/
static bool pbvh_bmesh_split_tris(PBVH *pbvh, PBVHNode *node)
{
BMFace *f;
BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT | BM_FACE);
// split by uvs
int layeri = CustomData_get_layer_index(&pbvh->bm->ldata, CD_MLOOPUV);
if (layeri < 0) {
return false;
}
int totlayer = 0;
while (layeri < pbvh->bm->ldata.totlayer && pbvh->bm->ldata.layers[layeri].type == CD_MLOOPUV) {
totlayer++;
layeri++;
}
const int cd_uv = pbvh->bm->ldata.layers[layeri].offset;
const int cd_size = CustomData_sizeof(CD_MLOOPUV);
SculptVertRef *verts = NULL;
PBVHTri *tris = NULL;
intptr_t *loops = NULL;
BLI_array_declare(verts);
BLI_array_declare(tris);
BLI_array_declare(loops);
TGSET_ITER (f, node->bm_faces) {
BMLoop *l = f->l_first;
do {
l->head.index = -1;
l = l->next;
} while (l != f->l_first);
}
TGSET_ITER_END
int vi = 0;
TGSET_ITER (f, node->bm_faces) {
BMLoop *l = f->l_first;
do {
if (l->head.index >= 0) {
continue;
}
l->head.index = vi++;
BLI_array_append(loops, (intptr_t)l);
SculptVertRef sv = {(intptr_t)l->v};
BLI_array_append(verts, sv);
BMIter iter;
BMLoop *l2;
BM_ITER_ELEM (l2, &iter, l, BM_LOOPS_OF_VERT) {
bool ok = true;
for (int i = 0; i < totlayer; i++) {
MLoopUV *uv1 = BM_ELEM_CD_GET_VOID_P(l, cd_uv + cd_size * i);
MLoopUV *uv2 = BM_ELEM_CD_GET_VOID_P(l2, cd_uv + cd_size * i);
if (len_v3v3(uv1, uv2) > 0.001) {
ok = false;
break;
}
}
if (ok) {
l2->head.index = l->head.index;
}
}
} while (l != f->l_first);
}
TGSET_ITER_END
TGSET_ITER (f, node->bm_faces) {
BMLoop *l1 = f->l_first, *l2 = f->l_first->next, *l3 = f->l_first->prev;
PBVHTri tri;
tri.f.i = (intptr_t)f;
tri.v[0] = l1->head.index;
tri.v[1] = l2->head.index;
tri.v[2] = l3->head.index;
copy_v3_v3(tri.no, f->no);
BLI_array_append(tris, tri);
}
TGSET_ITER_END
if (node->tribuf) {
MEM_SAFE_FREE(node->tribuf->verts);
MEM_SAFE_FREE(node->tribuf->tris);
MEM_SAFE_FREE(node->tribuf->loops);
node->tribuf->tottri = 0;
node->tribuf->tris = NULL;
}
else {
node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
}
node->tribuf->verts = verts;
node->tribuf->loops = loops;
node->tribuf->tris = tris;
node->tribuf->tottri = BLI_array_len(tris);
node->tribuf->totvert = BLI_array_len(verts);
node->tribuf->totloop = BLI_array_len(loops);
return true;
}
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
*
* Skips triangles that are hidden. */
void BKE_pbvh_bmesh_node_save_ortri(BMesh *bm, PBVHNode *node)
void BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
{
/* Skip if original coords/triangles are already saved */
if (node->bm_orco) {
BMesh *bm = pbvh->bm;
if (!(node->flag & PBVH_UpdateTris) && node->tribuf) {
return;
}
const int totvert = BLI_table_gset_len(node->bm_unique_verts) +
BLI_table_gset_len(node->bm_other_verts);
if (node->tribuf) {
MEM_SAFE_FREE(node->tribuf->verts);
MEM_SAFE_FREE(node->tribuf->tris);
MEM_SAFE_FREE(node->tribuf->loops);
const int tottri = BLI_table_gset_len(node->bm_faces);
node->bm_orco = MEM_mallocN(sizeof(*node->bm_orco) * totvert, __func__);
node->bm_ortri = MEM_mallocN(sizeof(*node->bm_ortri) * tottri, __func__);
/* Copy out the vertices and assign a temporary index */
int i = 0;
BMVert *v;
TGSET_ITER (v, node->bm_unique_verts) {
copy_v3_v3(node->bm_orco[i], v->co);
BM_elem_index_set(v, i); /* set_dirty! */
i++;
node->tribuf->tottri = 0;
node->tribuf->totvert = 0;
node->tribuf->totloop = 0;
}
TGSET_ITER_END
TGSET_ITER (v, node->bm_other_verts) {
copy_v3_v3(node->bm_orco[i], v->co);
BM_elem_index_set(v, i); /* set_dirty! */
i++;
else {
node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
node->tribuf->loops = NULL;
node->tribuf->totloop = 0;
}
TGSET_ITER_END
/* Likely this is already dirty. */
bm->elem_index_dirty |= BM_VERT;
node->flag &= ~PBVH_UpdateTris;
PBVHTri *tris = NULL;
SculptVertRef *verts = NULL;
/* Copy the triangles */
i = 0;
BLI_array_declare(tris);
BLI_array_declare(verts);
GHash *vmap = BLI_ghash_ptr_new("pbvh_bmesh.c vmap");
BMFace *f;
TGSET_ITER (f, node->bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
BMVert *v1 = f->l_first->v;
BMVert *v2 = f->l_first->next->v;
BMVert *v3 = f->l_first->prev->v;
#if 0
if (f->l_first->v->head.index >= totvert || f->l_first->next->v->head.index >= totvert ||
f->l_first->prev->v->head.index >= totvert) {
printf("Error!\n");
continue;
}
#endif
PBVHTri tri = {0};
#if 0
BMIter bm_iter;
BMVert *v;
BMLoop *l = f->l_first;
int j = 0;
BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) {
node->bm_ortri[i][j] = BM_elem_index_get(v);
do {
void **val = NULL;
if (!BLI_ghash_ensure_p(vmap, l->v, &val)) {
SculptVertRef sv = {(intptr_t)l->v};
*val = (void*) BLI_array_len(verts);
BLI_array_append(verts, sv);
}
tri.v[j] = (intptr_t) val[0];
j++;
}
#else
bm_face_as_array_index_tri(f, node->bm_ortri[i]);
#endif
i++;
l = l->next;
} while (l != f->l_first);
copy_v3_v3(tri.no, f->no);
tri.f.i = (intptr_t)f;
BLI_array_append(tris, tri);
}
TGSET_ITER_END
node->bm_tot_ortri = i;
bm->elem_index_dirty | BM_VERT;
node->tribuf->tris = tris;
node->tribuf->tottri = BLI_array_len(tris);
node->tribuf->verts = verts;
node->tribuf->totvert = BLI_array_len(verts);
BLI_ghash_free(vmap, NULL, NULL);
}
static int pbvh_count_subtree_verts(PBVH *pbvh, PBVHNode *n)
@ -3812,7 +3953,7 @@ static void BKE_pbvh_bmesh_corect_tree(PBVH *pbvh, PBVHNode *node, PBVHNode *par
node->flag |= PBVH_Leaf | PBVH_UpdateRedraw | PBVH_UpdateBB | PBVH_UpdateDrawBuffers |
PBVH_RebuildDrawBuffers | PBVH_UpdateOriginalBB | PBVH_UpdateMask |
PBVH_UpdateVisibility | PBVH_UpdateColor | PBVH_UpdateTopology |
PBVH_UpdateNormals;
PBVH_UpdateNormals | PBVH_UpdateTris;
TableGSet *other = BLI_table_gset_new(__func__);
BMVert *v;
@ -3890,14 +4031,14 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
printf("un-deleting an empty node\n");
PBVHNode *n3 = n1->flag & PBVH_Delete ? n1 : n2;
n3->flag = PBVH_Leaf;
n3->flag = PBVH_Leaf | PBVH_UpdateTris;
n3->bm_unique_verts = BLI_table_gset_new("bm_unique_verts");
n3->bm_other_verts = BLI_table_gset_new("bm_other_verts");
n3->bm_faces = BLI_table_gset_new("bm_faces");
}
else if ((n1->flag & PBVH_Delete) && (n2->flag & PBVH_Delete)) {
n->children_offset = 0;
n->flag |= PBVH_Leaf;
n->flag |= PBVH_Leaf | PBVH_UpdateTris;
if (!n->bm_unique_verts) {
// should not happen
@ -3940,14 +4081,8 @@ static void pbvh_bmesh_join_nodes(PBVH *bvh)
n->face_vert_indices = NULL;
}
if (n->bm_orco) {
MEM_freeN(n->bm_orco);
n->bm_orco = NULL;
}
if (n->bm_ortri) {
MEM_freeN(n->bm_ortri);
n->bm_ortri = NULL;
if (n->tribuf) {
BKE_pbvh_bmesh_free_tris(bvh, n);
}
if (n->bm_unique_verts) {
@ -4086,11 +4221,15 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
check_heap();
int totnode = pbvh->totnode;
// pbvh_bmesh_join_nodes(pbvh);
pbvh_bmesh_join_nodes(pbvh);
check_heap();
for (int i = 0; i < pbvh->totnode; i++) {
BKE_pbvh_update_bounds(pbvh, (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw));
totnode = pbvh->totnode;
for (int i = 0; i < totnode; i++) {
PBVHNode *n = pbvh->nodes + i;
if (totnode != pbvh->totnode) {
@ -4100,18 +4239,11 @@ void BKE_pbvh_bmesh_after_stroke(PBVH *pbvh)
}
if (n->flag & PBVH_Leaf) {
/* Free orco/ortri data */
pbvh_bmesh_node_drop_orig(n);
/* Recursively split nodes that have gotten too many
* elements */
if (!pbvh_bmesh_node_limit_ensure(pbvh, i)) {
BKE_pbvh_bmesh_node_save_ortri(pbvh->bm, n);
}
pbvh_bmesh_node_limit_ensure(pbvh, i);
}
}
BKE_pbvh_update_bounds(pbvh, (PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw));
}
void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size, float detail_range)

View File

@ -106,9 +106,8 @@ struct PBVHNode {
TableGSet *bm_faces;
TableGSet *bm_unique_verts;
TableGSet *bm_other_verts;
float (*bm_orco)[3];
int (*bm_ortri)[3];
int bm_tot_ortri;
PBVHTriBuf *tribuf;
/* Used to store the brush color during a stroke and composite it over the original color */
PBVHColorBufferNode color_buffer;
@ -235,20 +234,25 @@ bool ray_face_nearest_tri(const float ray_start[3],
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
bool pbvh_bmesh_node_raycast(PBVHNode *node,
bool pbvh_bmesh_node_raycast(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
struct IsectRayPrecalc *isect_precalc,
float *dist,
bool use_original,
SculptVertRef *r_active_vertex_index,
SculptFaceRef *r_active_face_index,
float *r_face_normal);
bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node,
struct SculptVertRef *r_active_vertex_index,
struct SculptFaceRef *r_active_face_index,
float *r_face_normal,
int stroke_id);
bool pbvh_bmesh_node_nearest_to_ray(PBVH *pbvh,
PBVHNode *node,
const float ray_start[3],
const float ray_normal[3],
float *depth,
float *dist_sq,
bool use_original);
bool use_original,
int stroke_id);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);

View File

@ -131,6 +131,17 @@ int SCULPT_vertex_count_get(SculptSession *ss)
return 0;
}
const float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex)
{
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
BMVert *v = (BMVert *)vertex.i;
return BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v)->origco;
}
// XXX implement me
return SCULPT_vertex_co_get(ss, vertex);
}
const float *SCULPT_vertex_co_get(SculptSession *ss, SculptVertRef index)
{
switch (BKE_pbvh_type(ss->pbvh)) {
@ -1851,16 +1862,17 @@ static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3
* Same goes for alt-key smoothing. */
bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush)
{
return ((BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
return (
(BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) &&
(!ss->cache || (!ss->cache->alt_smooth)) &&
(!ss->cache || (!ss->cache->alt_smooth)) &&
/* Requires mesh restore, which doesn't work with
* dynamic-topology. */
!(brush->flag & BRUSH_ANCHORED) && !(brush->flag & BRUSH_DRAG_DOT) &&
(brush->cached_dyntopo.flag & (DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE | DYNTOPO_CLEANUP)) &&
!(brush->cached_dyntopo.flag & DYNTOPO_DISABLED) &&
SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
/* Requires mesh restore, which doesn't work with
* dynamic-topology. */
!(brush->flag & BRUSH_ANCHORED) && !(brush->flag & BRUSH_DRAG_DOT) &&
(brush->cached_dyntopo.flag & (DYNTOPO_SUBDIVIDE | DYNTOPO_COLLAPSE | DYNTOPO_CLEANUP)) &&
!(brush->cached_dyntopo.flag & DYNTOPO_DISABLED) &&
SCULPT_TOOL_HAS_DYNTOPO(brush->sculpt_tool));
}
/*** paint mesh ***/
@ -2341,8 +2353,7 @@ typedef struct AreaNormalCenterTLSData {
int count_co[2];
} AreaNormalCenterTLSData;
static void calc_area_normal_and_center_task_cb(
void *__restrict userdata,
static void calc_area_normal_and_center_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict tls)
{
@ -2404,13 +2415,18 @@ static void calc_area_normal_and_center_task_cb(
int(*orco_tris)[3];
int orco_tris_num;
BKE_pbvh_node_get_bm_orco_data(data->nodes[n], &orco_tris, &orco_tris_num, &orco_coords);
PBVHTriBuf *tribuf = BKE_pbvh_bmesh_get_tris(ss->pbvh, data->nodes[n]);
for (int i = 0; i < orco_tris_num; i++) {
const float *co_tri[3] = {
orco_coords[orco_tris[i][0]],
orco_coords[orco_tris[i][1]],
orco_coords[orco_tris[i][2]],
for (int i = 0; i < tribuf->tottri; i++) {
PBVHTri *tri = tribuf->tris + i;
SculptVertRef v1 = tribuf->verts[tri->v[0]];
SculptVertRef v2 = tribuf->verts[tri->v[1]];
SculptVertRef v3 = tribuf->verts[tri->v[2]];
const float(*co_tri[3]) = {
SCULPT_vertex_origco_get(ss, v1),
SCULPT_vertex_origco_get(ss, v2),
SCULPT_vertex_origco_get(ss, v3),
};
float co[3];
@ -5270,7 +5286,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cd_layer_disp = SCULPT_dyntopo_get_templayer(ss, CD_PROP_FLOAT, SCULPT_LAYER_DISP);
//should never happen
// should never happen
if (cd_pers_co < 0 || cd_pers_no < 0 || cd_pers_disp < 0 || cd_layer_disp < 0) {
printf("error!! $d $d $d $d\n", cd_pers_co, cd_pers_no, cd_pers_disp, cd_layer_disp);
return;
@ -5285,7 +5301,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
SculptThreadedTaskData data = {
.sd = sd,
.ob = ob,
.ob = ob,
.brush = brush,
.nodes = nodes,
.cd_pers_co = cd_pers_co,
@ -6532,7 +6548,8 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe
BKE_pbvh_node_mark_update(nodes[i]);
}
} else {
}
else {
for (int i = 0; i < totnode; i++) {
SCULPT_ensure_dyntopo_node_undo(ob, nodes[i], SCULPT_UNDO_COORDS, -1);
BKE_pbvh_node_mark_update(nodes[i]);
@ -7947,7 +7964,8 @@ static void sculpt_raycast_cb(PBVHNode *node, void *data_v, float *tmin)
&srd->depth,
&srd->active_vertex_index,
&srd->active_face_grid_index,
srd->face_normal)) {
srd->face_normal,
srd->ss->stroke_id)) {
srd->hit = true;
*tmin = srd->depth;
}
@ -7981,7 +7999,8 @@ static void sculpt_find_nearest_to_ray_cb(PBVHNode *node, void *data_v, float *t
srd->ray_start,
srd->ray_normal,
&srd->depth,
&srd->dist_sq_to_ray)) {
&srd->dist_sq_to_ray,
srd->ss->stroke_id)) {
srd->hit = true;
*tmin = srd->dist_sq_to_ray;
}
@ -8071,7 +8090,8 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
.face_normal = face_normal,
};
isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
BKE_pbvh_raycast(
ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original, srd.ss->stroke_id);
/* Cursor is not over the mesh, return default values. */
if (!srd.hit) {
@ -8198,7 +8218,8 @@ bool SCULPT_stroke_get_location(bContext *C, float out[3], const float mouse[2])
srd.face_normal = face_normal;
isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
BKE_pbvh_raycast(ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original);
BKE_pbvh_raycast(
ss->pbvh, sculpt_raycast_cb, &srd, ray_start, ray_normal, srd.original, srd.ss->stroke_id);
if (srd.hit) {
hit = true;
copy_v3_v3(out, ray_normal);

View File

@ -64,6 +64,7 @@ typedef struct {
float edge_length;
struct IsectRayPrecalc isect_precalc;
SculptSession *ss;
} SculptDetailRaycastData;
static bool sculpt_and_constant_or_manual_detail_poll(bContext *C)
@ -193,8 +194,13 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin)
{
if (BKE_pbvh_node_get_tmin(node) < *tmin) {
SculptDetailRaycastData *srd = data_v;
if (BKE_pbvh_bmesh_node_raycast_detail(
node, srd->ray_start, &srd->isect_precalc, &srd->depth, &srd->edge_length)) {
if (BKE_pbvh_bmesh_node_raycast_detail(srd->ss->pbvh,
node,
srd->ray_start,
&srd->isect_precalc,
&srd->depth,
&srd->edge_length)) {
srd->hit = true;
*tmin = srd->depth;
}
@ -215,12 +221,14 @@ static void sample_detail_dyntopo(bContext *C, ViewContext *vc, ARegion *region,
SculptDetailRaycastData srd;
srd.hit = 0;
srd.ss = ob->sculpt;
srd.ray_start = ray_start;
srd.depth = depth;
srd.edge_length = 0.0f;
isect_ray_tri_watertight_v3_precalc(&srd.isect_precalc, ray_normal);
BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false);
BKE_pbvh_raycast(ob->sculpt->pbvh, sculpt_raycast_detail_cb, &srd, ray_start, ray_normal, false, srd.ss->stroke_id);
if (srd.hit && srd.edge_length > 0.0f) {
/* Convert edge length to world space detail resolution. */

View File

@ -179,6 +179,7 @@ void SCULPT_vertex_neighbors_get(struct SculptSession *ss,
SculptVertRef SCULPT_active_vertex_get(SculptSession *ss);
const float *SCULPT_active_vertex_co_get(SculptSession *ss);
const float *SCULPT_vertex_origco_get(SculptSession *ss, SculptVertRef vertex);
void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]);
/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise