merged in branches/2009-03-09_intersect_returning_normals

git-svn-id: svn://anubis/fart/trunk@202 7f9b0f55-74a9-4bce-be96-3c2cd072584d
This commit is contained in:
Josh Holtrop 2009-03-09 23:24:01 +00:00
commit 4716b200fd
20 changed files with 110 additions and 173 deletions

1
.todo
View File

@ -1,6 +1,5 @@
FART To-Do List FART To-Do List
=============== ===============
- Fix subtractions of subtractions (inverting normals problem)
- Shape definitions / reusability - Shape definitions / reusability
- Add distribution infrastructure - Add distribution infrastructure
- Add maximum recursion depth option / parameter - Add maximum recursion depth option / parameter

View File

@ -148,27 +148,27 @@ Color Scene::traceRayRecurse(const Ray & ray, int depth, double factor)
{ {
Color color; Color color;
ShapeDistance hit = getRayClosestHit(ray); Shape::Intersection hit = getRayClosestHit(ray);
if ( ! hit.shape.isNull() ) if ( ! hit.shape.isNull() )
{ {
/* compute the Phong lighting for each hit */ /* compute the Phong lighting for each hit */
refptr<Material> material = hit.shape->getMaterial(); refptr<Material> material = hit.shape->getMaterial();
Vector surfacePoint = ray[hit.dist]; /* TODO: make sure this can be removed */
Vector surfaceNormal = hit.shape->getNormalAt(surfacePoint); #if 0
/* check for backfaces */ /* check for backfaces */
if (ray.getDirection() % surfaceNormal > 0.0) if (ray.getDirection() % surfaceNormal > 0.0)
{ {
/* if dot product is positive, this is a back-face */ /* if dot product is positive, this is a back-face */
surfaceNormal = -surfaceNormal; surfaceNormal = -surfaceNormal;
} }
#endif
color = computePhong(material, color = computePhong(material,
ray, ray,
surfacePoint, hit.position,
surfaceNormal); hit.normal);
if (depth > 0 && factor > SCENE_FACTOR_THRESHOLD) if (depth > 0 && factor > SCENE_FACTOR_THRESHOLD)
{ {
@ -177,8 +177,8 @@ Color Scene::traceRayRecurse(const Ray & ray, int depth, double factor)
{ {
color *= (1.0 - reflectance); color *= (1.0 - reflectance);
Vector reflected_direction = Vector reflected_direction =
(-ray.getDirection()).reflect(surfaceNormal); (-ray.getDirection()).reflect(hit.normal);
Ray newRay(surfacePoint, reflected_direction); Ray newRay(hit.position, reflected_direction);
Vector jitter_surface_point = newRay[0.0001]; Vector jitter_surface_point = newRay[0.0001];
Ray jitterNewRay(jitter_surface_point, reflected_direction); Ray jitterNewRay(jitter_surface_point, reflected_direction);
Color c = traceRayRecurse(jitterNewRay, Color c = traceRayRecurse(jitterNewRay,
@ -191,7 +191,8 @@ Color Scene::traceRayRecurse(const Ray & ray, int depth, double factor)
if (factor * transparency > SCENE_FACTOR_THRESHOLD) if (factor * transparency > SCENE_FACTOR_THRESHOLD)
{ {
color *= (1.0 - transparency); color *= (1.0 - transparency);
Vector jitter_surface_point = ray[hit.dist + 0.0001]; Vector jitter_surface_point = hit.position
+ ray.getDirection() * 0.0001;
Ray newRay(jitter_surface_point, ray.getDirection()); Ray newRay(jitter_surface_point, ray.getDirection());
Color c = traceRayRecurse(newRay, Color c = traceRayRecurse(newRay,
depth - 1, depth - 1,
@ -204,9 +205,10 @@ Color Scene::traceRayRecurse(const Ray & ray, int depth, double factor)
return color; return color;
} }
Scene::ShapeDistance Scene::getRayClosestHit(const Ray & ray) Shape::Intersection Scene::getRayClosestHit(const Ray & ray)
{ {
ShapeDistance hit; Shape::Intersection hit;
double min_dist = 0.0;
bool foundOne = false; bool foundOne = false;
/* loop through all shapes in the scene */ /* loop through all shapes in the scene */
@ -221,12 +223,12 @@ Scene::ShapeDistance Scene::getRayClosestHit(const Ray & ray)
i++) i++)
{ {
refptr<Shape> shape = intersections[i].shape; refptr<Shape> shape = intersections[i].shape;
const Vector & isect_point = intersections[i].vector; const Vector & isect_point = intersections[i].position;
double intersect_dist = (isect_point - ray.getOrigin()).mag(); double intersect_dist = ray.getOrigin().dist_to(isect_point);
if (foundOne == false || intersect_dist < hit.dist) if (foundOne == false || intersect_dist < min_dist)
{ {
hit.shape = shape; hit = intersections[i];
hit.dist = intersect_dist; min_dist = intersect_dist;
foundOne = true; foundOne = true;
} }
} }
@ -306,12 +308,12 @@ double Scene::calculateLightContribution(const Ray & toLight,
for (;;) for (;;)
{ {
ShapeDistance hit = getRayClosestHit(currentRay); Shape::Intersection hit = getRayClosestHit(currentRay);
if ( hit.shape.isNull() ) if ( hit.shape.isNull() )
break; break;
double offset = hit.dist + 0.0001; double offset = currentRay.getOrigin().dist_to(hit.position) + 0.0001;
if ( dist_so_far + offset > dist_to_light ) if ( dist_so_far + offset > dist_to_light )
break; break;
@ -327,9 +329,3 @@ double Scene::calculateLightContribution(const Ray & toLight,
return contrib; return contrib;
} }
bool operator<(const Scene::ShapeDistance & sd1,
const Scene::ShapeDistance & sd2)
{
return sd1.dist < sd2.dist;
}

View File

@ -22,20 +22,6 @@
class Scene class Scene
{ {
public: public:
/* types */
class ShapeDistance
{
public:
ShapeDistance() {}
ShapeDistance(refptr<Shape> shape, double dist)
{
this->shape = shape;
this->dist = dist;
}
refptr<Shape> shape;
double dist;
};
Scene(const std::map<std::string, const char *> & options, Scene(const std::map<std::string, const char *> & options,
const char * filename); const char * filename);
~Scene(); ~Scene();
@ -51,7 +37,7 @@ class Scene
void renderPixel(int x, int y, unsigned char * pixel); void renderPixel(int x, int y, unsigned char * pixel);
Color traceRay(const Ray & ray); Color traceRay(const Ray & ray);
Color traceRayRecurse(const Ray & ray, int depth, double factor); Color traceRayRecurse(const Ray & ray, int depth, double factor);
ShapeDistance getRayClosestHit(const Ray & ray); Shape::Intersection getRayClosestHit(const Ray & ray);
Color computePhong(const refptr<Material> material, Color computePhong(const refptr<Material> material,
const Ray & viewRay, const Ray & viewRay,
const Vector & surfacePoint, const Vector & surfacePoint,
@ -102,8 +88,5 @@ class Scene
unsigned char * m_data; unsigned char * m_data;
}; };
bool operator<(const Scene::ShapeDistance & sd1,
const Scene::ShapeDistance & sd2);
#endif #endif

View File

@ -3,7 +3,7 @@ scene
{ {
options options
{ {
multisample 2 multisample 3
} }
camera camera
@ -17,6 +17,15 @@ scene
position <-1, -3, 4> position <-1, -3, 4>
} }
plane
{
position <0, 0, 1>, 1
material
{
color <0, 1, 1>
}
}
subtract subtract
{ {
box box

View File

@ -45,8 +45,22 @@ Shape::IntersectionList Box::intersect(refptr<Shape> _this, const Ray & ray)
&& (dim == 1 || fabs(isect_point[1]) <= m_size[1]) && (dim == 1 || fabs(isect_point[1]) <= m_size[1])
&& (dim == 2 || fabs(isect_point[2]) <= m_size[2]) ) && (dim == 2 || fabs(isect_point[2]) <= m_size[2]) )
{ {
Vector normal(0, 0, -1);
if ( FP_EQUAL(isect_point[0], m_size[0]) )
normal = Vector(1, 0, 0);
else if ( FP_EQUAL(isect_point[0], -m_size[0]) )
normal = Vector(-1, 0, 0);
else if ( FP_EQUAL(isect_point[1], m_size[1]) )
normal = Vector(0, 1, 0);
else if ( FP_EQUAL(isect_point[1], -m_size[1]) )
normal = Vector(0, -1, 0);
else if ( FP_EQUAL(isect_point[2], m_size[2]) )
normal = Vector(0, 0, 1);
res.add(Intersection(_this, res.add(Intersection(_this,
m_transform.transform_point(isect_point)) m_transform.transform_point(isect_point),
m_transform.transform_normal(normal))
); );
} }
} }
@ -56,23 +70,3 @@ Shape::IntersectionList Box::intersect(refptr<Shape> _this, const Ray & ray)
return res; return res;
} }
Vector Box::getNormalAt(const Vector & pt)
{
Vector local_pt = m_inverse.transform_point(pt);
Vector normal(0, 0, -1);
if ( FP_EQUAL(local_pt[0], m_size[0]) )
normal = Vector(1, 0, 0);
else if ( FP_EQUAL(local_pt[0], -m_size[0]) )
normal = Vector(-1, 0, 0);
else if ( FP_EQUAL(local_pt[1], m_size[1]) )
normal = Vector(0, 1, 0);
else if ( FP_EQUAL(local_pt[1], -m_size[1]) )
normal = Vector(0, -1, 0);
else if ( FP_EQUAL(local_pt[2], m_size[2]) )
normal = Vector(0, 0, 1);
return m_transform.transform_normal(normal);
}

View File

@ -9,7 +9,6 @@ class Box : public Shape
public: public:
Box(refptr<Vector> size); Box(refptr<Vector> size);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
Vector m_size; Vector m_size;

View File

@ -39,7 +39,8 @@ Shape::IntersectionList Cyl::intersect(refptr<Shape> _this, const Ray & ray)
<= m_bottom_radius_2) <= m_bottom_radius_2)
{ {
res.add(Intersection(_this, res.add(Intersection(_this,
m_transform.transform_point(isect_point))); m_transform.transform_point(isect_point),
m_transform.transform_normal(Vector(0, 0, -1))));
} }
} }
} }
@ -57,7 +58,8 @@ Shape::IntersectionList Cyl::intersect(refptr<Shape> _this, const Ray & ray)
<= m_top_radius_2) <= m_top_radius_2)
{ {
res.add(Intersection(_this, res.add(Intersection(_this,
m_transform.transform_point(isect_point))); m_transform.transform_point(isect_point),
m_transform.transform_normal(Vector(0, 0, 1))));
} }
} }
} }
@ -101,41 +103,18 @@ Shape::IntersectionList Cyl::intersect(refptr<Shape> _this, const Ray & ray)
Vector isect_point = ray_inv[solutions.results[i]]; Vector isect_point = ray_inv[solutions.results[i]];
if (isect_point[2] > 0.0 && isect_point[2] < m_height) if (isect_point[2] > 0.0 && isect_point[2] < m_height)
{ {
res.add(Intersection(_this,
m_transform.transform_point(isect_point)));
}
}
}
return res;
}
Vector Cyl::getNormalAt(const Vector & pt)
{
Vector local_pt = m_inverse.transform_point(pt);
Vector normal; Vector normal;
if ( FP_EQUAL(local_pt[2], 0.0) && m_bottom_radius > 0.0 )
{
normal = Vector(0, 0, -1);
}
else if ( FP_EQUAL(local_pt[2], m_height) && m_top_radius > 0.0 )
{
normal = Vector(0, 0, 1);
}
else
{
if ( FP_EQUAL(m_slope, 0.0) ) if ( FP_EQUAL(m_slope, 0.0) )
{ {
normal = Vector(local_pt[0], local_pt[1], 0.0); normal = Vector(isect_point[0], isect_point[1], 0.0);
} }
else else
{ {
double x = local_pt[0]; double x = isect_point[0];
double y = local_pt[1]; double y = isect_point[1];
double dist = sqrt( local_pt[0] * local_pt[0] double dist = sqrt( isect_point[0] * isect_point[0]
+ local_pt[1] * local_pt[1] ); + isect_point[1] * isect_point[1] );
if (dist > 0.0) if (dist > 0.0)
{ {
double scale = 1.0 / dist; double scale = 1.0 / dist;
@ -145,7 +124,13 @@ Vector Cyl::getNormalAt(const Vector & pt)
normal = Vector(x, y, m_inv_slope); normal = Vector(x, y, m_inv_slope);
} }
normal.normalize(); normal.normalize();
res.add(Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal)));
}
}
} }
return m_transform.transform_normal(normal); return res;
} }

