reflection geometry finally correct
[laserbrain_demo] / src / metascene.cc
index 09527e9..eef5e65 100644 (file)
@@ -37,6 +37,7 @@ struct MaterialEditTexture {
 
 struct MaterialEditMirror {
        float reflectivity;
+       int plane;
 };
 
 struct MaterialEdit {
@@ -107,7 +108,7 @@ void MetaScene::update(float dt)
                static bool once;
                if(!once) {
                        float x = ImGui::GetColumnOffset(1);
-                       ImGui::SetColumnOffset(1, x * 1.7);
+                       ImGui::SetColumnOffset(1, x * 1.55);
                        once = true;
                }
        }
@@ -179,7 +180,7 @@ std::list<SceneNode*> MetaScene::match_nodes(const char *qstr) const
                        res.splice(res.end(), tmp);
                }
        }
-       return std::move(res);
+       return res;     // hopefully it'll be moved
 }
 
 Scene *MetaScene::extract_nodes(const char *qstr)
@@ -202,6 +203,8 @@ Scene *MetaScene::extract_nodes(const char *qstr)
 
 int MetaScene::calc_mirror_planes()
 {
+       FlatMirror *planes = 0;
+
        int num_mirrors = 0;
        while(mirrors) {
                FlatMirror *m = mirrors;
@@ -225,9 +228,10 @@ int MetaScene::calc_mirror_planes()
 
                                FlatMirror *mir = new FlatMirror;
                                mir->reflect = obj->mtl.reflect;
+                               mir->node = obj->node;
 
                                if(obj->mtl.flat_mirror == MTL_MIRROR_AUTO) {
-                                       // assume the object is actually flat, so grab the first triangle and make a plane
+                                       // grab the first triangle and make a plane
                                        Triangle face = Triangle(0, (const Vec3*)mesh->get_attrib_data(MESH_ATTR_VERTEX),
                                                        mesh->get_index_data());
                                        face.calc_normal();
@@ -235,24 +239,48 @@ int MetaScene::calc_mirror_planes()
                                        mir->plane.pt = face.v[0];
                                        mir->plane.normal = face.normal;
                                } else {
+                                       int plane_idx = obj->mtl.flat_mirror - MTL_MIRROR_AABB_PX;
+                                       mir->plane = obj->get_aabox().get_plane(plane_idx);
+                               }
+
+                               mir->wplane = mir->plane;
+                               if(obj->node) {
+                                       const Mat4 &xform = obj->node->get_matrix();
+                                       mir->wplane.pt = xform * mir->wplane.pt;
+                                       mir->wplane.normal = normalize(xform.upper3x3() * mir->wplane.normal);
                                }
 
                                // check to see if we have found this mirror plane already
                                bool found = false;
-                               FlatMirror *node = mirrors;
+                               FlatMirror *node = planes;
                                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) {
+                                       float d1 = dot(mir->wplane.normal, mir->wplane.pt);
+                                       float d2 = dot(node->wplane.normal, node->wplane.pt);
+
+                                       if(1.0f - dot(mir->wplane.normal, node->wplane.normal) < 1e-4f &&
+                                                       fabs(d1 - d2) < 1e-4) {
                                                found = true;
                                                break;
                                        }
                                        node = node->next;
                                }
 
+                               debug_log("[%s@%s] mirror plane: local(%g %g %g %g), world(%g %g %g %g)%s\n",
+                                               obj->get_name(), obj->node ? obj->node->get_name() : "<no-node>",
+                                               mir->plane.normal.x, mir->plane.normal.y, mir->plane.normal.z,
+                                               dot(mir->plane.normal, mir->plane.pt), mir->wplane.normal.x, mir->wplane.normal.y,
+                                               mir->wplane.normal.z, dot(mir->wplane.normal, mir->wplane.pt), found ? " duplicate" : "");
+
                                if(!found) {
                                        mir->next = mirrors;
                                        mirrors = mir;
 
+                                       node = new FlatMirror;
+                                       node->wplane = mir->wplane;
+                                       node->next = planes;
+                                       planes = node;
+
+                                       mir->objects.push_back(obj);
                                        objmirror[obj] = mir;   // associate with object
                                        ++num_mirrors;
                                } else {
@@ -262,6 +290,12 @@ int MetaScene::calc_mirror_planes()
                }
        }
 
+       while(planes) {
+               FlatMirror *tmp = planes;
+               planes = planes->next;
+               delete tmp;
+       }
+
        return num_mirrors;
 }
 
@@ -499,6 +533,35 @@ static bool proc_mtledit(MetaScene *mscn, MaterialEdit *med, struct ts_node *nod
                if(strcmp(cn->name, "mirror") == 0) {
                        // make this object a flat mirror (hopefully the object is flat otherwise this won't work)
                        float refl = 1.0f;
+                       int plane = MTL_MIRROR_AUTO;
+
+                       struct ts_attr *aplane = ts_get_attr(cn, "plane");
+                       if(aplane) {
+                               if(aplane->val.type == TS_NUMBER) {
+                                       plane = MTL_MIRROR_AABB_PX + aplane->val.inum;
+                               } else {
+                                       char csign, caxis;
+                                       if(sscanf(aplane->val.str, "aabb%c%c", &csign, &caxis) != 2 || (csign != '+' && csign != '-')) {
+                                               error_log("invalid reflect plane specifier: %s\n", aplane->val.str);
+                                               continue;
+                                       }
+
+                                       switch(tolower(caxis)) {
+                                       case 'x':
+                                               plane = csign == '+' ? MTL_MIRROR_AABB_PX : MTL_MIRROR_AABB_NX;
+                                               break;
+                                       case 'y':
+                                               plane = csign == '+' ? MTL_MIRROR_AABB_PY : MTL_MIRROR_AABB_NY;
+                                               break;
+                                       case 'z':
+                                               plane = csign == '+' ? MTL_MIRROR_AABB_PZ : MTL_MIRROR_AABB_NZ;
+                                               break;
+                                       default:
+                                               error_log("invalid reflect plane specifier: %s\n", aplane->val.str);
+                                               continue;
+                                       }
+                               }
+                       }
 
                        struct ts_attr *arefl = ts_get_attr(cn, "reflect");
                        if(arefl) {
@@ -512,6 +575,7 @@ static bool proc_mtledit(MetaScene *mscn, MaterialEdit *med, struct ts_node *nod
 
                        med->type = MTL_EDIT_MIRROR;
                        med->mirror.reflectivity = refl;
+                       med->mirror.plane = plane;
                        break;
                }
        }
@@ -578,7 +642,7 @@ static void apply_mtledit(Material *mtl, const MaterialEdit &med)
                break;
 
        case MTL_EDIT_MIRROR:
-               mtl->flat_mirror = med.mirror.reflectivity > 1e-6;
+               mtl->flat_mirror = med.mirror.plane;
                mtl->reflect = med.mirror.reflectivity;
                break;
        }