Skip to content

Commit

Permalink
Boundingboxes should be ready.
Browse files Browse the repository at this point in the history
Next step (later) would be to properly use them other than group to lower the number of intersection calculation per ray.
  • Loading branch information
Godzil committed Feb 25, 2020
1 parent 831a096 commit 2ea4abd
Show file tree
Hide file tree
Showing 21 changed files with 406 additions and 34 deletions.
89 changes: 87 additions & 2 deletions source/include/boundingbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,96 @@

struct BoundingBox
{
private:
bool isReset;

public:
Tuple min;
Tuple max;

BoundingBox() : min(-0, -0, -0), max(0, 0, 0) { };
BoundingBox(Tuple min, Tuple max) : min(min), max(max) { };
BoundingBox() : min(INFINITY, INFINITY, INFINITY, 1.0), max(-INFINITY, -INFINITY, -INFINITY, 1.0), isReset(true) { };
BoundingBox(Tuple min, Tuple max) : min(min), max(max), isReset(false) { };

void operator|(const BoundingBox &b) {
isReset = false;

if (this->min.x > b.min.x) { this->min.x = b.min.x; }
if (this->min.y > b.min.y) { this->min.y = b.min.y; }
if (this->min.z > b.min.z) { this->min.z = b.min.z; }

if (this->max.x < b.max.x) { this->max.x = b.max.x; }
if (this->max.y < b.max.y) { this->max.y = b.max.y; }
if (this->max.z < b.max.z) { this->max.z = b.max.z; }
}

bool haveFiniteBounds() { return this->min.isRepresentable() && this->max.isRepresentable(); };

bool fitsIn(const BoundingBox &other) {
bool fits = true;

if (this->min.x > other.min.x) { fits = false; }
if (this->min.y > other.min.y) { fits = false; }
if (this->min.z > other.min.z) { fits = false; }

if (this->max.x < other.max.x) { fits = false; }
if (this->max.y < other.max.y) { fits = false; }
if (this->max.z < other.max.z) { fits = false; }

return fits;
}

void checkAxis(double axeOrigin, double axeDirection, double xMin, double xMax, double *axeMin, double *axeMax)
{
double tMinNumerator = (xMin - axeOrigin);
double tMaxNumerator = (xMax - axeOrigin);

if (fabs(axeDirection) >= getEpsilon())
{
*axeMin = tMinNumerator / axeDirection;
*axeMax = tMaxNumerator / axeDirection;
}
else
{
*axeMin = tMinNumerator * INFINITY;
*axeMax = tMaxNumerator * INFINITY;
}

if (*axeMin > *axeMax)
{
double swap = *axeMax;
*axeMax = *axeMin;
*axeMin = swap;
}
}

void reset()
{
this->isReset = true;
min.x = min.y = min.z = INFINITY;
max.x = max.y = max.z = -INFINITY;
}

bool isEmpty() { return this->isReset; };

bool intesectMe(Ray r) {

double xtMin, xtMax, ytMin, ytMax, ztMin, ztMax;
double tMin, tMax;

this->checkAxis(r.origin.x, r.direction.x, this->min.x, this->max.x, &xtMin, &xtMax);
this->checkAxis(r.origin.y, r.direction.y, this->min.y, this->max.y, &ytMin, &ytMax);
this->checkAxis(r.origin.z, r.direction.z, this->min.z, this->max.z, &ztMin, &ztMax);

tMin = max3(xtMin, ytMin, ztMin);
tMax = min3(xtMax, ytMax, ztMax);

if (tMin <= tMax)
{
return true;
}
return false;
}

};

#endif //DORAYME_BOUNDINGBOX_H
1 change: 1 addition & 0 deletions source/include/cone.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Cone : public Shape {

Cone() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(SHAPE_CONE) {};
BoundingBox getBounds();
bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); };
};

#endif /* DORAYME_CONE_H */
1 change: 1 addition & 0 deletions source/include/cylinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Cylinder : public Shape {
Cylinder() : minCap(-INFINITY), maxCap(INFINITY), isClosed(false), Shape(SHAPE_CYLINDER) {};

BoundingBox getBounds();
bool haveFiniteBounds() { return !(isinf(this->minCap) || isinf(this->maxCap)); };
};