View File

@ -9,7 +9,6 @@ class Cyl : public Shape
public: public:
Cyl(double bottom_radius, double top_radius, double height); Cyl(double bottom_radius, double top_radius, double height);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
double m_bottom_radius; double m_bottom_radius;

View File

@ -21,8 +21,7 @@ Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ra
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.shape->getNormalAt( Vector normal = merged[i].intersection.normal;
merged[i].intersection.vector);
double dot = - (ray.getDirection() % normal); double dot = - (ray.getDirection() % normal);
bool front = dot > 0.0; bool front = dot > 0.0;
bool left = merged[i].left; bool left = merged[i].left;
@ -56,11 +55,3 @@ Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ra
return res; return res;
} }
Vector Intersect::getNormalAt(const Vector & pt)
{
/* this should not be called */
cerr << __FILE__ << ": " << __LINE__ <<
": error: Intersect::getNormalAt() was called!" << endl;
return Vector(0, 0, 0);
}

View File

@ -9,7 +9,6 @@ class Intersect : public Shape
public: public:
Intersect(refptr<Shape> shape1, refptr<Shape> shape2); Intersect(refptr<Shape> shape1, refptr<Shape> shape2);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
refptr<Shape> m_shape1; refptr<Shape> m_shape1;

View File

@ -11,6 +11,8 @@ Plane::Plane(double a, double b, double c, double d)
m_b = b; m_b = b;
m_c = c; m_c = c;
m_d = d; m_d = d;
m_normal = Vector(m_a, m_b, m_c);
m_normal.normalize();
} }
Shape::IntersectionList Plane::intersect(refptr<Shape> _this, const Ray & ray) Shape::IntersectionList Plane::intersect(refptr<Shape> _this, const Ray & ray)
@ -42,15 +44,9 @@ Shape::IntersectionList Plane::intersect(refptr<Shape> _this, const Ray & ray)
{ {
Vector isect_point = ray_inv[solutions.results[0]]; Vector isect_point = ray_inv[solutions.results[0]];
res.add(Intersection(_this, res.add(Intersection(_this,
m_transform.transform_point(isect_point))); m_transform.transform_point(isect_point),
m_transform.transform_normal(m_normal)));
} }
} }
return res; return res;
} }
Vector Plane::getNormalAt(const Vector & pt)
{
Vector normal(m_a, m_b, m_c);
normal.normalize();
return m_transform.transform_normal(normal);
}

