hand-tracking and exhibits part one
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 23 Jan 2018 09:32:51 +0000 (11:32 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 23 Jan 2018 09:32:51 +0000 (11:32 +0200)
src/app.cc
src/exhibit.cc
src/exman.cc
src/geom.cc
src/geom.h

index 0ac331b..63e7cd7 100644 (file)
@@ -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();
index 2e81854..b598b75 100644 (file)
@@ -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)
index e5cdd9f..eea24a6 100644 (file)
@@ -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; i<nitems; i++) {
+               ExSelection sel = items[i]->select(sph);
+               if(sel) {
+                       return sel;
+               }
        }
-       return sel;     // TODO
+       return ExSelection();
 }
 
 // TODO optimize
index 5fc3dce..3a287a6 100644 (file)
@@ -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;
+}
index 5db1996..f9b88e5 100644 (file)
@@ -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_