#endif //DORAYME_CYLINDER_H
10 changes: 9 additions & 1 deletion source/include/group.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,24 @@

#include <shape.h>

/* TODO: Add a way to force(?) material from group to be applied on childs */

class Group : public Shape
{
private:
uint32_t allocatedObjectCount;
Shape* *objectList;
uint32_t objectCount;

uint32_t allocatedUnboxableObjectCount;
Shape* *unboxableObjectList;
uint32_t unboxableObjectCount;

protected:
Intersect localIntersect(Ray r);
Tuple localNormalAt(Tuple point);


BoundingBox bounds;

public:
bool isEmpty();
Expand All @@ -34,6 +40,8 @@ class Group : public Shape

BoundingBox getBounds();

void updateBoundingBox();

Group();
};

Expand Down
1 change: 1 addition & 0 deletions source/include/plane.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class Plane : public Shape
public:
Plane() : Shape(SHAPE_PLANE) { };
BoundingBox getBounds();
bool haveFiniteBounds() { return false; };
};

#endif //DORAYME_PLANE_H
4 changes: 3 additions & 1 deletion source/include/shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ class Shape
Shape(ShapeType = SHAPE_NONE);

virtual Intersect intersect(Ray r);
virtual Intersect intersectOOB(Ray r) { return this->intersect(r); };
Tuple normalAt(Tuple point);

/* Bouding box points are always world value */
/* Bounding box points are always world value */
virtual BoundingBox getBounds();
virtual bool haveFiniteBounds() { return true; };

void updateTransform();
Tuple worldToObject(Tuple point) { return this->inverseTransform * point; };
Expand Down
4 changes: 4 additions & 0 deletions source/include/tuple.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class Tuple
Tuple operator/(const double &b) const { return Tuple(this->x / b, this->y / b,
this->z / b, this->w / b); };

void fixPoint();
void fixVector();
bool isRepresentable();

void set(double nX, double nY, double nZ) { this->x = nX; this->y = nY; this->z = nZ; };
double magnitude();
Tuple normalise();
Expand Down
3 changes: 3 additions & 0 deletions source/math_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ double getEpsilon()

bool double_equal(double a, double b)
{
if (isinf(a) && isinf(b))
return true;

return fabs(a - b) < current_precision;
}

Expand Down
5 changes: 4 additions & 1 deletion source/shapes/cone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,13 @@ BoundingBox Cone::getBounds()

double a = fabs(this->minCap);
double b = fabs(this->maxCap);
double limit = (a < b)?a:b;
double limit = (a > b)?a:b;

ret.min = this->objectToWorld(Point(-limit, this->minCap, -limit));
ret.max = this->objectToWorld(Point(limit, this->maxCap, limit));

ret.min.fixPoint();
ret.max.fixPoint();

return ret;
}
3 changes: 3 additions & 0 deletions source/shapes/cylinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,8 @@ BoundingBox Cylinder::getBounds()
ret.min = this->objectToWorld(Point(-1, this->minCap, -1));
ret.max = this->objectToWorld(Point(1, this->maxCap, 1));

ret.min.fixPoint();
ret.max.fixPoint();

return ret;
}
89 changes: 64 additions & 25 deletions source/shapes/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ Group::Group() : Shape(SHAPE_GROUP)
this->allocatedObjectCount = MIN_ALLOC;
this->objectList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC);
this->objectCount = 0;

this->allocatedUnboxableObjectCount = MIN_ALLOC;
this->unboxableObjectList = (Shape **)calloc(sizeof(Shape *), MIN_ALLOC);
this->unboxableObjectCount = 0;

}

Intersect Group::intersect(Ray r)
Expand All @@ -27,9 +32,28 @@ Intersect Group::intersect(Ray r)
int i, j;
if (this->objectCount > 0)
{
for(i = 0; i < this->objectCount; i++)
if (this->bounds.intesectMe(r))
{
for (i = 0 ; i < this->objectCount ; i++)
{
Intersect xs = this->objectList[i]->intersect(r);
if (xs.count() > 0)
{
for (j = 0 ; j < xs.count() ; j++)
{
ret.add(xs[j]);
}
}
}
}
}