View File

@ -9,10 +9,10 @@ class Plane : public Shape
public: public:
Plane(double a, double b, double c, double d); Plane(double a, double b, double c, double d);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
double m_a, m_b, m_c, m_d; double m_a, m_b, m_c, m_d;
Vector m_normal;
}; };
#endif #endif

View File

@ -35,8 +35,8 @@ class BoolIntersectionComparator
bool operator()(const Shape::BoolIntersection & i1, bool operator()(const Shape::BoolIntersection & i1,
const Shape::BoolIntersection & i2) const const Shape::BoolIntersection & i2) const
{ {
return (m_refPoint.dist_to(i1.intersection.vector) return ( m_refPoint.dist_to(i1.intersection.position)
< m_refPoint.dist_to(i2.intersection.vector)); < m_refPoint.dist_to(i2.intersection.position) );
} }
protected: protected:
Vector m_refPoint; Vector m_refPoint;

View File

@ -18,13 +18,17 @@ class Shape
{ {
public: public:
Intersection() {}; Intersection() {};
Intersection(refptr<Shape> shape, const Vector & vector) Intersection(refptr<Shape> shape,
const Vector & position,
const Vector & normal)
{ {
this->shape = shape; this->shape = shape;
this->vector = vector; this->position = position;
this->normal = normal;
} }
refptr<Shape> shape; refptr<Shape> shape;
Vector vector; Vector position;
Vector normal;
}; };
class BoolIntersection class BoolIntersection
{ {
@ -97,7 +101,6 @@ class Shape
virtual ~Shape(); virtual ~Shape();
virtual IntersectionList intersect(refptr<Shape> _this, virtual IntersectionList intersect(refptr<Shape> _this,
const Ray & ray) = 0; const Ray & ray) = 0;
virtual Vector getNormalAt(const Vector & pt) = 0;
void setTransform(Transform & t) void setTransform(Transform & t)
{ {

View File

@ -30,19 +30,14 @@ Shape::IntersectionList Sphere::intersect(refptr<Shape> _this, const Ray & ray)
if (quadSolutions.results[i] >= 0.0) if (quadSolutions.results[i] >= 0.0)
{ {
Vector isect_point = ray_inv[quadSolutions.results[i]]; Vector isect_point = ray_inv[quadSolutions.results[i]];
Vector normal = isect_point;
normal.normalize();
res.add( res.add(
Intersection(_this, m_transform.transform_point(isect_point)) Intersection(_this,
m_transform.transform_point(isect_point),
m_transform.transform_normal(normal))
); );
} }
} }
return res; return res;
} }
Vector Sphere::getNormalAt(const Vector & pt)
{
Vector normal = m_inverse.transform_point(pt);
normal.normalize();
return m_transform.transform_normal(normal);
}

