Commit: e9e37ddeb62595c62dc2fddfd02a4cdc7d96d53c
Author: Lukas Tönne
Date: Tue Jul 14 17:27:01 2015 +0200
Branches: mathutils_bvhtree
https://developer.blender.org/rBe9e37ddeb62595c62dc2fddfd02a4cdc7d96d53c
Another alternative BVH Tree representation for totally custom user
geometry.
The new constructor method allows creating a BVHTree from a list of
vertices and triangles directly, without a separate mesh representation.
===================================================================
M source/blender/blenkernel/BKE_bvhutils.h
M source/blender/blenkernel/intern/bvhutils.c
M source/blender/python/mathutils/mathutils_bvhtree.c
M source/blender/python/mathutils/mathutils_bvhtree.h
===================================================================
diff --git a/source/blender/blenkernel/BKE_bvhutils.h
b/source/blender/blenkernel/BKE_bvhutils.h
index a360511..8109f46 100644
--- a/source/blender/blenkernel/BKE_bvhutils.h
+++ b/source/blender/blenkernel/BKE_bvhutils.h
@@ -101,6 +101,7 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data);
* Math functions used by callbacks
*/
float bvhtree_ray_tri_intersection(const BVHTreeRay *ray, const float m_dist,
const float v0[3], const float v1[3], const float v2[3]);
+float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray, float radius,
const float m_dist, const float v0[3], const float v1[3], const float v2[3]);
float nearest_point_in_tri_surface_squared(const float v0[3], const float
v1[3], const float v2[3], const float p[3], int *v, int *e, float nearest[3]);
/*
diff --git a/source/blender/blenkernel/intern/bvhutils.c
b/source/blender/blenkernel/intern/bvhutils.c
index 1a4a4bd..2213869 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -60,7 +60,7 @@ float bvhtree_ray_tri_intersection(const BVHTreeRay *ray,
const float UNUSED(m_d
return FLT_MAX;
}
-static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius,
const float m_dist, const float v0[3], const float v1[3], const float v2[3])
+float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray, float radius,
const float m_dist, const float v0[3], const float v1[3], const float v2[3])
{
float idist;
@@ -163,7 +163,7 @@ static void mesh_faces_spherecast(void *userdata, int
index, const BVHTreeRay *r
if (data->sphere_radius == 0.0f)
dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0,
t1, t2);
else
- dist = sphereray_tri_intersection(ray,
data->sphere_radius, hit->dist, t0, t1, t2);
+ dist = bvhtree_sphereray_tri_intersection(ray,
data->sphere_radius, hit->dist, t0, t1, t2);
if (dist >= 0 && dist < hit->dist) {
hit->index = index;
@@ -200,7 +200,7 @@ static void editmesh_faces_spherecast(void *userdata, int
index, const BVHTreeRa
if (data->sphere_radius == 0.0f)
dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0,
t1, t2);
else
- dist = sphereray_tri_intersection(ray,
data->sphere_radius, hit->dist, t0, t1, t2);
+ dist = bvhtree_sphereray_tri_intersection(ray,
data->sphere_radius, hit->dist, t0, t1, t2);
if (dist >= 0 && dist < hit->dist) {
hit->index = index;
diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c
b/source/blender/python/mathutils/mathutils_bvhtree.c
index 7d4d4ef..310ec41 100644
--- a/source/blender/python/mathutils/mathutils_bvhtree.c
+++ b/source/blender/python/mathutils/mathutils_bvhtree.c
@@ -73,6 +73,26 @@ typedef struct {
int bmtotlooptris;
} PyBVHTree_BMesh;
+typedef struct BVHVertex {
+ float co[3];
+} BVHVertex;
+
+typedef struct BVHTriangle {
+ int v1, v2, v3;
+} BVHTriangle;
+
+typedef struct PyBVHTree_Custom {
+ PyBVHTree base;
+ /* geometry data */
+ struct BVHTree *tree;
+
+ struct BVHVertex *vert;
+ struct BVHTriangle *tri;
+ int totvert, tottri;
+
+ float epsilon;
+} PyBVHTree_Custom;
+
/* -------------------------------------------------------------------- */
/* Utility helper functions */
@@ -691,6 +711,360 @@ PyTypeObject PyBVHTreeBMesh_Type = {
};
/* -------------------------------------------------------------------- */
+/* BVHTreeCustom */
+
+static BVHTree *bvhtree_from_triangles_create_tree(float epsilon, int
tree_type, int axis,
+ BVHVertex *vert,
BVHTriangle *tri, int numtris)
+{
+ BVHTree *tree = NULL;
+ int i;
+
+ if (numtris == 0 || !vert || !tri)
+ return NULL;
+
+ /* Create a bvh-tree of the given target */
+ tree = BLI_bvhtree_new(numtris, epsilon, (char)tree_type, (char)axis);
+ if (tree) {
+ for (i = 0; i < numtris; i++) {
+ float co[3][3];
+
+ copy_v3_v3(co[0], vert[tri[i].v1].co);
+ copy_v3_v3(co[1], vert[tri[i].v2].co);
+ copy_v3_v3(co[2], vert[tri[i].v3].co);
+
+ BLI_bvhtree_insert(tree, i, co[0], 3);
+ }
+
+ BLI_bvhtree_balance(tree);
+ }
+
+ return tree;
+}
+
+static int PyBVHTreeCustom__tp_init(PyBVHTree_Custom *self, PyObject *args,
PyObject *kwargs)
+{
+ const char *keywords[] = {"vertices", "triangles", NULL};
+
+ PyObject *py_verts, *py_tris;
+ int numverts, numtris;
+ BVHVertex *verts, *vp;
+ BVHTriangle *tris, *tp;
+ int i;
+ bool valid = true;
+
+ if (PyBVHTree_Type.tp_init((PyObject *)self, args, kwargs) < 0)
+ return -1;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char
*)"OO:BVHTreeCustom", (char **)keywords,
+ &py_verts, &py_tris))
+ {
+ return -1;
+ }
+
+ if (!PySequence_Check(py_verts)) {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a sequence of vectors");
+ return -1;
+ }
+
+ if (!PySequence_Check(py_tris)) {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a sequence of lists of integers");
+ return -1;
+ }
+
+ if (valid) {
+ numverts = (int)PySequence_Size(py_verts);
+ vp = verts = MEM_mallocN(sizeof(BVHVertex) * (size_t)numverts,
"BPy BVHTree vertices");
+ for (i = 0; i < numverts; i++, vp++) {
+ PyObject *py_vert = PySequence_GetItem(py_verts, i);
+
+ if (mathutils_array_parse(vp->co, 3, 3, py_vert,
"BVHTree vertex: ") == -1) {
+ valid = false;
+ break;
+ }
+ }
+ }
+
+ if (valid) {
+ numtris = (int)PySequence_Size(py_tris);
+ /* now construct loop list */
+ tp = tris = MEM_mallocN(sizeof(BVHTriangle) * (size_t)numtris,
"BPy BVHTree triangles");
+ for (i = 0; i < numtris; i++) {
+ PyObject *py_triverts = PySequence_GetItem(py_tris, i);
+ int tottri = (int)PySequence_Size(py_triverts);
+
+ if (tottri != 3) {
+ Py_XDECREF(py_triverts); /* may be null so use
Py_XDECREF*/
+ PyErr_SetString(PyExc_TypeError,
+ "One or more of the triangles
does not have 3 indices");
+ valid = false;
+ break;
+ }
+
+ tp->v1 =
(int)PyLong_AsLong(PySequence_GetItem(py_triverts, 0));
+ tp->v2 =
(int)PyLong_AsLong(PySequence_GetItem(py_triverts, 1));
+ tp->v3 =
(int)PyLong_AsLong(PySequence_GetItem(py_triverts, 2));
+ }
+ }
+
+ if (valid) {
+ self->vert = verts;
+ self->totvert = numverts;
+ self->tri = tris;
+ self->tottri = numtris;
+
+ /* XXX make configurable? */
+ self->epsilon = 0.0f;
+
+ self->tree = bvhtree_from_triangles_create_tree(self->epsilon,
4, 6, self->vert, self->tri, self->tottri);
+
+ return 0;
+ }
+ else {
+ if (verts)
+ MEM_freeN(verts);
+ if (tris)
+ MEM_freeN(tris);
+
+ return -1;
+ }
+}
+
+static void PyBVHTreeCustom__tp_dealloc(PyBVHTree_Custom *self)
+{
+ if (self->tree)
+ BLI_bvhtree_free(self->tree);
+
+ if (self->vert)
+ MEM_freeN(self->vert);
+ if (self->tri)
+ MEM_freeN(self->tri);
+
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static void bvhtree_custom_raycast_cb(void *userdata, int index, const
BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ PyBVHTree_Custom *self = (PyBVHTree_Custom *)userdata;
+ const BVHVertex *verts = self->vert;
+ const BVHTriangle *tris = self->tri;
+
+ const float *t0, *t1, *t2;
+ t0 = verts[ tris[index].v1 ].co;
+ t1 = verts[ tris[index].v2 ].co;
+ t2 = verts[ tris[index].v3 ].co;
+
+ {
+ float dist;
+ if (self->epsilon == 0.0f)
+ dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0,
t1, t2);
+ else
+ dist = bvhtree_sphereray_tri_intersection(ray,
self->epsilon, hit->dist, t0, t1, t2);
+
+ if (dist >= 0 && dist < hit->dist) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction,
dist);
+
+ normal_tri_v3(hit->no, t0, t1, t2);
+ }
+ }
+}
+
+PyDoc_STRVAR(py_BVHTreeCustom_ray_cast_doc,
+".. method:: ray_cast(ray_start, ray_end)\n"
+"\n"
+" Cast a ray onto the mesh.\n"
+"\n"
+" :arg ray_point: Start location of the ray in object space.\n"
+" :type ray_point: :class:`Vector`\n"
+" :arg ray_direction: Direction of the ray in object space.\n"
+" :type ray_direction: :class:`Vector`\n"
+" :arg ray_maxdist: Maximum distance of intersection.\n"
+" :type ray_maxdist: :float\n"
+" :return: Returns a tuple (:class:`Vector` location, :class:`Vector`
normal, int index, float distance), index==-1 if no hit was found.\n"
+" :rtype: :class:`tuple`\n"
+);
+static PyObject *py_BVHTreeCustom_ray_cast(PyBVHTree_Custom *self, PyObject
*args)
+{
+ const char *error_prefix = "ray_cast";
+
+ PyObject *py_point, *py_direction;
+ float ray_point[3], ray_direction[3];
+ float ray_maxdist = FLT_MAX;
+
+ if (!PyArg_ParseTuple(args, (char *)"OO|f:ray_cast", &py_point,
&py_direction, &ray_maxdist))
+ {
+ return NULL;
+ }
+
+ if (mathutils_array_parse(ray_point, 2, 3, py_point, error_prefix) ==
-1 ||
+ mathutils_array_parse(ray_direction, 2, 3, py_direction,
error_prefix) == -1)
+ {
+ return NULL;
+ }
+
+ normalize_v3(ray_direction);
+
+ /* may fail if the mesh has no faces, in that case the ray-cast misses
*/
+ if (self->tree) {
+ BVHTreeRayHit hit;
+ hit.dist = ray_maxdist;
+ hit.index = -1;
+
+ if (BLI_bvhtree_ray_cast(self->tree, ray_point, ray_direction,
0.0f, &hit,
+ bvhtree_custom_raycast_cb, self) != -1)
+ {
+ if (hit.dist <= ray_maxdist) {
+ return bvhtree_ray_hit_to_py(hit.co, hit.no,
hit.index, hit.dist);
+ }
+ }
+ }
+
+ return bvhtree_ray_hit_to_py(NULL, NULL, -1, 0.0f);
+}
+
+/* Callback to bvh tree nearest point. The tree must have been built using
bvhtree_from_mesh_faces.
+ * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the
tree. */
+static void bvhtree_custom_nearest_point_cb(void *userdata, int index, const
float co[3], BVHTreeNearest *nearest)
+{
+ PyBVHTree_Custom *self = (PyBVHTree_Custom *)userdata;
+ const BVHVertex *verts = self->vert;
+ const BVHTriangle *tris = self->tri;
+
+ const float *t0, *t1, *t2, *t3;
+ t0 = verts[ tris->v1 ].co;
+ t1 = verts[ tris->v2 ].co;
+ t2 = verts[ tris->v3 ].co;
+
+ {
+ float nearest_tmp[3], dist_sq;
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
+ if (dist_sq < nearest->dist_sq) {
+ nearest->index = index;
+ nearest->dist_sq = dist_sq;
+ copy_v3_v3(nearest->co, nearest_tmp);
+ normal_tri_v3(near
@@ Diff output truncated at 10240 characters. @@
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs