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
===============
- Fix subtractions of subtractions (inverting normals problem)
- Shape definitions / reusability
- Add distribution infrastructure
- Add maximum recursion depth option / parameter

View File

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

View File

@ -3,7 +3,7 @@ scene
{
options
{
multisample 2
multisample 3
}
camera
@ -17,6 +17,15 @@ scene
position <-1, -3, 4>
}
plane
{
position <0, 0, 1>, 1
material
{
color <0, 1, 1>
}
}
subtract
{
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 == 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,
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;
}
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:
Box(refptr<Vector> size);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected:
Vector m_size;

View File

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

View File

@ -9,7 +9,6 @@ class Cyl : public Shape
public:
Cyl(double bottom_radius, double top_radius, double height);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected:
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++)
{
Vector normal = merged[i].intersection.shape->getNormalAt(
merged[i].intersection.vector);
Vector normal = merged[i].intersection.normal;
double dot = - (ray.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
@ -56,11 +55,3 @@ Shape::IntersectionList Intersect::intersect(refptr<Shape> _this, const Ray & ra
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:
Intersect(refptr<Shape> shape1, refptr<Shape> shape2);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected:
refptr<Shape> m_shape1;

View File

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

View File

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

View File

@ -18,13 +18,17 @@ class Shape
{
public:
Intersection() {};
Intersection(refptr<Shape> shape, const Vector & vector)
Intersection(refptr<Shape> shape,
const Vector & position,
const Vector & normal)
{
this->shape = shape;
this->vector = vector;
this->position = position;
this->normal = normal;
}
refptr<Shape> shape;
Vector vector;
Vector position;
Vector normal;
};
class BoolIntersection
{
@ -97,7 +101,6 @@ class Shape
virtual ~Shape();
virtual IntersectionList intersect(refptr<Shape> _this,
const Ray & ray) = 0;
virtual Vector getNormalAt(const Vector & pt) = 0;
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)
{
Vector isect_point = ray_inv[quadSolutions.results[i]];
Vector normal = isect_point;
normal.normalize();
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;
}
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:
Sphere(double radius);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected:
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++)
{
Vector normal = merged[i].intersection.shape->getNormalAt(
merged[i].intersection.vector);
Vector normal = merged[i].intersection.normal;
double dot = - (ray.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
@ -32,25 +31,27 @@ Shape::IntersectionList Subtract::intersect(refptr<Shape> _this, const Ray & ray
in2 = front;
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;
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))
{
/* we found an intersection point with the boolean object */
res.add( merged[i].intersection );
/* we found an intersection point
* 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;
}
}
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:
Subtract(refptr<Shape> shape1, refptr<Shape> shape2);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected:
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++)
{
Vector normal = merged[i].intersection.shape->getNormalAt(
merged[i].intersection.vector);
Vector normal = merged[i].intersection.normal;
double dot = - (ray.getDirection() % normal);
bool front = dot > 0.0;
bool left = merged[i].left;
@ -56,11 +55,3 @@ Shape::IntersectionList Union::intersect(refptr<Shape> _this, const Ray & ray)
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:
Union(refptr<Shape> shape1, refptr<Shape> shape2);
IntersectionList intersect(refptr<Shape> _this, const Ray & ray);
Vector getNormalAt(const Vector & pt);
protected:
refptr<Shape> m_shape1;