charles/src/object.cc

155 lines
3.7 KiB
C++
Raw Normal View History

2013-09-07 16:09:19 -07:00
/* object.c
*
* Definition of scene Objects.
*
* Eryn Wells <eryn@erynwells.me>
*/
#include <cassert>
#include <cmath>
#include <cstdlib>
2013-09-07 22:22:27 -07:00
2013-09-07 16:48:50 -07:00
#include "basics.h"
2013-09-07 16:09:19 -07:00
#include "object.h"
2013-09-07 18:26:32 -07:00
static int sphere_does_intersect(Object *obj, Ray ray, float **t);
static int sphere_point_lies_on_surface(Object *obj, Vector3 p);
static Vector3 sphere_compute_normal(Object *obj, Vector3 p);
2013-09-07 18:26:32 -07:00
2013-09-07 16:48:50 -07:00
/*
2013-09-10 09:18:05 -07:00
* Object::Object --
2013-09-07 16:48:50 -07:00
*
2013-09-10 09:18:05 -07:00
* Default constructor. Create a new Object with an origin at (0, 0, 0).
2013-09-07 16:48:50 -07:00
*/
2013-09-10 09:18:05 -07:00
Object::Object()
: origin()
{ }
2013-09-07 16:48:50 -07:00
/*
2013-09-10 09:18:05 -07:00
* Object::get_origin --
* Object::set_origin --
2013-09-07 16:48:50 -07:00
*
2013-09-10 09:18:05 -07:00
* Get and set the Object's origin.
2013-09-07 16:48:50 -07:00
*/
Vector3
2013-09-10 09:18:05 -07:00
Object::get_origin()
2013-09-07 22:22:27 -07:00
{
2013-09-10 09:18:05 -07:00
return origin;
2013-09-07 22:22:27 -07:00
}
void
2013-09-10 09:18:05 -07:00
Object::set_origin(Vector3 v)
2013-09-07 22:22:27 -07:00
{
2013-09-10 09:18:05 -07:00
origin = v;
2013-09-07 22:22:27 -07:00
}
2013-09-07 18:26:32 -07:00
/*
* Sphere::does_intersect --
2013-09-07 18:26:32 -07:00
*
* Compute the intersection of a ray with this Sphere. All intersection t values are returned in the **t argument. The
* number of values returned therein is indicated by the return value. Memory is allocated at *t. It is the caller's
* responsibility to free it when it is no longer needed. If 0 is returned, no memory needs to be freed.
2013-09-07 18:26:32 -07:00
*/
int
Sphere::does_intersect(const Ray &ray, float **t)
2013-09-07 18:26:32 -07:00
{
// Origin of the vector in object space.
Vector3 ray_origin_obj = ray.origin - get_origin();
2013-09-07 18:26:32 -07:00
// Coefficients for quadratic equation.
float a = ray.direction.dot(ray.direction);
float b = ray.direction.dot(ray_origin_obj) * 2.0;
float c = ray_origin_obj.dot(ray_origin_obj) - (radius * radius);
2013-09-07 18:26:32 -07:00
2013-09-08 18:28:53 -07:00
// Discriminant for the quadratic equation.
float discrim = (b * b) - (4.0 * a * c);
2013-09-07 18:26:32 -07:00
// If the discriminant is less than zero, there are no real (as in not imaginary) solutions to this intersection.
if (discrim < 0) {
return 0;
}
2013-09-08 18:28:53 -07:00
// Compute the intersections, the roots of the quadratic equation. Spheres have at most two intersections.
float sqrt_discrim = sqrtf(discrim);
float t0 = (-b - sqrt_discrim) / (2.0 * a);
float t1 = (-b + sqrt_discrim) / (2.0 * a);
2013-09-07 18:26:32 -07:00
// If t[1] is less than t[0], swap them (t[0] will always be the first intersection).
if (t1 < t0) {
float tmp = t0;
t0 = t1;
t1 = tmp;
}
/*
* If the farther intersection of the two is in the negative direction, the sphere is in the ray's negative
* direction.
*/
if (t1 < 0) {
return 0;
}
/*
* Allocate the memory and store the values. It's possible the two values are equal. Only allocate enough memory to
* store the required number of values.
*/
int nints = (t0 != t1) ? 2 : 1;
if (t != NULL) {
*t = malloc(sizeof(float) * nints);
if (*t == NULL) {
return 0;
}
(*t)[0] = t0;
if (nints > 1) {
(*t)[1] = t1;
}
2013-09-07 18:26:32 -07:00
}
return nints;
}
/*
* sphere_point_lies_on_surface --
*
* Determine if a point lies on the given sphere.
*/
int
sphere_point_lies_on_surface(Object *obj, Vector3 p)
{
assert(obj != NULL && obj->type == ObjectTypeSphere);
Vector3 loc = object_get_location(obj);
float x = p.x - loc.x;
float y = p.y - loc.y;
float z = p.z - loc.z;
float r = object_sphere_get_radius(obj);
return (x * x) + (y * y) + (z * z) == (r * r);
}
/*
* sphere_compute_normal --
*
* Compute the normal for the given Object (which must be a Sphere) at the given point. This point must lie on the
* surface of the object.
*/
/* static */ Vector3
sphere_compute_normal(Object *obj, Vector3 p)
{
assert(obj != NULL && obj->type == ObjectTypeSphere);
// Make sure the given point is actually on the surface of the sphere.
if (!sphere_point_lies_on_surface(obj, p)) {
return Vector3Zero;
}
// The fun thing about sphere is the normal to any point on the sphere is the point itself. Woo!
return p;
}