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
This commit is contained in:
Josh Holtrop 2009-03-15 19:51:21 +00:00
parent f103b71ed6
commit 5590c533ce
12 changed files with 203 additions and 173 deletions

2
.todo
View File

@ -4,14 +4,12 @@ FART To-Do List
High Priority: High Priority:
- Add distribution infrastructure - Add distribution infrastructure
- Multi-threading - Multi-threading
- Rework booleans to base them on regions instead of in/out for each side
Medium Priority: Medium Priority:
- Shape definitions / reusability - Shape definitions / reusability
- Scene file pre-parser to allow includes, macros, and comments - Scene file pre-parser to allow includes, macros, and comments
- Vim syntax file - Vim syntax file
- Add jitter parameter to lights to effect soft shadow edges - Add jitter parameter to lights to effect soft shadow edges
- Allow >2 sub-shapes in boolean shape definitions in scene files
Low Priority: Low Priority:
- Refraction - Refraction

View File

@ -465,9 +465,8 @@ refptr<Shape> Scene::processSphere(refptr<Node> node)
refptr<Shape> Scene::processBool(refptr<Node> node) refptr<Shape> Scene::processBool(refptr<Node> node)
{ {
refptr<Shape> shape1, shape2; vector< refptr<Shape> > shapes;
refptr<Material> material; refptr<Material> material;
int shapes_seen = 0;
bool restore_transform = processTransforms(node); bool restore_transform = processTransforms(node);
@ -477,14 +476,9 @@ refptr<Shape> Scene::processBool(refptr<Node> node)
{ {
if ( (*it)->isShape() ) if ( (*it)->isShape() )
{ {
switch (shapes_seen) refptr<Shape> shape = processShape(*it);
{ if ( ! shape.isNull() )
case 0: shape1 = processShape(*it); shapes.push_back(shape);
break;
case 1: shape2 = processShape(*it);
break;
}
shapes_seen++;
} }
else if ( (*it)->isMaterial() ) else if ( (*it)->isMaterial() )
{ {
@ -492,30 +486,20 @@ refptr<Shape> Scene::processBool(refptr<Node> node)
} }
} }
if (shapes_seen < 2 || shape1.isNull() || shape2.isNull()) if (shapes.size() < 2)
{ {
if (shapes_seen < 2) cerr << "Error: boolean objects must have 2 or more sub-objects!"
cerr << __FILE__ << ": " << __LINE__ << endl;
<< ": 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;
exit(3); exit(3);
} }
refptr<Shape> shape; refptr<Shape> shape;
if ( typeid(*node) == typeid(IntersectNode) ) if ( typeid(*node) == typeid(IntersectNode) )
shape = new Intersect(shape1, shape2); shape = new Intersect(shapes);
else if ( typeid(*node) == typeid(UnionNode) ) else if ( typeid(*node) == typeid(UnionNode) )
shape = new Union(shape1, shape2); shape = new Union(shapes);
else if ( typeid(*node) == typeid(SubtractNode) ) else if ( typeid(*node) == typeid(SubtractNode) )
shape = new Subtract(shape1, shape2); shape = new Subtract(shapes);
else else
{ {
cerr << __FILE__ << ": " << __LINE__ cerr << __FILE__ << ": " << __LINE__

View File

@ -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 { box: BOX LCURLY box_items RCURLY {
$$ = new BoxNode(); $$ = new BoxNode();
$$->addChildren($3); $$->addChildren($3);
@ -171,11 +183,9 @@ cyl_item: SIZE vector {
| shape_item { $$ = $1; } | shape_item { $$ = $1; }
; ;
intersect: INTERSECT LCURLY shape shape shape_items RCURLY { intersect: INTERSECT LCURLY bool_items RCURLY {
$$ = new IntersectNode(); $$ = new IntersectNode();
$$->addChild($3); $$->addChildren($3);
$$->addChild($4);
$$->addChildren($5);
} }
; ;
@ -368,11 +378,9 @@ sphere_item: radius { $$ = $1; }
| shape_item { $$ = $1; } | shape_item { $$ = $1; }
; ;
subtract: SUBTRACT LCURLY shape shape shape_items RCURLY { subtract: SUBTRACT LCURLY bool_items RCURLY {
$$ = new SubtractNode(); $$ = new SubtractNode();
$$->addChild($3); $$->addChildren($3);
$$->addChild($4);
$$->addChildren($5);
} }
; ;
@ -414,11 +422,9 @@ transform_block_item: transform_block { $$ = $1; }
| shape { $$ = $1; } | shape { $$ = $1; }
; ;
union: UNION LCURLY shape shape shape_items RCURLY { union: UNION LCURLY bool_items RCURLY {
$$ = new UnionNode(); $$ = new UnionNode();
$$->addChild($3); $$->addChildren($3);
$$->addChild($4);
$$->addChildren($5);
} }
; ;

View File

@ -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 <1, 0.8, 0.8> } box { size <0.8, 0.8, 1> }
union {
box { size <0.8, 1, 0.8> } cyl { size <0.1, 0.1, 0.8> translate <0.4, 0.4, -0.4> }
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> }
union {
union { cyl { size <.1, .1, .8> translate <.4, -.4, .4> rotate -90, <1, 0, 0> }
union { cyl { size <.1, .1, .8> translate <.4, -.4, -.4> rotate -90, <1, 0, 0> }
cyl { cyl { size <.1, .1, .8> translate <-.4, -.4, .4> rotate -90, <1, 0, 0> }
size <0.1, 0.1, 0.8> cyl { size <.1, .1, .8> translate <-.4, -.4, -.4> rotate -90, <1, 0, 0> }
translate <0.4, 0.4, -0.4>
} cyl { size <.1, .1, .8> translate <.4, -.4, .4> rotate -90, <0, 1, 0> }
cyl { cyl { size <.1, .1, .8> translate <.4, -.4, -.4> rotate -90, <0, 1, 0> }
size <0.1, 0.1, 0.8> cyl { size <.1, .1, .8> translate <.4, .4, .4> rotate -90, <0, 1, 0> }
translate <0.4, -0.4, -0.4> cyl { size <.1, .1, .8> translate <.4, .4, -.4> rotate -90, <0, 1, 0> }
}
} sphere { radius .1 translate <.4, .4, .4> }
union { sphere { radius .1 translate <.4, .4, -.4> }
cyl { sphere { radius .1 translate <.4, -.4, .4> }
size <0.1, 0.1, 0.8> sphere { radius .1 translate <.4, -.4, -.4> }
translate <-0.4, 0.4, -0.4> sphere { radius .1 translate <-.4, .4, .4> }
} sphere { radius .1 translate <-.4, .4, -.4> }
cyl { sphere { radius .1 translate <-.4, -.4, .4> }
size <0.1, 0.1, 0.8> sphere { radius .1 translate <-.4, -.4, -.4> }
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> }
}
}
}
material material
{ {

View File

@ -1,16 +1,6 @@
#include "BoolShape.h" #include "BoolShape.h"
BoolShape::BoolShape(refptr<Shape> shape1, refptr<Shape> shape2)
{
m_shape1 = shape1;
m_shape2 = shape2;
}
BoolShape::~BoolShape()
{
}
void BoolShape::setMaterial(refptr<Material> material) void BoolShape::setMaterial(refptr<Material> material)
{ {
m_material = material; m_material = material;

View File

@ -7,8 +7,6 @@
class BoolShape : public Shape class BoolShape : public Shape
{ {
public: public:
BoolShape(refptr<Shape> shape1, refptr<Shape> shape2);
~BoolShape();
virtual IntersectionList intersect(refptr<Shape> _this, const Ray & ray) = 0; virtual IntersectionList intersect(refptr<Shape> _this, const Ray & ray) = 0;
virtual void setMaterial(refptr<Material> material); virtual void setMaterial(refptr<Material> material);

View File

@ -3,9 +3,30 @@
#include <iostream> #include <iostream>
using namespace std; using namespace std;
Intersect::Intersect(refptr<Shape> shape1, refptr<Shape> shape2) Intersect::Intersect(const vector< refptr<Shape> > & shapes)
: BoolShape(shape1, shape2)
{ {
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > 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<Shape> _this, const Ray & ray) Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ray)
@ -16,8 +37,31 @@ Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ra
IntersectionList res; IntersectionList res;
bool in1 = false, in2 = false; 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++) for (int i = 0, sz = merged.size(); i < sz; i++)
{ {
Vector normal = merged[i].intersection.normal; Vector normal = merged[i].intersection.normal;

View File

@ -3,11 +3,12 @@
#define INTERSECT_H INTERSECT_H #define INTERSECT_H INTERSECT_H
#include "BoolShape.h" #include "BoolShape.h"
#include <vector>
class Intersect : public BoolShape class Intersect : public BoolShape
{ {
public: public:
Intersect(refptr<Shape> shape1, refptr<Shape> shape2); Intersect(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
}; };

View File

@ -3,9 +3,30 @@
#include <iostream> #include <iostream>
using namespace std; using namespace std;
Subtract::Subtract(refptr<Shape> shape1, refptr<Shape> shape2) Subtract::Subtract(const vector< refptr<Shape> > & shapes)
: BoolShape(shape1, shape2)
{ {
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > 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<Shape> _this, const Ray & ray) Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray)
@ -16,8 +37,31 @@ Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray
IntersectionList res; IntersectionList res;
bool in1 = false, in2 = false; 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++) for (int i = 0, sz = merged.size(); i < sz; i++)
{ {
Vector normal = merged[i].intersection.normal; Vector normal = merged[i].intersection.normal;

View File

@ -3,11 +3,12 @@
#define SUBTRACT_H SUBTRACT_H #define SUBTRACT_H SUBTRACT_H
#include "BoolShape.h" #include "BoolShape.h"
#include <vector>
class Subtract : public BoolShape class Subtract : public BoolShape
{ {
public: public:
Subtract(refptr<Shape> shape1, refptr<Shape> shape2); Subtract(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
}; };

View File

@ -1,11 +1,33 @@
#include "Union.h" #include "Union.h"
#include <iostream> #include <iostream>
#include <vector>
using namespace std; using namespace std;
Union::Union(refptr<Shape> shape1, refptr<Shape> shape2) Union::Union(const vector< refptr<Shape> > & shapes)
: BoolShape(shape1, shape2)
{ {
int num_shapes = shapes.size();
if (num_shapes > 2)
{
m_shape2 = shapes[num_shapes - 1];
vector< refptr<Shape> > 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<Shape> _this, const Ray & ray) Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
@ -16,8 +38,31 @@ Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
IntersectionList res; IntersectionList res;
bool in1 = false, in2 = false; 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++) for (int i = 0, sz = merged.size(); i < sz; i++)
{ {
Vector normal = merged[i].intersection.normal; Vector normal = merged[i].intersection.normal;

View File

@ -3,11 +3,12 @@
#define UNION_H UNION_H #define UNION_H UNION_H
#include "BoolShape.h" #include "BoolShape.h"
#include <vector>
class Union : public BoolShape class Union : public BoolShape
{ {
public: public:
Union(refptr<Shape> shape1, refptr<Shape> shape2); Union(const std::vector< refptr<Shape> > & shapes);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
}; };