mirror planes detection needs work
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 17 Mar 2018 05:49:22 +0000 (07:49 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 17 Mar 2018 05:49:22 +0000 (07:49 +0200)
src/app.cc
src/app.h
src/metascene.cc
src/metascene.h
src/opengl.c
src/opengl.h
src/renderer.cc
src/renderer.h

index b61b0e7..30222f9 100644 (file)
@@ -33,6 +33,7 @@ static Ray calc_pick_ray(int x, int y);
 
 long time_msec;
 int win_width, win_height;
 
 long time_msec;
 int win_width, win_height;
+int vp_width, vp_height;
 float win_aspect;
 bool fb_srgb;
 bool opt_gear_wireframe;
 float win_aspect;
 bool fb_srgb;
 bool opt_gear_wireframe;
@@ -166,11 +167,8 @@ bool app_init(int argc, char **argv)
        avatar.body_rot = rad_to_deg(acos(dot(dir, Vec3(0, 0, 1))));
 
        exman = new ExhibitManager;
        avatar.body_rot = rad_to_deg(acos(dot(dir, Vec3(0, 0, 1))));
 
        exman = new ExhibitManager;
-       /*
-       if(!exman->load(mscn, "data/exhibits")) {
-               //return false;
-       }
-       */
+       // exhibits are loaded in post_scene_init, because they need access to the scene graph
+
        if(!exui_init()) {
                error_log("failed to initialize exhibit ui system\n");
                return false;
        if(!exui_init()) {
                error_log("failed to initialize exhibit ui system\n");
                return false;
@@ -194,6 +192,9 @@ bool app_init(int argc, char **argv)
        }
 
        rend = new Renderer;
        }
 
        rend = new Renderer;
+       if(!rend->init()) {
+               return false;
+       }
        rend->set_scene(mscn);
 
        glUseProgram(0);
        rend->set_scene(mscn);
 
        glUseProgram(0);
@@ -208,8 +209,11 @@ bool app_init(int argc, char **argv)
        return true;
 }
 
        return true;
 }
 
+// post_scene_init is called after the scene has completed loading
 static void post_scene_init()
 {
 static void post_scene_init()
 {
+       mscn->update(0);        // update once to calculate node matrices
+
        int num_mir = mscn->calc_mirror_planes();
        info_log("found %d mirror planes\n", num_mir);
 
        int num_mir = mscn->calc_mirror_planes();
        info_log("found %d mirror planes\n", num_mir);
 
@@ -429,6 +433,8 @@ void app_display()
                for(int i=0; i<2; i++) {
                        // for each eye
                        goatvr_draw_eye(i);
                for(int i=0; i<2; i++) {
                        // for each eye
                        goatvr_draw_eye(i);
+                       vp_width = goatvr_get_fb_eye_width(i);
+                       vp_height = goatvr_get_fb_eye_height(i);
 
                        proj_matrix = goatvr_projection_matrix(i, NEAR_CLIP, FAR_CLIP);
                        glMatrixMode(GL_PROJECTION);
 
                        proj_matrix = goatvr_projection_matrix(i, NEAR_CLIP, FAR_CLIP);
                        glMatrixMode(GL_PROJECTION);
@@ -449,6 +455,9 @@ void app_display()
                }
                goatvr_draw_done();
 
                }
                goatvr_draw_done();
 
+               vp_width = win_width;
+               vp_height = win_height;
+
                if(should_swap) {
                        app_swap_buffers();
                }
                if(should_swap) {
                        app_swap_buffers();
                }
@@ -555,6 +564,9 @@ void app_reshape(int x, int y)
        glViewport(0, 0, x, y);
        goatvr_set_fb_size(x, y, 1.0f);
        debug_gui_reshape(x, y);
        glViewport(0, 0, x, y);
        goatvr_set_fb_size(x, y, 1.0f);
        debug_gui_reshape(x, y);
+
+       vp_width = x;
+       vp_height = y;
 }
 
 void app_keyboard(int key, bool pressed)
 }
 
 void app_keyboard(int key, bool pressed)
index 686c7e0..0e41312 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -7,6 +7,7 @@
 
 extern long time_msec;
 extern int win_width, win_height;
 
 extern long time_msec;
 extern int win_width, win_height;
+extern int vp_width, vp_height;        // viewport size differs from win size during VR eye rendering
 extern float win_aspect;
 extern bool opt_gear_wireframe;
 extern bool fb_srgb;
 extern float win_aspect;
 extern bool opt_gear_wireframe;
 extern bool fb_srgb;