/* We are force to do them all the time */
if (this->unboxableObjectCount > 0)
{
for(i = 0; i < this->unboxableObjectCount; i++)
{
Intersect xs = this->objectList[i]->intersect(r);
Intersect xs = this->unboxableObjectList[i]->intersect(r);
if (xs.count() > 0)
{
for(j = 0; j < xs.count(); j++)
Expand All @@ -39,7 +63,6 @@ Intersect Group::intersect(Ray r)
}
}
}

return ret;
}

Expand All @@ -53,48 +76,64 @@ Tuple Group::localNormalAt(Tuple point)
return Vector(1, 0, 0);
}

/* ONLY INSERT SHAPES THAT ARE NOT GOING TO CHANGE ELSE..! */
void Group::addObject(Shape *s)
{
if ((this->objectCount + 1) > this->allocatedObjectCount)
if (s->haveFiniteBounds())
{
this->allocatedObjectCount *= 2;
this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount);
if ((this->objectCount + 1) > this->allocatedObjectCount)
{
this->allocatedObjectCount *= 2;
this->objectList = (Shape **)realloc(this->objectList, sizeof(Shape **) * this->allocatedObjectCount);
}

s->parent = this;
s->updateTransform();

this->objectList[this->objectCount++] = s;

this->bounds | s->getBounds();

}
else
{
if ((this->unboxableObjectCount + 1) > this->allocatedUnboxableObjectCount)
{
this->allocatedUnboxableObjectCount *= 2;
this->unboxableObjectList = (Shape **)realloc(this->unboxableObjectList, sizeof(Shape **) * this->allocatedUnboxableObjectCount);
}

s->parent = this;
s->updateTransform();
s->parent = this;
s->updateTransform();

this->objectList[this->objectCount++] = s;
this->unboxableObjectList[this->unboxableObjectCount++] = s;
}
}

bool Group::isEmpty()
{
return (this->objectCount == 0);
return (this->objectCount == 0) && (this->unboxableObjectCount == 0);
}

BoundingBox Group::getBounds()
{
BoundingBox ret;
if (this->bounds.isEmpty()) { this->updateBoundingBox(); }
return this->bounds;
}

void Group::updateBoundingBox()
{
this->bounds.reset();
if (this->objectCount > 0)
{
ret.min = Point(INFINITY, INFINITY, INFINITY);
ret.max = Point(-INFINITY, -INFINITY, -INFINITY);

int i;
for(i = 0; i < this->objectCount; i++)
{
BoundingBox obj = this->objectList[i]->getBounds();

if (ret.min.x > obj.min.x) { ret.min.x = obj.min.x; }
if (ret.min.y > obj.min.y) { ret.min.y = obj.min.y; }
if (ret.min.z > obj.min.z) { ret.min.z = obj.min.z; }

if (ret.max.x < obj.max.x) { ret.max.x = obj.max.x; }
if (ret.max.y < obj.max.y) { ret.max.y = obj.max.y; }
if (ret.max.z < obj.max.z) { ret.max.z = obj.max.z; }
if (!this->objectList[i]->haveFiniteBounds())
{
BoundingBox objB = this->objectList[i]->getBounds();
this->bounds | objB;
}
}
}

return ret;
}
3 changes: 3 additions & 0 deletions source/shapes/plane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@ BoundingBox Plane::getBounds()
ret.min = this->objectToWorld(Point(-INFINITY, 0-getEpsilon(), -INFINITY));
ret.max = this->objectToWorld(Point(INFINITY, 0+getEpsilon(), INFINITY));

ret.min.fixPoint();
ret.max.fixPoint();

return ret;
}
24 changes: 24 additions & 0 deletions source/tuple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,28 @@ Tuple Tuple::cross(const Tuple &b) const
Tuple Tuple::reflect(const Tuple &normal)
{
return *this - normal * 2 * this->dot(normal);
}

void Tuple::fixPoint()
{
if (isnan(this->x) || isnan(this->y) || isnan(this->z))
{
/* w is probably broken, so fix it */
this->w = 1;
}
}

void Tuple::fixVector()
{

if (isnan(this->x) || isnan(this->y) || isnan(this->z))
{
/* w is probably broken, so fix it */
this->w = 0;
}
}

bool Tuple::isRepresentable()
{
return !(isnan(this->x) || isnan(this->y) || isnan(this->z));
}
Loading

0 comments on commit 2ea4abd

Please sign in to comment.