View File

@ -9,7 +9,6 @@ class Sphere : public Shape
public: public:
Sphere(double radius); Sphere(double radius);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
double m_radius; double m_radius;

View File

@ -21,8 +21,7 @@ Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray
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.shape->getNormalAt( Vector normal = merged[i].intersection.normal;
merged[i].intersection.vector);
double dot = - (ray.getDirection() % normal); double dot = - (ray.getDirection() % normal);
bool front = dot > 0.0; bool front = dot > 0.0;
bool left = merged[i].left; bool left = merged[i].left;
@ -32,25 +31,27 @@ Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray
in2 = front; in2 = front;
if (!in_bool && in1 && !in2) if (!in_bool && in1 && !in2)
{ {
/* we found an intersection point with the boolean object */ /* we found an intersection point
* to get into the boolean object */
in_bool = true; in_bool = true;
res.add( merged[i].intersection ); BoolIntersection bi = merged[i];
Intersection i = bi.intersection;
if ( ! left ) /* if this point came from object B (A - B) */
i.normal = - i.normal;
res.add(i);
} }
else if (in_bool && !(in1 && !in2)) else if (in_bool && !(in1 && !in2))
{ {
/* we found an intersection point with the boolean object */ /* we found an intersection point
res.add( merged[i].intersection ); * to get out of the boolean object */
BoolIntersection bi = merged[i];
Intersection i = bi.intersection;
if ( ! left ) /* if this point came from object B (A - B) */
i.normal = - i.normal;
res.add(i);
in_bool = false; in_bool = false;
} }
} }
return res; return res;
} }
Vector Subtract::getNormalAt(const Vector & pt)
{
/* this should not be called */
cerr << __FILE__ << ": " << __LINE__ <<
": error: Subtract::getNormalAt() was called!" << endl;
return Vector(0, 0, 0);
}

