[Bf-blender-cvs] [56a07ba7065] master: Vertex Paint: apply when cursor isn't over faces

Campbell Barton noreply at git.blender.org
Thu Oct 5 12:29:25 CEST 2017


Commit: 56a07ba70650b1e65f5979eab39730a1db314c56
Author: Campbell Barton
Date:   Thu Oct 5 21:16:25 2017 +1100
Branches: master
https://developer.blender.org/rB56a07ba70650b1e65f5979eab39730a1db314c56

Vertex Paint: apply when cursor isn't over faces

This behavior makes more sense for sculpt, less so for painting.
Restores non PBVH behavior, adding `BKE_pbvh_find_nearest_to_ray` -
similar to ray-cast except it finds the closest point on the surface.

===================================================================

M	source/blender/blenkernel/BKE_pbvh.h
M	source/blender/blenkernel/intern/pbvh.c
M	source/blender/blenkernel/intern/pbvh_bmesh.c
M	source/blender/blenkernel/intern/pbvh_intern.h
M	source/blender/editors/sculpt_paint/sculpt.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 08959e79740..c6b9b6a4de6 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -59,6 +59,8 @@ typedef bool (*BKE_pbvh_SearchCallback)(PBVHNode *node, void *data);
 typedef void (*BKE_pbvh_HitCallback)(PBVHNode *node, void *data);
 typedef void (*BKE_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float *tmin);
 
+typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float *tmin);
+
 /* Building */
 
 PBVH *BKE_pbvh_new(void);
@@ -114,6 +116,16 @@ void BKE_pbvh_raycast_project_ray_root(
         PBVH *bvh, bool original,
         float ray_start[3], float ray_end[3], float ray_normal[3]);
 
+void BKE_pbvh_find_nearest_to_ray(
+        PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
+        const float ray_start[3], const float ray_normal[3],
+        bool original);
+
+bool BKE_pbvh_node_find_nearest_to_ray(
+        PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
+        const float ray_start[3], const float ray_normal[3],
+        float *depth, float *dist_sq);
+
 /* Drawing */
 
 void BKE_pbvh_node_draw(PBVHNode *node, void *data);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index bc93aa5678a..9b6c5f05a3d 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -1572,6 +1572,74 @@ bool ray_face_intersection_tri(
 	}
 }
 
