From 5590c533ce823635710c5733927d162129d65cdd Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 15 Mar 2009 19:51:21 +0000 Subject: [PATCH] Fixed boolean objects to determine if rays start inside or outside the boolean; changed constructors to accept a list of shapes instead of just two shapes; changed parser to accept any number of top-level shapes inside of a boolean shape block; changed scenes/die.fart to reflect this change (a drastic simplification) git-svn-id: svn://anubis/fart/trunk@215 7f9b0f55-74a9-4bce-be96-3c2cd072584d --- .todo | 2 - main/Scene-load.cc | 36 ++++-------- parser/parser.yy | 30 ++++++---- scenes/die.fart | 136 +++++++++----------------------------------- shapes/BoolShape.cc | 10 ---- shapes/BoolShape.h | 2 - shapes/Intersect.cc | 50 +++++++++++++++- shapes/Intersect.h | 3 +- shapes/Subtract.cc | 50 +++++++++++++++- shapes/Subtract.h | 3 +- shapes/Union.cc | 51 ++++++++++++++++- shapes/Union.h | 3 +- 12 files changed, 203 insertions(+), 173 deletions(-) diff --git a/.todo b/.todo index 2315ed4..dd7ca1d 100644 --- a/.todo +++ b/.todo @@ -4,14 +4,12 @@ FART To-Do List High Priority: - Add distribution infrastructure - Multi-threading - - Rework booleans to base them on regions instead of in/out for each side Medium Priority: - Shape definitions / reusability - Scene file pre-parser to allow includes, macros, and comments - Vim syntax file - Add jitter parameter to lights to effect soft shadow edges - - Allow >2 sub-shapes in boolean shape definitions in scene files Low Priority: - Refraction diff --git a/main/Scene-load.cc b/main/Scene-load.cc index 71ced78..f568aac 100644 --- a/main/Scene-load.cc +++ b/main/Scene-load.cc @@ -465,9 +465,8 @@ refptr Scene::processSphere(refptr node) refptr Scene::processBool(refptr node) { - refptr shape1, shape2; + vector< refptr > shapes; refptr material; - int shapes_seen = 0; bool restore_transform = processTransforms(node); @@ -477,14 +476,9 @@ refptr Scene::processBool(refptr node) { if ( (*it)->isShape() ) { - switch (shapes_seen) - { - case 0: shape1 = processShape(*it); - break; - case 1: shape2 = processShape(*it); - break; - } - shapes_seen++; + refptr shape = processShape(*it); + if ( ! shape.isNull() ) + shapes.push_back(shape); } else if ( (*it)->isMaterial() ) { @@ -492,30 +486,20 @@ refptr Scene::processBool(refptr node) } } - if (shapes_seen < 2 || shape1.isNull() || shape2.isNull()) + if (shapes.size() < 2) { - if (shapes_seen < 2) - cerr << __FILE__ << ": " << __LINE__ - << ": error: only saw " - << shapes_seen - << " child shapes!" - << endl; - if (shape1.isNull()) - cerr << __FILE__ << ": " << __LINE__ - << ": error: shape1 is null!" << endl; - if (shape2.isNull()) - cerr << __FILE__ << ": " << __LINE__ - << ": error: shape2 is null!" << endl; + cerr << "Error: boolean objects must have 2 or more sub-objects!" + << endl; exit(3); } refptr shape; if ( typeid(*node) == typeid(IntersectNode) ) - shape = new Intersect(shape1, shape2); + shape = new Intersect(shapes); else if ( typeid(*node) == typeid(UnionNode) ) - shape = new Union(shape1, shape2); + shape = new Union(shapes); else if ( typeid(*node) == typeid(SubtractNode) ) - shape = new Subtract(shape1, shape2); + shape = new Subtract(shapes); else { cerr << __FILE__ << ": " << __LINE__ diff --git a/parser/parser.yy b/parser/parser.yy index 2ef0361..3eaeb49 100644 --- a/parser/parser.yy +++ b/parser/parser.yy @@ -103,6 +103,18 @@ scene: SCENE LCURLY scene_items RCURLY { } ; +bool_items: /* empty */ + | bool_item bool_items { + $$ = new ItemsNode(); + $$->addChild($1); + $$->addChildren($2); + } + ; + +bool_item: shape + | shape_item + ; + box: BOX LCURLY box_items RCURLY { $$ = new BoxNode(); $$->addChildren($3); @@ -171,11 +183,9 @@ cyl_item: SIZE vector { | shape_item { $$ = $1; } ; -intersect: INTERSECT LCURLY shape shape shape_items RCURLY { +intersect: INTERSECT LCURLY bool_items RCURLY { $$ = new IntersectNode(); - $$->addChild($3); - $$->addChild($4); - $$->addChildren($5); + $$->addChildren($3); } ; @@ -368,11 +378,9 @@ sphere_item: radius { $$ = $1; } | shape_item { $$ = $1; } ; -subtract: SUBTRACT LCURLY shape shape shape_items RCURLY { +subtract: SUBTRACT LCURLY bool_items RCURLY { $$ = new SubtractNode(); - $$->addChild($3); - $$->addChild($4); - $$->addChildren($5); + $$->addChildren($3); } ; @@ -414,11 +422,9 @@ transform_block_item: transform_block { $$ = $1; } | shape { $$ = $1; } ; -union: UNION LCURLY shape shape shape_items RCURLY { +union: UNION LCURLY bool_items RCURLY { $$ = new UnionNode(); - $$->addChild($3); - $$->addChild($4); - $$->addChildren($5); + $$->addChildren($3); } ; diff --git a/scenes/die.fart b/scenes/die.fart index 1c4e82d..ef44f66 100644 --- a/scenes/die.fart +++ b/scenes/die.fart @@ -19,115 +19,33 @@ scene union { - union { - union { - box { size <1, 0.8, 0.8> } - union { - box { size <0.8, 1, 0.8> } - box { size <0.8, 0.8, 1> } - } - } - union { - union { - union { - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, 0.4, -0.4> - } - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, -0.4, -0.4> - } - } - union { - cyl { - size <0.1, 0.1, 0.8> - translate <-0.4, 0.4, -0.4> - } - cyl { - size <0.1, 0.1, 0.8> - translate <-0.4, -0.4, -0.4> - } - } - } - union { - union { - union { - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, -0.4, 0.4> - rotate -90, <1, 0, 0> - } - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, -0.4, -0.4> - rotate -90, <1, 0, 0> - } - } - union { - cyl { - size <0.1, 0.1, 0.8> - translate <-0.4, -0.4, 0.4> - rotate -90, <1, 0, 0> - } - cyl { - size <0.1, 0.1, 0.8> - translate <-0.4, -0.4, -0.4> - rotate -90, <1, 0, 0> - } - } - } - union { - union { - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, -0.4, 0.4> - rotate -90, <0, 1, 0> - } - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, -0.4, -0.4> - rotate -90, <0, 1, 0> - } - } - union { - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, 0.4, 0.4> - rotate -90, <0, 1, 0> - } - cyl { - size <0.1, 0.1, 0.8> - translate <0.4, 0.4, -0.4> - rotate -90, <0, 1, 0> - } - } - } - } - } - } - union { - union { - union { - sphere { radius 0.1 translate <0.4, 0.4, 0.4> } - sphere { radius 0.1 translate <0.4, 0.4, -0.4> } - } - union { - sphere { radius 0.1 translate <0.4, -0.4, 0.4> } - sphere { radius 0.1 translate <0.4, -0.4, -0.4> } - } - } - union { - union { - sphere { radius 0.1 translate <-0.4, 0.4, 0.4> } - sphere { radius 0.1 translate <-0.4, 0.4, -0.4> } - } - union { - sphere { radius 0.1 translate <-0.4, -0.4, 0.4> } - sphere { radius 0.1 translate <-0.4, -0.4, -0.4> } - } - } - } + box { size <1, 0.8, 0.8> } + box { size <0.8, 1, 0.8> } + box { size <0.8, 0.8, 1> } + + cyl { size <0.1, 0.1, 0.8> translate <0.4, 0.4, -0.4> } + cyl { size <0.1, 0.1, 0.8> translate <0.4, -0.4, -0.4> } + cyl { size <0.1, 0.1, 0.8> translate <-0.4, 0.4, -0.4> } + cyl { size <0.1, 0.1, 0.8> translate <-0.4, -0.4, -0.4> } + + cyl { size <.1, .1, .8> translate <.4, -.4, .4> rotate -90, <1, 0, 0> } + cyl { size <.1, .1, .8> translate <.4, -.4, -.4> rotate -90, <1, 0, 0> } + cyl { size <.1, .1, .8> translate <-.4, -.4, .4> rotate -90, <1, 0, 0> } + cyl { size <.1, .1, .8> translate <-.4, -.4, -.4> rotate -90, <1, 0, 0> } + + cyl { size <.1, .1, .8> translate <.4, -.4, .4> rotate -90, <0, 1, 0> } + cyl { size <.1, .1, .8> translate <.4, -.4, -.4> rotate -90, <0, 1, 0> } + cyl { size <.1, .1, .8> translate <.4, .4, .4> rotate -90, <0, 1, 0> } + cyl { size <.1, .1, .8> translate <.4, .4, -.4> rotate -90, <0, 1, 0> } + + sphere { radius .1 translate <.4, .4, .4> } + sphere { radius .1 translate <.4, .4, -.4> } + sphere { radius .1 translate <.4, -.4, .4> } + sphere { radius .1 translate <.4, -.4, -.4> } + sphere { radius .1 translate <-.4, .4, .4> } + sphere { radius .1 translate <-.4, .4, -.4> } + sphere { radius .1 translate <-.4, -.4, .4> } + sphere { radius .1 translate <-.4, -.4, -.4> } material { diff --git a/shapes/BoolShape.cc b/shapes/BoolShape.cc index bf3a3f4..3695963 100644 --- a/shapes/BoolShape.cc +++ b/shapes/BoolShape.cc @@ -1,16 +1,6 @@ #include "BoolShape.h" -BoolShape::BoolShape(refptr shape1, refptr shape2) -{ - m_shape1 = shape1; - m_shape2 = shape2; -} - -BoolShape::~BoolShape() -{ -} - void BoolShape::setMaterial(refptr material) { m_material = material; diff --git a/shapes/BoolShape.h b/shapes/BoolShape.h index dd2f909..c633906 100644 --- a/shapes/BoolShape.h +++ b/shapes/BoolShape.h @@ -7,8 +7,6 @@ class BoolShape : public Shape { public: - BoolShape(refptr shape1, refptr shape2); - ~BoolShape(); virtual IntersectionList intersect(refptr _this, const Ray & ray) = 0; virtual void setMaterial(refptr material); diff --git a/shapes/Intersect.cc b/shapes/Intersect.cc index 666f6aa..dd343dd 100644 --- a/shapes/Intersect.cc +++ b/shapes/Intersect.cc @@ -3,9 +3,30 @@ #include using namespace std; -Intersect::Intersect(refptr shape1, refptr shape2) - : BoolShape(shape1, shape2) +Intersect::Intersect(const vector< refptr > & shapes) { + int num_shapes = shapes.size(); + if (num_shapes > 2) + { + m_shape2 = shapes[num_shapes - 1]; + vector< refptr > rest = shapes; + rest.pop_back(); + m_shape1 = new Intersect(rest); + } + else if (num_shapes == 2) + { + m_shape1 = shapes[0]; + m_shape2 = shapes[1]; + } + else + { + cerr << __FILE__ << ": " << __LINE__ + << ": error: Intersect::Intersect() called with only " + << num_shapes + << " sub-shapes!" + << endl; + exit(4); + } } Shape::IntersectionList Intersect::intersect(refptr _this, const Ray & ray) @@ -16,8 +37,31 @@ Shape::IntersectionList Intersect::intersect(refptr _this, const Ray & ra IntersectionList res; bool in1 = false, in2 = false; - bool in_bool = false; + /* initially go through the merged intersections to see whether + * the ray started inside one of the sub-objects */ + for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0; + i < sz && (!saw1 || !saw2); + i++) + { + Vector normal = merged[i].intersection.normal; + double dot = - (ray.getDirection() % normal); + bool back = dot < 0.0; + bool left = merged[i].left; + if (back) + { + if (left && !saw1) + in1 = true; + else if (!left && !saw2) + in2 = true; + } + if (left) + saw1 = 1; + else + saw2 = 1; + } + + bool in_bool = in1 && in2; for (int i = 0, sz = merged.size(); i < sz; i++) { Vector normal = merged[i].intersection.normal; diff --git a/shapes/Intersect.h b/shapes/Intersect.h index 751333b..f958882 100644 --- a/shapes/Intersect.h +++ b/shapes/Intersect.h @@ -3,11 +3,12 @@ #define INTERSECT_H INTERSECT_H #include "BoolShape.h" +#include class Intersect : public BoolShape { public: - Intersect(refptr shape1, refptr shape2); + Intersect(const std::vector< refptr > & shapes); IntersectionList intersect(refptr _this, const Ray & ray); }; diff --git a/shapes/Subtract.cc b/shapes/Subtract.cc index c847cba..ec22725 100644 --- a/shapes/Subtract.cc +++ b/shapes/Subtract.cc @@ -3,9 +3,30 @@ #include using namespace std; -Subtract::Subtract(refptr shape1, refptr shape2) - : BoolShape(shape1, shape2) +Subtract::Subtract(const vector< refptr > & shapes) { + int num_shapes = shapes.size(); + if (num_shapes > 2) + { + m_shape2 = shapes[num_shapes - 1]; + vector< refptr > rest = shapes; + rest.pop_back(); + m_shape1 = new Subtract(rest); + } + else if (num_shapes == 2) + { + m_shape1 = shapes[0]; + m_shape2 = shapes[1]; + } + else + { + cerr << __FILE__ << ": " << __LINE__ + << ": error: Subtract::Subtract() called with only " + << num_shapes + << " sub-shapes!" + << endl; + exit(4); + } } Shape::IntersectionList Subtract::intersect(refptr _this, const Ray & ray) @@ -16,8 +37,31 @@ Shape::IntersectionList Subtract::intersect(refptr _this, const Ray & ray IntersectionList res; bool in1 = false, in2 = false; - bool in_bool = false; + /* initially go through the merged intersections to see whether + * the ray started inside one of the sub-objects */ + for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0; + i < sz && (!saw1 || !saw2); + i++) + { + Vector normal = merged[i].intersection.normal; + double dot = - (ray.getDirection() % normal); + bool back = dot < 0.0; + bool left = merged[i].left; + if (back) + { + if (left && !saw1) + in1 = true; + else if (!left && !saw2) + in2 = true; + } + if (left) + saw1 = 1; + else + saw2 = 1; + } + + bool in_bool = in1 && !in2; for (int i = 0, sz = merged.size(); i < sz; i++) { Vector normal = merged[i].intersection.normal; diff --git a/shapes/Subtract.h b/shapes/Subtract.h index 4a6f3a5..9697b8b 100644 --- a/shapes/Subtract.h +++ b/shapes/Subtract.h @@ -3,11 +3,12 @@ #define SUBTRACT_H SUBTRACT_H #include "BoolShape.h" +#include class Subtract : public BoolShape { public: - Subtract(refptr shape1, refptr shape2); + Subtract(const std::vector< refptr > & shapes); IntersectionList intersect(refptr _this, const Ray & ray); }; diff --git a/shapes/Union.cc b/shapes/Union.cc index e22f4d8..07d7af6 100644 --- a/shapes/Union.cc +++ b/shapes/Union.cc @@ -1,11 +1,33 @@ #include "Union.h" #include +#include using namespace std; -Union::Union(refptr shape1, refptr shape2) - : BoolShape(shape1, shape2) +Union::Union(const vector< refptr > & shapes) { + int num_shapes = shapes.size(); + if (num_shapes > 2) + { + m_shape2 = shapes[num_shapes - 1]; + vector< refptr > rest = shapes; + rest.pop_back(); + m_shape1 = new Union(rest); + } + else if (num_shapes == 2) + { + m_shape1 = shapes[0]; + m_shape2 = shapes[1]; + } + else + { + cerr << __FILE__ << ": " << __LINE__ + << ": error: Union::Union() called with only " + << num_shapes + << " sub-shapes!" + << endl; + exit(4); + } } Shape::IntersectionList Union::intersect(refptr _this, const Ray & ray) @@ -16,8 +38,31 @@ Shape::IntersectionList Union::intersect(refptr _this, const Ray & ray) IntersectionList res; bool in1 = false, in2 = false; - bool in_bool = false; + /* initially go through the merged intersections to see whether + * the ray started inside one of the sub-objects */ + for (int i = 0, sz = merged.size(), saw1 = 0, saw2 = 0; + i < sz && (!saw1 || !saw2); + i++) + { + Vector normal = merged[i].intersection.normal; + double dot = - (ray.getDirection() % normal); + bool back = dot < 0.0; + bool left = merged[i].left; + if (back) + { + if (left && !saw1) + in1 = true; + else if (!left && !saw2) + in2 = true; + } + if (left) + saw1 = 1; + else + saw2 = 1; + } + + bool in_bool = in1 || in2; for (int i = 0, sz = merged.size(); i < sz; i++) { Vector normal = merged[i].intersection.normal; diff --git a/shapes/Union.h b/shapes/Union.h index ddd3306..e332990 100644 --- a/shapes/Union.h +++ b/shapes/Union.h @@ -3,11 +3,12 @@ #define UNION_H UNION_H #include "BoolShape.h" +#include class Union : public BoolShape { public: - Union(refptr shape1, refptr shape2); + Union(const std::vector< refptr > & shapes); IntersectionList intersect(refptr _this, const Ray & ray); };