From c0ca6a38b81ec01767667f48554f081c5029cdf2 Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Wed, 24 Jun 2020 15:02:59 -0500 Subject: [PATCH 1/4] Stub out a callback handler --- pyembree/callback_handler.pxd | 15 +++++++++++++++ pyembree/callback_handler.pyx | 5 +++++ pyembree/rtcore_scene.pyx | 14 ++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 pyembree/callback_handler.pxd create mode 100644 pyembree/callback_handler.pyx diff --git a/pyembree/callback_handler.pxd b/pyembree/callback_handler.pxd new file mode 100644 index 0000000..fd5d585 --- /dev/null +++ b/pyembree/callback_handler.pxd @@ -0,0 +1,15 @@ +from rtcore_ray cimport RTCRay + +cdef enum: + CALLBACK_TERMINATE = 0 + CALLBACK_CONTINUE = 1 + +cdef class RayCollisionCallback: + # The function callback needs to return either CALLBACK_TERMINATE or + # CALLBACK_CONTINUE. CALLBACK_CONTINUE will keep it running, but + # assumes that you have done something to the ray. Otherwise it will + # enter into an endless loop. + cdef int callback(self, RTCRay ray) + +cdef class RayCollisionNull(RayCollisionCallback): + pass diff --git a/pyembree/callback_handler.pyx b/pyembree/callback_handler.pyx new file mode 100644 index 0000000..f9df7f1 --- /dev/null +++ b/pyembree/callback_handler.pyx @@ -0,0 +1,5 @@ +from rtcore_ray cimport RTCRay + +cdef class RayCollisionCallback: + cdef int callback(self, RTCRay ray): + return CALLBACK_TERMINATE diff --git a/pyembree/rtcore_scene.pyx b/pyembree/rtcore_scene.pyx index be5e58e..8cc7907 100644 --- a/pyembree/rtcore_scene.pyx +++ b/pyembree/rtcore_scene.pyx @@ -6,6 +6,8 @@ import numbers cimport rtcore as rtc cimport rtcore_ray as rtcr cimport rtcore_geometry as rtcg +from .callback_handler cimport \ + RayCollisionCallback, RayCollisionNull, CALLBACK_TERMINATE, CALLBACK_CONTINUE log = logging.getLogger('pyembree') @@ -35,12 +37,16 @@ cdef class EmbreeScene: def run(self, np.ndarray[np.float32_t, ndim=2] vec_origins, np.ndarray[np.float32_t, ndim=2] vec_directions, - dists=None,query='INTERSECT',output=None): + dists=None,query='INTERSECT',output=None, + RayCollisionCallback callback_handler=None): if self.is_committed == 0: rtcCommit(self.scene_i) self.is_committed = 1 + if callback_handler is None: + callback_handler = RayCollisionNull() + cdef int nv = vec_origins.shape[0] cdef int vo_i, vd_i, vd_step cdef np.ndarray[np.int32_t, ndim=1] intersect_ids @@ -77,6 +83,7 @@ cdef class EmbreeScene: intersect_ids = np.empty(nv, dtype="int32") cdef rtcr.RTCRay ray + cdef int do_continue vd_i = 0 vd_step = 1 # If vec_directions is 1 long, we won't be updating it. @@ -96,7 +103,10 @@ cdef class EmbreeScene: vd_i += vd_step if query_type == intersect or query_type == distance: - rtcIntersect(self.scene_i, ray) + do_continue = CALLBACK_CONTINUE + while do_continue == CALLBACK_CONTINUE: + rtcIntersect(self.scene_i, ray) + do_continue = callback_handler.callback(ray) if not output: if query_type == intersect: intersect_ids[i] = ray.primID From 28faae5d70eb2586cd2a197660624b201a67a6c8 Mon Sep 17 00:00:00 2001 From: Meagan Lang Date: Tue, 30 Jun 2020 14:57:29 -0700 Subject: [PATCH 2/4] Change ray to pass-by-references to allow modification. --- pyembree/callback_handler.pxd | 2 +- pyembree/callback_handler.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyembree/callback_handler.pxd b/pyembree/callback_handler.pxd index fd5d585..c5bfd12 100644 --- a/pyembree/callback_handler.pxd +++ b/pyembree/callback_handler.pxd @@ -9,7 +9,7 @@ cdef class RayCollisionCallback: # CALLBACK_CONTINUE. CALLBACK_CONTINUE will keep it running, but # assumes that you have done something to the ray. Otherwise it will # enter into an endless loop. - cdef int callback(self, RTCRay ray) + cdef int callback(self, RTCRay &ray) cdef class RayCollisionNull(RayCollisionCallback): pass diff --git a/pyembree/callback_handler.pyx b/pyembree/callback_handler.pyx index f9df7f1..1f55811 100644 --- a/pyembree/callback_handler.pyx +++ b/pyembree/callback_handler.pyx @@ -1,5 +1,5 @@ from rtcore_ray cimport RTCRay cdef class RayCollisionCallback: - cdef int callback(self, RTCRay ray): + cdef int callback(self, RTCRay &ray): return CALLBACK_TERMINATE From b33530a2645e66787984cfc2bf13ba83df77be87 Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Tue, 7 Jul 2020 11:13:42 -0500 Subject: [PATCH 3/4] Add a python callback handler example --- pyembree/callback_handler.pxd | 8 +++---- pyembree/callback_handler.pyx | 44 +++++++++++++++++++++++++++++++++++ pyembree/rtcore_scene.pyx | 6 ++--- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/pyembree/callback_handler.pxd b/pyembree/callback_handler.pxd index c5bfd12..a79405e 100644 --- a/pyembree/callback_handler.pxd +++ b/pyembree/callback_handler.pxd @@ -1,12 +1,12 @@ from rtcore_ray cimport RTCRay cdef enum: - CALLBACK_TERMINATE = 0 - CALLBACK_CONTINUE = 1 + _CALLBACK_TERMINATE = 0 + _CALLBACK_CONTINUE = 1 cdef class RayCollisionCallback: - # The function callback needs to return either CALLBACK_TERMINATE or - # CALLBACK_CONTINUE. CALLBACK_CONTINUE will keep it running, but + # The function callback needs to return either _CALLBACK_TERMINATE or + # _CALLBACK_CONTINUE. _CALLBACK_CONTINUE will keep it running, but # assumes that you have done something to the ray. Otherwise it will # enter into an endless loop. cdef int callback(self, RTCRay &ray) diff --git a/pyembree/callback_handler.pyx b/pyembree/callback_handler.pyx index 1f55811..19f9901 100644 --- a/pyembree/callback_handler.pyx +++ b/pyembree/callback_handler.pyx @@ -1,5 +1,49 @@ from rtcore_ray cimport RTCRay +# This is to make them accessible from Python +CALLBACK_TERMINATE = _CALLBACK_TERMINATE +CALLBACK_CONTINUE = _CALLBACK_CONTINUE + cdef class RayCollisionCallback: cdef int callback(self, RTCRay &ray): return CALLBACK_TERMINATE + +cdef class PythonCallback(RayCollisionCallback): + # This class lets you specify a python function that can modify in situ the + # rays that are arriving. Changes will be reflected. + cdef public object callback_function + def __init__(self, callback_function): + self.callback_function = callback_function + + cdef int callback(self, RTCRay &ray): + ray_info = dict( + org = (ray.org[0], ray.org[1], ray.org[2]), + dir = (ray.dir[0], ray.dir[1], ray.dir[2]), + tnear = ray.tnear, + tfar = ray.tfar, + time = ray.time, + mask = ray.mask, + Ng = (ray.Ng[0], ray.Ng[1], ray.Ng[2]), + u = ray.u, + v = ray.v, + geomID = ray.geomID, + primID = ray.primID, + instID = ray.instID + ) + rv = self.callback_function(ray_info) + # We now update the ray contents from the dictionary + for i in range(3): + ray.org[i] = ray_info['org'][i] + ray.dir[i] = ray_info['dir'][i] + ray.Ng[i] = ray_info['Ng'][i] + ray.tnear = ray_info['tnear'] + ray.tfar = ray_info['tfar'] + ray.mask = ray_info['mask'] + ray.u = ray_info['u'] + ray.v = ray_info['v'] + ray.geomID = ray_info['geomID'] + ray.primID = ray_info['primID'] + ray.instID = ray_info['instID'] + if rv == _CALLBACK_CONTINUE: + return _CALLBACK_CONTINUE + return _CALLBACK_TERMINATE diff --git a/pyembree/rtcore_scene.pyx b/pyembree/rtcore_scene.pyx index 8cc7907..90ac323 100644 --- a/pyembree/rtcore_scene.pyx +++ b/pyembree/rtcore_scene.pyx @@ -7,7 +7,7 @@ cimport rtcore as rtc cimport rtcore_ray as rtcr cimport rtcore_geometry as rtcg from .callback_handler cimport \ - RayCollisionCallback, RayCollisionNull, CALLBACK_TERMINATE, CALLBACK_CONTINUE + RayCollisionCallback, RayCollisionNull, _CALLBACK_TERMINATE, _CALLBACK_CONTINUE log = logging.getLogger('pyembree') @@ -103,8 +103,8 @@ cdef class EmbreeScene: vd_i += vd_step if query_type == intersect or query_type == distance: - do_continue = CALLBACK_CONTINUE - while do_continue == CALLBACK_CONTINUE: + do_continue = _CALLBACK_CONTINUE + while do_continue == _CALLBACK_CONTINUE: rtcIntersect(self.scene_i, ray) do_continue = callback_handler.callback(ray) if not output: From d1b57cec79e820e4b2fa8956da6bb7b376216957 Mon Sep 17 00:00:00 2001 From: Matthew Turk Date: Tue, 7 Jul 2020 11:19:15 -0500 Subject: [PATCH 4/4] Adding news item --- news/callbacks.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 news/callbacks.rst diff --git a/news/callbacks.rst b/news/callbacks.rst new file mode 100644 index 0000000..e5efbfa --- /dev/null +++ b/news/callbacks.rst @@ -0,0 +1,13 @@ +**Added:** + +Callbacks can now be supplied to the ray caster. This includes callbacks written in Cython, subclassing from the RayCollisionCallback cython class, and callbacks generated in Python that instantiate a PythonCallback object. + +**Changed:** None + +**Deprecated:** None + +**Removed:** None + +**Fixed:** None + +**Security:** None