From 03085a16aa2fef785083fa3921be83015e08b290 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 12 Jan 2018 08:13:04 +0200 Subject: [PATCH] fixed bounding volume issue --- src/app.cc | 3 ++ src/app.h | 2 + src/blob_exhibit.h | 2 + src/exhibit.cc | 13 +++++++ src/exhibit.h | 6 ++- src/geom.cc | 104 ++++++++++++++++++++++++++++++++++++++++++++++------ src/geom.h | 17 ++++++++- src/geomdraw.cc | 80 ++++++++++++++++++++++++++++++++++++++++ src/geomdraw.h | 8 ++++ src/object.cc | 3 +- src/object.h | 4 +- src/snode.cc | 4 +- 12 files changed, 226 insertions(+), 20 deletions(-) create mode 100644 src/geomdraw.cc create mode 100644 src/geomdraw.h diff --git a/src/app.cc b/src/app.cc index 869af78..615366a 100644 --- a/src/app.cc +++ b/src/app.cc @@ -39,6 +39,8 @@ SceneSet sceneman; unsigned int sdr_ltmap, sdr_ltmap_notex; +int fpexcept_enabled; + static Avatar avatar; static float cam_dist = 0.0; @@ -82,6 +84,7 @@ bool app_init(int argc, char **argv) char *env = getenv("FPEXCEPT"); if(env && atoi(env)) { info_log("enabling floating point exceptions\n"); + fpexcept_enabled = 1; enable_fpexcept(); } diff --git a/src/app.h b/src/app.h index 83680ec..fe06daf 100644 --- a/src/app.h +++ b/src/app.h @@ -15,6 +15,8 @@ extern SceneSet sceneman; extern unsigned int sdr_ltmap, sdr_ltmap_notex; +extern int fpexcept_enabled; // int so that C modules may fwd-delcare and use it + enum { MOD_SHIFT = 1, MOD_ALT = 2, diff --git a/src/blob_exhibit.h b/src/blob_exhibit.h index 001047a..be279e6 100644 --- a/src/blob_exhibit.h +++ b/src/blob_exhibit.h @@ -18,6 +18,8 @@ public: void update(float dt); void draw() const; + + const AABox &get_aabox() const; }; #endif // BLOB_EXHIBIT_H_ diff --git a/src/exhibit.cc b/src/exhibit.cc index eaa2251..c525f77 100644 --- a/src/exhibit.cc +++ b/src/exhibit.cc @@ -1,6 +1,7 @@ #include "exhibit.h" #include "snode.h" #include "scene.h" +#include "geomdraw.h" class ExhibitPriv { public: @@ -92,5 +93,17 @@ void Exhibit::post_draw() const if(node) { glMatrixMode(GL_MODELVIEW); glPopMatrix(); + + const AABox &bvol = get_aabox(); + debug_log("bvol (%g %g %g) -> (%g %g %g)\n", bvol.min.x, bvol.min.y, bvol.min.z, + bvol.max.x, bvol.max.y, bvol.max.z); + draw_geom_object(&bvol); } } + + +const AABox &Exhibit::get_aabox() const +{ + aabb = node->get_bounds(); + return aabb; +} diff --git a/src/exhibit.h b/src/exhibit.h index 0f98b05..f2c521b 100644 --- a/src/exhibit.h +++ b/src/exhibit.h @@ -71,11 +71,13 @@ public: virtual ExSelection select(const Ray &ray) const; virtual ExSelection select(const Sphere &sph) const; - virtual void update(float dt = 0.0f); + virtual void update(float dt = 0.0f) override; virtual void pre_draw() const; - virtual void draw() const; + virtual void draw() const override; virtual void post_draw() const; + + virtual const AABox &get_aabox() const override; }; #endif // EXHIBIT_H_ diff --git a/src/geom.cc b/src/geom.cc index 0a82566..5fc3dce 100644 --- a/src/geom.cc +++ b/src/geom.cc @@ -1,6 +1,7 @@ #include #include #include "geom.h" +#include "app.h" #define SPHERE(ptr) ((Sphere*)ptr) #define AABOX(ptr) ((AABox*)ptr) @@ -16,6 +17,15 @@ GeomObject::~GeomObject() { } +bool GeomObject::valid() const +{ + return true; +} + +void GeomObject::invalidate() +{ +} + Sphere::Sphere() { @@ -30,6 +40,17 @@ Sphere::Sphere(const Vec3 ¢, float radius) this->radius = radius; } +bool Sphere::valid() const +{ + return radius >= 0.0f; +} + +void Sphere::invalidate() +{ + center = Vec3(0, 0, 0); + radius = -1; +} + bool Sphere::intersect(const Ray &ray, HitPoint *hit) const { float a = dot(ray.dir, ray.dir); @@ -94,19 +115,41 @@ AABox::AABox(const Vec3 &vmin, const Vec3 &vmax) type = GOBJ_AABOX; } +bool AABox::valid() const +{ + return min.x <= max.x && min.y <= max.y && min.z <= max.z; +} + +void AABox::invalidate() +{ + min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX); + max = Vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX); +} + Vec3 AABox::get_corner(int idx) const { - static const Vec3 v[] = { - Vec3(-0.5, -0.5, -0.5), Vec3(0.5, -0.5, -0.5), Vec3(0.5, -0.5, 0.5), Vec3(-0.5, -0.5, 0.5), - Vec3(-0.5, 0.5, -0.5), Vec3(0.5, 0.5, -0.5), Vec3(0.5, 0.5, 0.5), Vec3(-0.5, 0.5, 0.5) - }; - return v[idx] * Vec3(max - min); + Vec3 v[] = {min, max}; + static const int xidx[] = {0, 1, 1, 0, 0, 1, 1, 0}; + static const int yidx[] = {0, 0, 0, 0, 1, 1, 1, 1}; + static const int zidx[] = {0, 0, 1, 1, 0, 0, 1, 1}; + return Vec3(v[xidx[idx]].x, v[yidx[idx]].y, v[zidx[idx]].z); } bool AABox::intersect(const Ray &ray, HitPoint *hit) const { Vec3 param[2] = {min, max}; +#ifndef NDEBUG + Vec3 inv_dir; + if(fpexcept_enabled) { + inv_dir.x = ray.dir.x == 0.0f ? 1.0f : 1.0f / ray.dir.x; + inv_dir.y = ray.dir.y == 0.0f ? 1.0f : 1.0f / ray.dir.y; + inv_dir.z = ray.dir.z == 0.0f ? 1.0f : 1.0f / ray.dir.z; + } else { + inv_dir = Vec3(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); + } +#else Vec3 inv_dir(1.0 / ray.dir.x, 1.0 / ray.dir.y, 1.0 / ray.dir.z); +#endif int sign[3] = {inv_dir.x < 0, inv_dir.y < 0, inv_dir.z < 0}; float tmin = (param[sign[0]].x - ray.origin.x) * inv_dir.x; @@ -186,28 +229,39 @@ float AABox::signed_distance(const Vec3 &v) const Box::Box() { + type = GOBJ_BOX; } Box::Box(const AABox &aabox, const Mat4 &xform) : xform(xform) { + type = GOBJ_BOX; min = aabox.min; max = aabox.max; } +void Box::invalidate() +{ + AABox::invalidate(); + xform = Mat4::identity; +} + Box::Box(const Vec3 &min, const Vec3 &max) : AABox(min, max) { + type = GOBJ_BOX; } Box::Box(const Vec3 &min, const Vec3 &max, const Mat4 &xform) : AABox(min, max), xform(xform) { + type = GOBJ_BOX; } // XXX all this shit is completely untested Box::Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk) { + type = GOBJ_BOX; float ilen = length(vi); float jlen = length(vj); float klen = length(vk); @@ -225,17 +279,13 @@ Box::Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk) Box::Box(const Vec3 *varr, int vcount) { + type = GOBJ_BOX; calc_bounding_aabox(this, varr, vcount); } Vec3 Box::get_corner(int idx) const { - static const Vec3 v[] = { - Vec3(-0.5, -0.5, -0.5), Vec3(0.5, -0.5, -0.5), Vec3(0.5, -0.5, 0.5), Vec3(-0.5, -0.5, 0.5), - Vec3(-0.5, 0.5, -0.5), Vec3(0.5, 0.5, -0.5), Vec3(0.5, 0.5, 0.5), Vec3(-0.5, 0.5, 0.5) - }; - - return xform * (v[idx] * Vec3(max - min)); + return xform * AABox::get_corner(idx); } bool Box::intersect(const Ray &ray, HitPoint *hit) const @@ -274,22 +324,26 @@ float Box::signed_distance(const Vec3 &v) const Plane::Plane() : normal(0.0, 1.0, 0.0) { + type = GOBJ_PLANE; } Plane::Plane(const Vec3 &p, const Vec3 &norm) : pt(p) { + type = GOBJ_PLANE; normal = normalize(norm); } Plane::Plane(const Vec3 &p1, const Vec3 &p2, const Vec3 &p3) : pt(p1) { + type = GOBJ_PLANE; normal = normalize(cross(p2 - p1, p3 - p1)); } Plane::Plane(const Vec3 &normal, float dist) { + type = GOBJ_PLANE; this->normal = normalize(normal); pt = this->normal * dist; } @@ -331,21 +385,34 @@ float Plane::signed_distance(const Vec3 &v) const Disc::Disc() { + type = GOBJ_DISC; radius = 1.0; } Disc::Disc(const Vec3 &pt, const Vec3 &normal, float rad) : Plane(pt, normal) { + type = GOBJ_DISC; radius = rad; } Disc::Disc(const Vec3 &normal, float dist, float rad) : Plane(normal, dist) { + type = GOBJ_DISC; radius = rad; } +bool Disc::valid() const +{ + return radius >= 0.0f; +} + +void Disc::invalidate() +{ + radius = -1; +} + bool Disc::intersect(const Ray &ray, HitPoint *hit) const { HitPoint phit; @@ -385,6 +452,11 @@ Vec3 proj_point_plane(const Vec3 &pt, const Plane &plane) bool calc_bounding_sphere(Sphere *sph, const GeomObject *obj) { + if(!obj->valid()) { + sph->invalidate(); + return true; + } + switch(obj->type) { case GOBJ_SPHERE: *sph = *(Sphere*)obj; @@ -466,6 +538,11 @@ bool calc_bounding_sphere(Sphere *sph, const Vec3 *v, int num, const Mat4 &xform bool calc_bounding_aabox(AABox *box, const GeomObject *obj) { + if(!obj->valid()) { + box->invalidate(); + return true; + } + switch(obj->type) { case GOBJ_AABOX: *box = *(AABox*)obj; @@ -545,6 +622,11 @@ bool calc_bounding_aabox(AABox *box, const Vec3 *v, int num, const Mat4 &xform) bool calc_bounding_box(Box *box, const GeomObject *obj) { + if(!obj->valid()) { + box->invalidate(); + return true; + } + switch(obj->type) { case GOBJ_BOX: *box = *(Box*)obj; diff --git a/src/geom.h b/src/geom.h index f28f878..5db1996 100644 --- a/src/geom.h +++ b/src/geom.h @@ -12,7 +12,8 @@ enum GeomObjectType { GOBJ_SPHERE, GOBJ_AABOX, GOBJ_BOX, - GOBJ_PLANE + GOBJ_PLANE, + GOBJ_DISC }; class GeomObject; @@ -33,6 +34,9 @@ public: GeomObject(); virtual ~GeomObject(); + virtual bool valid() const; + virtual void invalidate(); + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const = 0; virtual bool contains(const Vec3 &pt) const = 0; @@ -48,6 +52,9 @@ public: Sphere(); Sphere(const Vec3 ¢er, float radius); + virtual bool valid() const; + virtual void invalidate(); + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; virtual bool contains(const Vec3 &pt) const; @@ -62,6 +69,9 @@ public: AABox(); AABox(const Vec3 &min, const Vec3 &max); + virtual bool valid() const; + virtual void invalidate(); + virtual Vec3 get_corner(int idx) const; virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; @@ -82,6 +92,8 @@ public: Box(const Vec3 &pos, const Vec3 &vi, const Vec3 &vj, const Vec3 &vk); Box(const Vec3 *varr, int vcount); + virtual void invalidate(); + virtual Vec3 get_corner(int idx) const; virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; @@ -116,6 +128,9 @@ public: Disc(const Vec3 &pt, const Vec3 &normal, float rad); Disc(const Vec3 &normal, float dist, float rad); + virtual bool valid() const; + virtual void invalidate(); + virtual bool intersect(const Ray &ray, HitPoint *hit = 0) const; //! true if the projection of pt to the plane is contained within the disc radius virtual bool contains(const Vec3 &pt) const; diff --git a/src/geomdraw.cc b/src/geomdraw.cc new file mode 100644 index 0000000..b348f87 --- /dev/null +++ b/src/geomdraw.cc @@ -0,0 +1,80 @@ +#include "geomdraw.h" +#include "opengl.h" +#include "logger.h" +#include "shader.h" + +static void draw_sphere(const Sphere *sph); +static void draw_box(const Box *box); +static void draw_plane(const Plane *plane); + +void draw_geom_object(const GeomObject *gobj) +{ + switch(gobj->type) { + case GOBJ_SPHERE: + draw_sphere((Sphere*)gobj); + break; + + case GOBJ_AABOX: + { + Box box = Box(*(AABox*)gobj, Mat4::identity); + draw_box(&box); + } + break; + + case GOBJ_BOX: + draw_box((Box*)gobj); + break; + + case GOBJ_PLANE: + draw_plane((Plane*)gobj); + break; + + default: + break; + } +} + +static void draw_sphere(const Sphere *sph) +{ + // TODO + warning_log("draw_sphere unimplemented\n"); +} + +static void draw_box(const Box *box) +{ + static const int edges[][2] = { + {0, 1}, {1, 2}, {2, 3}, {3, 0}, + {4, 5}, {5, 6}, {6, 7}, {7, 4}, + {0, 4}, {1, 5}, {2, 6}, {3, 7} + }; + + bind_shader(0); + + glPushAttrib(GL_ENABLE_BIT); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glMultMatrixf(box->xform[0]); + + glBegin(GL_LINES); + glColor3f(1, 1, 0); + for(int i=0; i<12; i++) { + Vec3 a = box->get_corner(edges[i][0]); + Vec3 b = box->get_corner(edges[i][1]); + + glVertex3f(a.x, a.y, a.z); + glVertex3f(b.x, b.y, b.z); + } + glEnd(); + + glPopMatrix(); + glPopAttrib(); +} + +static void draw_plane(const Plane *plane) +{ + // TODO + warning_log("draw_plane unimplemented\n"); +} diff --git a/src/geomdraw.h b/src/geomdraw.h new file mode 100644 index 0000000..05e86e6 --- /dev/null +++ b/src/geomdraw.h @@ -0,0 +1,8 @@ +#ifndef GEOMDRAW_H_ +#define GEOMDRAW_H_ + +#include "geom.h" + +void draw_geom_object(const GeomObject *gobj); + +#endif diff --git a/src/object.cc b/src/object.cc index 3318660..2bc8b79 100644 --- a/src/object.cc +++ b/src/object.cc @@ -38,6 +38,5 @@ void Object::draw() const const AABox &Object::get_aabox() const { - static AABox null_box; - return null_box; + return aabb; } diff --git a/src/object.h b/src/object.h index 65c39e1..3ffec1f 100644 --- a/src/object.h +++ b/src/object.h @@ -12,12 +12,12 @@ class SceneNode; enum ObjType { OBJ_NULL, OBJ_MESH }; class Object { -private: +protected: std::string name; + mutable AABox aabb; public: Material mtl; - //GeomObject *bvol; SceneNode *node; Object(); diff --git a/src/snode.cc b/src/snode.cc index eee5fce..fd37f24 100644 --- a/src/snode.cc +++ b/src/snode.cc @@ -330,7 +330,7 @@ AABox SceneNode::get_bounds() const calc_bounding_aabox(&sub_aabb, &sub_aabb, &tmp); } - AABox aabb; - calc_bounding_aabox(&aabb, &local_bvol, &sub_aabb); + AABox aabb = get_node_bounds(); + calc_bounding_aabox(&aabb, &aabb, &sub_aabb); return aabb; } -- 1.7.10.4