index 82cf669..6805fae 100644 (file)
@@ -203,6 +203,8 @@ Scene *MetaScene::extract_nodes(const char *qstr)
 
 int MetaScene::calc_mirror_planes()
 {
 
 int MetaScene::calc_mirror_planes()
 {
+       std::vector<Vec4> world_planes;
+
        int num_mirrors = 0;
        while(mirrors) {
                FlatMirror *m = mirrors;
        int num_mirrors = 0;
        while(mirrors) {
                FlatMirror *m = mirrors;
@@ -226,6 +228,7 @@ int MetaScene::calc_mirror_planes()
 
                                FlatMirror *mir = new FlatMirror;
                                mir->reflect = obj->mtl.reflect;
 
                                FlatMirror *mir = new FlatMirror;
                                mir->reflect = obj->mtl.reflect;
+                               mir->node = obj->node;
 
                                if(obj->mtl.flat_mirror == MTL_MIRROR_AUTO) {
                                        // grab the first triangle and make a plane
 
                                if(obj->mtl.flat_mirror == MTL_MIRROR_AUTO) {
                                        // grab the first triangle and make a plane
@@ -237,31 +240,36 @@ int MetaScene::calc_mirror_planes()
                                        mir->plane.normal = face.normal;
                                } else {
                                        int plane_idx = obj->mtl.flat_mirror - MTL_MIRROR_AABB_PX;
                                        mir->plane.normal = face.normal;
                                } else {
                                        int plane_idx = obj->mtl.flat_mirror - MTL_MIRROR_AABB_PX;
-                                       if(obj->node) {
-                                               mir->plane = obj->node->get_bounds().get_plane(plane_idx);
-                                       } else {
-                                               mir->plane = obj->get_aabox().get_plane(plane_idx);
-                                       }
+                                       mir->plane = obj->get_aabox().get_plane(plane_idx);
                                        debug_log("mirror plane: p(%f %f %f) n(%f %f %f)\n", mir->plane.pt.x, mir->plane.pt.y,
                                                        mir->plane.pt.z, mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z);
                                }
 
                                        debug_log("mirror plane: p(%f %f %f) n(%f %f %f)\n", mir->plane.pt.x, mir->plane.pt.y,
                                                        mir->plane.pt.z, mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z);
                                }
 
+                               float pdist = dot(mir->plane.normal, mir->plane.pt);
+                               Vec4 plane_eq = Vec4(mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z, pdist);
+
+                               if(obj->node) {
+                                       plane_eq = obj->node->get_matrix() * plane_eq;
+                               }
+
                                // check to see if we have found this mirror plane already
                                bool found = false;
                                // check to see if we have found this mirror plane already
                                bool found = false;
-                               FlatMirror *node = mirrors;
-                               while(node) {
-                                       if(1.0f - dot(mir->plane.normal, node->plane.normal) < 1e-4f &&
-                                                       fabs(dot(mir->plane.normal, normalize(mir->plane.pt - node->plane.pt))) < 1e-4) {
+                               int nplanes = world_planes.size();
+                               for(int k=0; k<nplanes; k++) {
+                                       if(1.0f - dot(plane_eq.xyz(), world_planes[k].xyz()) < 1e-4f &&
+                                                       fabs(plane_eq.w - world_planes[k].w) < 1e-4) {
                                                found = true;
                                                break;
                                        }
                                                found = true;
                                                break;
                                        }
-                                       node = node->next;
                                }
 
                                if(!found) {
                                        mir->next = mirrors;
                                        mirrors = mir;
 
                                }
 
                                if(!found) {
                                        mir->next = mirrors;
                                        mirrors = mir;
 
+                                       world_planes.push_back(plane_eq);
+
+                                       mir->objects.push_back(obj);
                                        objmirror[obj] = mir;   // associate with object
                                        ++num_mirrors;
                                } else {
                                        objmirror[obj] = mir;   // associate with object
                                        ++num_mirrors;
                                } else {
@@ -523,13 +531,13 @@ static bool proc_mtledit(MetaScene *mscn, MaterialEdit *med, struct ts_node *nod
 
                                        switch(tolower(caxis)) {
                                        case 'x':
 
                                        switch(tolower(caxis)) {
                                        case 'x':
-                                               plane = caxis == '+' ? MTL_MIRROR_AABB_PX : MTL_MIRROR_AABB_NX;
+                                               plane = csign == '+' ? MTL_MIRROR_AABB_PX : MTL_MIRROR_AABB_NX;
                                                break;
                                        case 'y':
                                                break;
                                        case 'y':
-                                               plane = caxis == '+' ? MTL_MIRROR_AABB_PY : MTL_MIRROR_AABB_NY;
+                                               plane = csign == '+' ? MTL_MIRROR_AABB_PY : MTL_MIRROR_AABB_NY;
                                                break;
                                        case 'z':
                                                break;
                                        case 'z':
-                                               plane = caxis == '+' ? MTL_MIRROR_AABB_PZ : MTL_MIRROR_AABB_NZ;
+                                               plane = csign == '+' ? MTL_MIRROR_AABB_PZ : MTL_MIRROR_AABB_NZ;
                                                break;
                                        default:
                                                error_log("invalid reflect plane specifier: %s\n", aplane->val.str);
                                                break;
                                        default:
                                                error_log("invalid reflect plane specifier: %s\n", aplane->val.str);
index 0417c00..6987f00 100644 (file)
@@ -13,7 +13,8 @@
 struct FlatMirror {
        Plane plane;
        float reflect;
 struct FlatMirror {
        Plane plane;
        float reflect;
-       //std::vector<Object*> objects;
+       std::vector<Object*> objects;
+       SceneNode *node;
 
        FlatMirror *next;
 };
 
        FlatMirror *next;
 };
@@ -32,7 +33,6 @@ public:
        std::map<Scene*, void*> scndata;
 
        FlatMirror *mirrors;
        std::map<Scene*, void*> scndata;
 
        FlatMirror *mirrors;
-       int num_mirrors;
        std::map<Object*, FlatMirror*> objmirror;
 
        AudioStream *music;
        std::map<Object*, FlatMirror*> objmirror;
 
        AudioStream *music;
index 796144c..a7962c7 100644 (file)
@@ -1,3 +1,4 @@
+#include <stdlib.h>
 #include "opengl.h"
 #include "logger.h"
 
 #include "opengl.h"
 #include "logger.h"
 
@@ -27,6 +28,33 @@ int init_opengl(void)
        return 0;
 }
 
        return 0;
 }
 
+void dump_gl_texture(unsigned int tex, const char *fname)
+{
+       FILE *fp;
+       int i, width, height;
+       unsigned char *pixels;
+
+       glBindTexture(GL_TEXTURE_2D, tex);
+       glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+       glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+
+       if(!(pixels = malloc(width * height * 3))) {
+               return;
+       }
+       glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
+
+       if(!(fp = fopen(fname, "wb"))) {
+               free(pixels);
+               return;
+       }
+       fprintf(fp, "P6\n%d %d\n255\n", width, height);
+       for(i=0; i<width * height * 3; i++) {
+               fputc(pixels[i], fp);
+       }
+       fclose(fp);
+       free(pixels);
+}
+
 
 static void GLAPIENTRY gldebug_logger(GLenum src, GLenum type, GLuint id, GLenum severity,
                GLsizei len, const char *msg, const void *cls)
 
 static void GLAPIENTRY gldebug_logger(GLenum src, GLenum type, GLuint id, GLenum severity,
                GLsizei len, const char *msg, const void *cls)
index 6ef1733..51d365a 100644 (file)
@@ -15,6 +15,8 @@ extern "C" {
 
 int init_opengl(void);
 
 
 int init_opengl(void);
 
+void dump_gl_texture(unsigned int tex, const char *fname);
+
 #ifdef __cplusplus
 }
 #endif
 #ifdef __cplusplus
 }
 #endif
index bb274f2..43a96db 100644 (file)
@@ -1,16 +1,31 @@
 #include "renderer.h"
 #include "renderer.h"
+#include "rtarg.h"
+#include "app.h"
+
+static RenderTarget *rtmirror;
 
 Renderer::Renderer()
 {
        mscn = 0;
 
 Renderer::Renderer()
 {
        mscn = 0;
+       ropt = RENDER_ALL;
 }
 
 Renderer::~Renderer()
 {
 }
 
 Renderer::~Renderer()
 {
+       destroy();
 }
 
 bool Renderer::init()
 {
 }
 
 bool Renderer::init()
 {
+       static bool once;
+       if(!rtmirror && !once) {
+               once = true;
+               rtmirror = new RenderTarget;
+               if(!rtmirror->create(vp_width, vp_height, GL_SRGB)) {
+                       error_log("failed to create mirror render target (%dx%d)\n", vp_width, vp_height);
+               }
+       }
+
        return true;
 }
 
        return true;
 }
 
@@ -28,16 +43,43 @@ MetaScene *Renderer::get_scene() const
        return mscn;
 }
 
        return mscn;
 }
 
+// render mirror reflections if ...
+#define DO_MIRRORS     \
+       mscn->mirrors &&                        /* scene contains mirrors */ \
+       (ropt & RENDER_MIRRORS) &&      /* mirror rendering is enabled */ \
+       rtmirror                                        /* mirror render target succesfully created */
+
 void Renderer::draw() const
 {
        if(!mscn) return;
 
 void Renderer::draw() const
 {
        if(!mscn) return;
 
+       if(DO_MIRRORS && current_render_target() != rtmirror) {
+               // check if the render target needs resizing
+               if(rtmirror->get_width() != vp_width || rtmirror->get_height() != vp_height) {
+                       if(!rtmirror->resize(vp_width, vp_height)) {
+                               error_log("failed to resize mirror render target (%dx%d)\n", vp_width, vp_height);
+                               goto abort_mirrors;
+                       }
+               }
+
+               FlatMirror *mir = mscn->mirrors;
+               while(mir) {
+                       draw_mirror(mir);
+                       mir = mir->next;
+               }
+       }
+abort_mirrors:
+
        int num = (int)mscn->scenes.size();
        for(int i=0; i<num; i++) {
                Scene *scn = mscn->scenes[i];
 
                int nobj = (int)scn->objects.size();
                for(int j=0; j<nobj; j++) {
        int num = (int)mscn->scenes.size();
        for(int i=0; i<num; i++) {
                Scene *scn = mscn->scenes[i];
 
                int nobj = (int)scn->objects.size();
                for(int j=0; j<nobj; j++) {
+                       // don't draw mirrors, we already did that earlier (if mirror rendering enabled)
+                       if((ropt & RENDER_MIRRORS) && scn->objects[j]->mtl.flat_mirror) {
+                               continue;
+                       }
                        draw_object(scn->objects[j]);
                }
        }
                        draw_object(scn->objects[j]);
                }
        }
@@ -59,3 +101,37 @@ void Renderer::draw_object(Object *obj) const
                obj->draw();
        }
 }
                obj->draw();
        }
 }
+
+void Renderer::draw_mirror(FlatMirror *mir) const
+{
+       push_render_target(rtmirror);
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       glMatrixMode(GL_MODELVIEW);
+       glPushMatrix();
+
+       float pdist = dot(mir->plane.normal, mir->plane.pt);
+       Vec4 peq = Vec4(mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z, pdist);
+
+       if(mir->node) {
+               peq = mir->node->get_matrix() * peq;
+       }
+
+       Mat4 mirmat;
+       mirmat.mirror(peq.x, peq.y, peq.z, peq.w);
+       glMultMatrixf(mirmat[0]);
+
+       glFrontFace(GL_CW);
+       draw();
+       glFrontFace(GL_CCW);
+
+       glPopMatrix();
+       pop_render_target();
+
+       dump_gl_texture(rtmirror->texture()->get_id(), "mirror.ppm");
+
+       int nobj = mir->objects.size();
+       for(int i=0; i<nobj; i++) {
+               draw_object(mir->objects[i]);
+       }
+}
index e5af123..e6aa8d5 100644 (file)
@@ -3,11 +3,18 @@
 
 #include "metascene.h"
 
 
 #include "metascene.h"
 
+enum {
+       RENDER_MIRRORS  = 1,
+
+       RENDER_ALL              = 0x7fffffff
+};
+
 class Renderer {
 private:
        MetaScene *mscn;
 
 public:
 class Renderer {
 private:
        MetaScene *mscn;
 
 public:
+       unsigned int ropt;
 
        Renderer();
        virtual ~Renderer();
 
        Renderer();
        virtual ~Renderer();
@@ -20,6 +27,8 @@ public:
 
        virtual void draw() const;
        virtual void draw_object(Object *obj) const;
 
        virtual void draw() const;
        virtual void draw_object(Object *obj) const;
+
+       virtual void draw_mirror(FlatMirror *mir) const;
 };
 
 #endif // RENDERER_H_
 };
 
 #endif // RENDERER_H_