From e310446b8c0bcc8a2248b4197493d1ee954eeb72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 3 May 2021 14:17:45 +0200 Subject: [PATCH] Fix ray intersection bug causing picking errors in mutter Resolves: #1956294 --- ...-direction-of-axis-when-intersecting.patch | 157 ++++++++++++++++++ graphene.spec | 9 +- 2 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 0001-ray-Nudge-ray-direction-of-axis-when-intersecting.patch diff --git a/0001-ray-Nudge-ray-direction-of-axis-when-intersecting.patch b/0001-ray-Nudge-ray-direction-of-axis-when-intersecting.patch new file mode 100644 index 0000000..ec424da --- /dev/null +++ b/0001-ray-Nudge-ray-direction-of-axis-when-intersecting.patch @@ -0,0 +1,157 @@ +From 1ec2948405695745b091587de914db9d9dd51817 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Tue, 23 Mar 2021 08:24:47 +0100 +Subject: [PATCH] ray: Nudge ray direction of axis when intersecting + +The formula used to calculate the inverse of the direction vector +doesn't handle the direction vector aligning with an axis. Depending on +the SIMD (or not SIMD) implementation used, a axis aligned vector would +either remain the same, or e.g. end up with NaN components messing up +any future calculations. + +Fixing the math to handle this is non-trivial, so for now work around +this by nudging the direction vector slightly off axis so that it has a +better hand of hitting the right box even when the direction is axis +aligned. + +Closes: #214 +--- + src/graphene-ray.c | 26 +++++++++++++++++- + tests/ray.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 92 insertions(+), 1 deletion(-) + +diff --git a/src/graphene-ray.c b/src/graphene-ray.c +index 8839b03..66c3393 100644 +--- a/src/graphene-ray.c ++++ b/src/graphene-ray.c +@@ -467,6 +467,22 @@ graphene_ray_intersects_sphere (const graphene_ray_t *r, + return graphene_ray_intersect_sphere (r, s, NULL) != GRAPHENE_RAY_INTERSECTION_KIND_NONE; + } + ++static inline float ++nudge_off_axis (float v) ++{ ++ if (graphene_approx_val (v, 0.f)) ++ { ++ if (v < 0.f) ++ return -2 * FLT_EPSILON; ++ else ++ return 2 * FLT_EPSILON; ++ } ++ else ++ { ++ return v; ++ } ++} ++ + /** + * graphene_ray_intersect_box: + * @r: a #graphene_ray_t +@@ -485,10 +501,18 @@ graphene_ray_intersect_box (const graphene_ray_t *r, + const graphene_box_t *b, + float *t_out) + { ++ graphene_vec3_t safe_direction; + graphene_vec3_t inv_dir; ++ float d[3]; ++ ++ graphene_vec3_to_float (&r->direction, d); ++ graphene_vec3_init (&safe_direction, ++ nudge_off_axis (d[0]), ++ nudge_off_axis (d[1]), ++ nudge_off_axis (d[2])); + + /* FIXME: Needs a graphene_vec3_reciprocal() */ +- inv_dir.value = graphene_simd4f_reciprocal (r->direction.value); ++ inv_dir.value = graphene_simd4f_reciprocal (safe_direction.value); + + graphene_vec3_t inv_min; + graphene_vec3_subtract (&(b->min), &r->origin, &inv_min); +diff --git a/tests/ray.c b/tests/ray.c +index 01f372c..afe14cb 100644 +--- a/tests/ray.c ++++ b/tests/ray.c +@@ -166,6 +166,72 @@ ray_intersect_triangle (void) + NULL); + } + ++static void ++ray_intersects_box (void) ++{ ++ graphene_point3d_t min; ++ graphene_point3d_t max; ++ graphene_point3d_t origin; ++ graphene_vec3_t direction; ++ graphene_box_t box; ++ graphene_ray_t ray; ++ ++ /* Off center box */ ++ ++ graphene_point3d_init (&min, 41.843132f, 27.356903f, -50.368336f); ++ graphene_point3d_init (&max, 51.698078f, 29.080172f, -50.368336f); ++ graphene_box_init (&box, &min, &max); ++ ++ /* Ray from (0, 0, 0) along an axis *NOT* hitting the above box ++ */ ++ ++ graphene_point3d_init (&origin, 0, 0, 0); ++ graphene_vec3_init (&direction, 0, 0.495176f, -0.868793f); ++ graphene_ray_init (&ray, &origin, &direction); ++ ++ mutest_expect ("intersection kind should be NONE", ++ mutest_int_value (graphene_ray_intersects_box (&ray, &box)), ++ mutest_to_be_false, ++ NULL); ++ ++ /* Nudged variant of the above ray */ ++ ++ graphene_vec3_init (&direction, 0 + 0.0001f, 0.495176f, -0.868793f); ++ graphene_ray_init (&ray, &origin, &direction); ++ ++ mutest_expect ("intersection kind should still be NONE", ++ mutest_int_value (graphene_ray_intersects_box (&ray, &box)), ++ mutest_to_be_false, ++ NULL); ++ ++ /* Centered box */ ++ ++ graphene_point3d_init (&min, -5.654480f, 27.356903f, -50.368336f); ++ graphene_point3d_init (&max, 5.654475f, 29.080172f, -50.368336f); ++ graphene_box_init (&box, &min, &max); ++ ++ /* Ray from (0, 0, 0) along the axis hitting the above box */ ++ ++ graphene_point3d_init (&origin, 0, 0, 0); ++ graphene_vec3_init (&direction, 0, 0.495176f, -0.868793f); ++ graphene_ray_init (&ray, &origin, &direction); ++ ++ mutest_expect ("intersection kind should be ENTER", ++ mutest_int_value (graphene_ray_intersects_box (&ray, &box)), ++ mutest_to_be_true, ++ NULL); ++ ++ /* Nudged variant of the above ray */ ++ ++ graphene_vec3_init (&direction, 2 * FLT_EPSILON, 0.495176f, -0.868793f); ++ graphene_ray_init (&ray, &origin, &direction); ++ ++ mutest_expect ("intersection kind should still be ENTER", ++ mutest_int_value (graphene_ray_intersects_box (&ray, &box)), ++ mutest_to_be_true, ++ NULL); ++} ++ + static void + ray_suite (void) + { +@@ -175,6 +241,7 @@ ray_suite (void) + mutest_it ("can compute the closest point to a point on the ray", ray_closest_point_to_point); + mutest_it ("can be transformed", ray_matrix_transform); + mutest_it ("can intersect triangles", ray_intersect_triangle); ++ mutest_it ("can intersect on axis", ray_intersects_box); + } + + MUTEST_MAIN ( +-- +2.31.1 + diff --git a/graphene.spec b/graphene.spec index 8f7fb6c..17e72dd 100644 --- a/graphene.spec +++ b/graphene.spec @@ -1,12 +1,15 @@ Name: graphene Version: 1.10.4 -Release: 4%{?dist} +Release: 5%{?dist} Summary: Thin layer of types for graphic libraries License: MIT URL: https://github.com/ebassi/graphene Source: %{url}/releases/download/%{version}/%{name}-%{version}.tar.xz +# Fix ray intersection bug causing picking errors in mutter (#1956294) +Patch1: 0001-ray-Nudge-ray-direction-of-axis-when-intersecting.patch + BuildRequires: gcc BuildRequires: gobject-introspection-devel >= 1.68.0-3.el9 BuildRequires: gtk-doc @@ -73,6 +76,10 @@ the functionality of the installed %{name} package. %{_datadir}/installed-tests/ %changelog +* Mon May 03 2021 Jonas Ã…dahl - 1.10.4-5 +- Fix ray intersection bug causing picking errors in mutter + Resolves: #1956294 + * Tue Apr 27 2021 Matthias Clasen - 1.10.4-4 - Rebuild with newer gobject-introspection to fix multilib conflict - Related: rhbz#1915340