View File

@ -9,7 +9,6 @@ class Subtract : public Shape
public: public:
Subtract(refptr<Shape> shape1, refptr<Shape> shape2); Subtract(refptr<Shape> shape1, refptr<Shape> shape2);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
refptr<Shape> m_shape1; refptr<Shape> m_shape1;

View File

@ -21,8 +21,7 @@ Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
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.shape->getNormalAt( Vector normal = merged[i].intersection.normal;
merged[i].intersection.vector);
double dot = - (ray.getDirection() % normal); double dot = - (ray.getDirection() % normal);
bool front = dot > 0.0; bool front = dot > 0.0;
bool left = merged[i].left; bool left = merged[i].left;
@ -56,11 +55,3 @@ Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
return res; return res;
} }
Vector Union::getNormalAt(const Vector & pt)
{
/* this should not be called */
cerr << __FILE__ << ": " << __LINE__ <<
": error: Union::getNormalAt() was called!" << endl;
return Vector(0, 0, 0);
}

View File

@ -9,7 +9,6 @@ class Union : public Shape
public: public:
Union(refptr<Shape> shape1, refptr<Shape> shape2); Union(refptr<Shape> shape1, refptr<Shape> shape2);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray); IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected: protected:
refptr<Shape> m_shape1; refptr<Shape> m_shape1;