From 6ecd4ecfa020964e4250bf9322c1a26ac4073b76 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 23 Jan 2018 11:32:51 +0200 Subject: [PATCH] hand-tracking and exhibits part one --- src/app.cc | 45 ++++++++++++++++++++++++------------- src/exhibit.cc | 8 ++++++- src/exman.cc | 13 ++++++----- src/geom.cc | 67 ++++++++++++++++++++++++++++++++++++++++++++++---------- src/geom.h | 29 +++++++++++++++--------- 5 files changed, 118 insertions(+), 44 deletions(-) diff --git a/src/app.cc b/src/app.cc index 0ac331b..63e7cd7 100644 --- a/src/app.cc +++ b/src/app.cc @@ -349,19 +349,36 @@ static void update(float dt) mouse_view_matrix.pre_rotate_y(deg_to_rad(avatar.body_rot)); mouse_view_matrix.pre_translate(-avatar.pos.x, -avatar.pos.y, -avatar.pos.z); - // check if an exhibit is hovered-over by mouse or 6dof (only if we don't have one grabbed) - if(!exsel_grab_mouse) { - // XXX note: using previous view/proj matrix lattency shouldn't be an issue but - // make sure state-creep doesn't get us - // XXX also this mouse-picking probably should only be active in non-VR mode - Ray ray = calc_pick_ray(prev_mx, prev_my); - exsel_hover = exman->select(ray); - } // update hand-tracking if(have_handtracking) { update_vrhands(&avatar); + + if(vrhand[0].valid) { + exslot_left.node.set_position(vrhand[0].pos); + exslot_left.node.set_rotation(vrhand[0].rot); + + // right hand takes precedence for hover + if(!exsel_grab_left && !exsel_hover) { + exsel_hover = exman->select(Sphere(vrhand[0].pos, 5)); + } + } + if(vrhand[1].valid) { + exslot_right.node.set_position(vrhand[1].pos); + exslot_right.node.set_rotation(vrhand[1].rot); + + if(!exsel_grab_right) { + exsel_hover = exman->select(Sphere(vrhand[1].pos, 5)); + } + } + } else { + // check if an exhibit is hovered-over by mouse (only if we don't have one grabbed) + if(!exsel_grab_mouse) { + Ray ray = calc_pick_ray(prev_mx, prev_my); + exsel_hover = exman->select(ray); + } + // TODO do this properly // set the position of the left hand at a suitable position for the exhibit UI dir = rotate(Vec3(-0.46, -0.1, -1), Vec3(0, 1, 0), deg_to_rad(-avatar.body_rot)); @@ -457,7 +474,6 @@ static void draw_scene() rend->draw(); exman->draw(); - /* if(have_handtracking) { Mat4 head_xform = inverse(mouse_view_matrix);//goatvr_head_matrix(); Mat4 head_dir_xform = head_xform.upper3x3(); @@ -467,15 +483,15 @@ static void draw_scene() glDisable(GL_LIGHTING); glBegin(GL_LINES); for(int i=0; i<2; i++) { - if(hand[i].valid) { + if(vrhand[i].valid) { glColor3f(i, 1 - i, i); } else { glColor3f(0.5, 0.5, 0.5); } - Vec3 v = head_xform * hand[i].pos; - Vec3 dir = head_dir_xform * rotate(Vec3(0, 0, -1), hand[i].rot) * 20.0f; - Vec3 up = head_dir_xform * rotate(Vec3(0, 1, 0), hand[i].rot) * 10.0f; - Vec3 right = head_dir_xform * rotate(Vec3(1, 0, 0), hand[i].rot) * 10.0f; + Vec3 v = head_xform * vrhand[i].pos; + Vec3 dir = head_dir_xform * rotate(Vec3(0, 0, -1), vrhand[i].rot) * 20.0f; + Vec3 up = head_dir_xform * rotate(Vec3(0, 1, 0), vrhand[i].rot) * 10.0f; + Vec3 right = head_dir_xform * rotate(Vec3(1, 0, 0), vrhand[i].rot) * 10.0f; glVertex3f(v.x, v.y, v.z); glVertex3f(v.x + dir.x, v.y + dir.y, v.z + dir.z); @@ -487,7 +503,6 @@ static void draw_scene() glEnd(); glPopAttrib(); } - */ if(debug_gui && dbg_sel_node) { AABox bvol = dbg_sel_node->get_bounds(); diff --git a/src/exhibit.cc b/src/exhibit.cc index 2e81854..b598b75 100644 --- a/src/exhibit.cc +++ b/src/exhibit.cc @@ -61,7 +61,13 @@ ExSelection Exhibit::select(const Ray &ray) const ExSelection Exhibit::select(const Sphere &sph) const { - return ExSelection(0); // TODO + ExSelection sel; + if(collision_sphere_aabox(sph, get_aabox())) { + sel.ex = (Exhibit*)this; + sel.selsphere = sph; + sel.validmask = EXSEL_SPHERE; + } + return sel; } void Exhibit::update(float dt) diff --git a/src/exman.cc b/src/exman.cc index e5cdd9f..eea24a6 100644 --- a/src/exman.cc +++ b/src/exman.cc @@ -285,13 +285,14 @@ ExSelection ExhibitManager::select(const Ray &ray) const ExSelection ExhibitManager::select(const Sphere &sph) const { - ExSelection sel; - if(!items.empty()) { - sel.ex = items[0]; - sel.selsphere = sph; - sel.validmask = EXSEL_SPHERE; + int nitems = items.size(); + for(int i=0; iselect(sph); + if(sel) { + return sel; + } } - return sel; // TODO + return ExSelection(); } // TODO optimize diff --git a/src/geom.cc b/src/geom.cc index 5fc3dce..3a287a6 100644 --- a/src/geom.cc +++ b/src/geom.cc @@ -26,6 +26,15 @@ void GeomObject::invalidate() { } +float GeomObject::distance(const Vec3 &v) const +{ + return sqrt(distance_sq(v)); +} + +float GeomObject::signed_distance(const Vec3 &v) const +{ + return sqrt(signed_distance_sq(v)); +} Sphere::Sphere() { @@ -94,14 +103,14 @@ bool Sphere::contains(const Vec3 &pt) const return length_sq(pt - center) <= radius * radius; } -float Sphere::distance(const Vec3 &v) const +float Sphere::distance_sq(const Vec3 &v) const { - return std::max(length(v - center) - radius, 0.0f); + return std::max(length_sq(v - center) - radius * radius, 0.0f); } -float Sphere::signed_distance(const Vec3 &v) const +float Sphere::signed_distance_sq(const Vec3 &v) const { - return length(v - center) - radius; + return length_sq(v - center) - radius * radius; } AABox::AABox() @@ -217,14 +226,31 @@ bool AABox::contains(const Vec3 &v) const v.x <= max.x && v.y <= max.y && v.z <= max.z; } -float AABox::distance(const Vec3 &v) const +#define SQ(x) ((x) * (x)) +float AABox::distance_sq(const Vec3 &v) const { - return 0.0; // TODO + float dsq = 0.0f; + + for(int i=0; i<3; i++) { + if(v[i] < min[i]) dsq += SQ(min[i] - v[i]); + if(v[i] > max[i]) dsq += SQ(v[i] - max[i]); + } + return dsq; } -float AABox::signed_distance(const Vec3 &v) const +float AABox::signed_distance_sq(const Vec3 &v) const { - return 0.0; // TODO + if(!contains(v)) { + return distance_sq(v); + } + + float dsq = 0.0f; + for(int i=0; i<3; i++) { + float dmin = v[i] - min[i]; + float dmax = max[i] - v[i]; + dsq -= dmin < dmax ? SQ(dmin) : SQ(dmax); + } + return dsq; } Box::Box() @@ -311,12 +337,12 @@ bool Box::contains(const Vec3 &pt) const return AABox::contains(inverse(xform) * pt); } -float Box::distance(const Vec3 &v) const +float Box::distance_sq(const Vec3 &v) const { return 0.0f; // TODO } -float Box::signed_distance(const Vec3 &v) const +float Box::signed_distance_sq(const Vec3 &v) const { return 0.0f; // TODO } @@ -382,6 +408,18 @@ float Plane::signed_distance(const Vec3 &v) const return dot(v - pt, normal); } +float Plane::distance_sq(const Vec3 &v) const +{ + float d = distance(v); + return d * d; +} + +float Plane::signed_distance_sq(const Vec3 &v) const +{ + float d = distance(v); + return dot(v, normal) >= 0.0f ? d * d : -(d * d); +} + Disc::Disc() { @@ -431,12 +469,12 @@ bool Disc::contains(const Vec3 &pt) const return length_sq(pj - this->pt) <= radius * radius; } -float Disc::distance(const Vec3 &v) const +float Disc::distance_sq(const Vec3 &v) const { return 0.0; // TODO } -float Disc::signed_distance(const Vec3 &v) const +float Disc::signed_distance_sq(const Vec3 &v) const { return 0.0; // TODO } @@ -703,3 +741,8 @@ bool intersect_aabox_aabox(AABox *res, const AABox &a, const AABox &b) } return res->min.x != res->max.x && res->min.y != res->max.y && res->min.z != res->max.z; } + +bool collision_sphere_aabox(const Sphere &s, const AABox &b) +{ + return b.distance_sq(s.center) <= s.radius * s.radius; +} diff --git a/src/geom.h b/src/geom.h index 5db1996..f9b88e5 100644 --- a/src/geom.h +++ b/src/geom.h @@ -40,8 +40,11 @@ public: virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0; virtual bool contains(const Vec3 &pt) const = 0; - virtual float distance(const Vec3 &v) const = 0; - virtual float signed_distance(const Vec3 &v) const = 0; + virtual float distance(const Vec3 &v) const; + virtual float signed_distance(const Vec3 &v) const; + + virtual float distance_sq(const Vec3 &v) const = 0; + virtual float signed_distance_sq(const Vec3 &v) const = 0; }; class Sphere : public GeomObject { @@ -58,8 +61,8 @@ public: virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; virtual bool contains(const Vec3 &pt) const; - virtual float distance(const Vec3 &v) const; - virtual float signed_distance(const Vec3 &v) const; + virtual float distance_sq(const Vec3 &v) const; + virtual float signed_distance_sq(const Vec3 &v) const; }; class AABox : public GeomObject { @@ -77,8 +80,8 @@ public: virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; virtual bool contains(const Vec3 &pt) const; - virtual float distance(const Vec3 &v) const; - virtual float signed_distance(const Vec3 &v) const; + virtual float distance_sq(const Vec3 &v) const; + virtual float signed_distance_sq(const Vec3 &v) const; }; class Box : public AABox { @@ -99,8 +102,8 @@ public: virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; virtual bool contains(const Vec3 &pt) const; - virtual float distance(const Vec3 &v) const; - virtual float signed_distance(const Vec3 &v) const; + virtual float distance_sq(const Vec3 &v) const; + virtual float signed_distance_sq(const Vec3 &v) const; }; @@ -118,6 +121,9 @@ public: virtual float distance(const Vec3 &v) const; virtual float signed_distance(const Vec3 &v) const; + + virtual float distance_sq(const Vec3 &v) const; + virtual float signed_distance_sq(const Vec3 &v) const; }; class Disc : public Plane { @@ -135,8 +141,8 @@ public: //! true if the projection of pt to the plane is contained within the disc radius virtual bool contains(const Vec3 &pt) const; - virtual float distance(const Vec3 &v) const; - virtual float signed_distance(const Vec3 &v) const; + virtual float distance_sq(const Vec3 &v) const; + virtual float signed_distance_sq(const Vec3 &v) const; }; //! project point to plane @@ -177,4 +183,7 @@ bool intersect_plane_sphere(Sphere *result, const Plane &p, const Sphere &s); //! calculate the intersection of two axis-aligned bounding boxes bool intersect_aabox_aabox(AABox *res, const AABox &a, const AABox &b); +//! determine if a sphere and an axis-aligned box collide +bool collision_sphere_aabox(const Sphere &s, const AABox &b); + #endif // GEOMOBJ_H_ -- 1.7.10.4