+/* Take advantage of the fact we know this wont be an intersection.
+ * Just handle ray-tri edges. */
+static float dist_squared_ray_to_tri_v3_fast(
+        const float ray_origin[3], const float ray_direction[3],
+        const float v0[3], const float v1[3], const float v2[3],
+        float r_point[3], float *r_depth)
+{
+	const float *tri[3] = {v0, v1, v2};
+	float dist_sq_best = FLT_MAX;
+	for (int i = 0, j = 2; i < 3; j = i++) {
+		float point_test[3], depth_test = FLT_MAX;
+		const float dist_sq_test = dist_squared_ray_to_seg_v3(
+		        ray_origin, ray_direction, tri[i], tri[j], point_test, &depth_test);
+		if (dist_sq_test < dist_sq_best || i == 0) {
+			copy_v3_v3(r_point, point_test);
+			*r_depth = depth_test;
+			dist_sq_best = dist_sq_test;
+		}
+	}
+	return dist_sq_best;
+}
+
+bool ray_face_nearest_quad(
+        const float ray_start[3], const float ray_normal[3],
+        const float t0[3], const float t1[3], const float t2[3], const float t3[3],
+        float *depth, float *dist_sq)
+{
+	float dist_sq_test;
+	float co[3], depth_test;
+
+	if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+	         ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq))
+	{
+		*dist_sq = dist_sq_test;
+		*depth = depth_test;
+		if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+		         ray_start, ray_normal, t0, t2, t3, co, &depth_test)) < *dist_sq))
+		{
+			*dist_sq = dist_sq_test;
+			*depth = depth_test;
+		}
+		return true;
+	}
+	else {
+		return false;
+	}
+}
+
+bool ray_face_nearest_tri(
+        const float ray_start[3], const float ray_normal[3],
+        const float t0[3], const float t1[3], const float t2[3],
+        float *depth, float *dist_sq)
+{
+	float dist_sq_test;
+	float co[3], depth_test;
+
+	if (((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
+	         ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq))
+	{
+		*dist_sq = dist_sq_test;
+		*depth = depth_test;
+		return true;
+	}
+	else {
+		return false;
+	}
+}
+
 static bool pbvh_faces_node_raycast(
         PBVH *bvh, const PBVHNode *node,
         float (*origco)[3],
@@ -1743,6 +1811,176 @@ void BKE_pbvh_raycast_project_ray_root(
 	}
 }
 
+/* -------------------------------------------------------------------- */
+
+typedef struct {
+	struct DistRayAABB_Precalc dist_ray_to_aabb_precalc;
+	bool original;
+} FindNearestRayData;
+
+static bool nearest_to_ray_aabb_dist_sq(PBVHNode *node, void *data_v)
+{
+	FindNearestRayData *rcd = data_v;
+	const float *bb_min, *bb_max;
+
+	if (rcd->original) {
+		/* BKE_pbvh_node_get_original_BB */
+		bb_min = node->orig_vb.bmin;
+		bb_max = node->orig_vb.bmax;
+	}
+	else {
+		/* BKE_pbvh_node_get_BB */
+		bb_min = node->vb.bmin;
+		bb_max = node->vb.bmax;
+	}
+
+	float co_dummy[3], depth;
+	node->tmin = dist_squared_ray_to_aabb(&rcd->dist_ray_to_aabb_precalc, bb_min, bb_max, co_dummy, &depth);
+	/* Ideally we would skip distances outside the range. */
+	return depth > 0.0f;
+}
+
+void BKE_pbvh_find_nearest_to_ray(
+        PBVH *bvh, BKE_pbvh_SearchNearestCallback cb, void *data,
+        const float ray_start[3], const float ray_normal[3],
+        bool original)
+{
+	FindNearestRayData ncd;
+
+	dist_squared_ray_to_aabb_precalc(&ncd.dist_ray_to_aabb_precalc, ray_start, ray_normal);
+	ncd.original = original;
+
+	BKE_pbvh_search_callback_occluded(bvh, nearest_to_ray_aabb_dist_sq, &ncd, cb, data);
+}
+
+
+static bool pbvh_faces_node_nearest_to_ray(
+        PBVH *bvh, const PBVHNode *node,
+        float (*origco)[3],
+        const float ray_start[3], const float ray_normal[3],
+        float *depth, float *dist_sq)
+{
+	const MVert *vert = bvh->verts;
+	const MLoop *mloop = bvh->mloop;
+	const int *faces = node->prim_indices;
+	int i, totface = node->totprim;
+	bool hit = false;
+
+	for (i = 0; i < totface; ++i) {
+		const MLoopTri *lt = &bvh->looptri[faces[i]];
+		const int *face_verts = node->face_vert_indices[i];
+
+		if (paint_is_face_hidden(lt, vert, mloop))
+			continue;
+
+		if (origco) {
+			/* intersect with backuped original coordinates */
+			hit |= ray_face_nearest_tri(
+			        ray_start, ray_normal,
+			        origco[face_verts[0]],
+			        origco[face_verts[1]],
+			        origco[face_verts[2]],
+			        depth, dist_sq);
+		}
+		else {
+			/* intersect with current coordinates */
+			hit |= ray_face_nearest_tri(
+			        ray_start, ray_normal,
+			        vert[mloop[lt->tri[0]].v].co,
+			        vert[mloop[lt->tri[1]].v].co,
+			        vert[mloop[lt->tri[2]].v].co,
+			        depth, dist_sq);
+		}
+	}
+
+	return hit;
+}
+
+static bool pbvh_grids_node_nearest_to_ray(
+        PBVH *bvh, PBVHNode *node,
+        float (*origco)[3],
+        const float ray_start[3], const float ray_normal[3],
+        float *depth, float *dist_sq)
+{
+	const int totgrid = node->totprim;
+	const int gridsize = bvh->gridkey.grid_size;
+	bool hit = false;
+
+	for (int i = 0; i < totgrid; ++i) {
+		CCGElem *grid = bvh->grids[node->prim_indices[i]];
+		BLI_bitmap *gh;
+
+		if (!grid)
+			continue;
+
+		gh = bvh->grid_hidden[node->prim_indices[i]];
+
+		for (int y = 0; y < gridsize - 1; ++y) {
+			for (int x = 0; x < gridsize - 1; ++x) {
+				/* check if grid face is hidden */
+				if (gh) {
+					if (paint_is_grid_face_hidden(gh, gridsize, x, y))
+						continue;
+				}
+
+				if (origco) {
+					hit |= ray_face_nearest_quad(
+					        ray_start, ray_normal,
+					        origco[y * gridsize + x],
+					        origco[y * gridsize + x + 1],
+					        origco[(y + 1) * gridsize + x + 1],
+					        origco[(y + 1) * gridsize + x],
+					        depth, dist_sq);
+				}
+				else {
+					hit |= ray_face_nearest_quad(
+					        ray_start, ray_normal,
+					        CCG_grid_elem_co(&bvh->gridkey, grid, x, y),
+					        CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y),
+					        CCG_grid_elem_co(&bvh->gridkey, grid, x + 1, y + 1),
+					        CCG_grid_elem_co(&bvh->gridkey, grid, x, y + 1),
+					        depth, dist_sq);
+				}
+			}
+		}
+
+		if (origco)
+			origco += gridsize * gridsize;
+	}
+
+	return hit;
+}
+
+bool BKE_pbvh_node_find_nearest_to_ray(
+        PBVH *bvh, PBVHNode *node, float (*origco)[3], bool use_origco,
+        const float ray_start[3], const float ray_normal[3],
+        float *depth, float *dist_sq)
+{
+	bool hit = false;
+
+	if (node->flag & PBVH_FullyHidden)
+		return false;
+
+	switch (bvh->type) {
+		case PBVH_FACES:
+			hit |= pbvh_faces_node_nearest_to_ray(
+			        bvh, node, origco,
+			        ray_start, ray_normal, depth, dist_sq);
+			break;
+		case PBVH_GRIDS:
+			hit |= pbvh_grids_node_nearest_to_ray(
+			        bvh, node, origco,
+			        ray_start, ray_normal, depth, dist_sq);
+			break;
+		case PBVH_BMESH:
+			hit = pbvh_bmesh_node_nearest_to_ray(
+			        node, ray_start, ray_normal, depth, dist_sq, use_origco);
+			break;
+	}
+
+	return hit;
+}
+
 typedef struct {
 	DMSetMaterial setMaterial;
 	bool wireframe;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 529dfae05e2..4bfda8ebf28 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1554,6 +1554,47 @@ bool BKE_pbvh_bmesh_node_raycast_detail(
 	return hit;
 }
 
+bool pbvh_bmesh_node_nearest_to_ray(
+        PBVHNode *node, const float ray_start[3],
+        const float ray_normal[3], float *depth, float *dist_sq,
+        bool use_original)
+{
+	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 {
+		GSetIterator gs_iter;
+
+		GSET_ITER (gs_iter, node->bm_faces) {
+			BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+
+			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);
+				hit |= ray_face_nearest_tri(
+				        ray_start, ray_normal,
+				        v_tri[0]->co,
+				        v_tri[1]->co,
+				        v_tri[2]->co,
+				        depth, dist_sq);
+			}
+		}
+	}
+
+	return hit;
+}
 
 void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode)
 {
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index 7d75930b3c6..e05a3068682 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -190,6 +190,16 @@ bool ray_face_intersection_tri(


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list