Redo planes in normal-distance form
This is how POV-Ray does it. This is how The Book does it. I'm just going along for the ride… :) But seriously, it seems to make some things easier.
This commit is contained in:
parent
d44fa4dd2a
commit
6ddd47fe64
2 changed files with 101 additions and 85 deletions
|
@ -12,103 +12,102 @@
|
||||||
|
|
||||||
#include "basics.h"
|
#include "basics.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "object_plane.h"
|
#include "objectPlane.hh"
|
||||||
|
|
||||||
|
namespace charles {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Plane::Plane --
|
* charles::Plane::Plane --
|
||||||
*
|
|
||||||
* Default constructor. Create a Plane with a point at the origin and normal vector in the Y direction.
|
|
||||||
*/
|
*/
|
||||||
Plane::Plane()
|
Plane::Plane()
|
||||||
: Plane(Vector3::Y)
|
: mNormal(Vector3::Y),
|
||||||
|
mDistance(0.0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
|
||||||
/*
|
const Vector3&
|
||||||
* Plane::Plane --
|
Plane::GetNormal()
|
||||||
*
|
const
|
||||||
* Constructor. Create a Plane with a point at the origin, and a given normal.
|
{
|
||||||
*/
|
return mNormal;
|
||||||
Plane::Plane(Vector3 n)
|
}
|
||||||
: Plane(Vector3::Zero, n)
|
|
||||||
{ }
|
|
||||||
|
void
|
||||||
|
Plane::SetNormal(const Vector3& normal)
|
||||||
|
{
|
||||||
|
mNormal = normal.normalized();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Double
|
||||||
|
Plane::GetDistance()
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return mDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Plane::SetDistance(Double distance)
|
||||||
|
{
|
||||||
|
mDistance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Plane::Plane --
|
* charles::Plane::DoesIntersect --
|
||||||
*
|
|
||||||
* Constructor. Create a Plane with the given origin and normal vectors.
|
|
||||||
*/
|
*/
|
||||||
Plane::Plane(Vector3 o, Vector3 n)
|
bool
|
||||||
: Shape(o),
|
Plane::DoesIntersect(const Ray &ray,
|
||||||
normal(n.normalize())
|
TVector& t)
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Plane::does_intersect --
|
|
||||||
*
|
|
||||||
* Compute the intersection of a ray with this Plane. 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.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
Plane::does_intersect(const Ray &ray, float **t)
|
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The algebraic form of a plane is the following:
|
* Planes are defined in terms of [A B C D], where [A B C] make up the unit
|
||||||
|
* normal vector, and D is the distance from the origin. We can write the
|
||||||
|
* equation for a plane like this:
|
||||||
*
|
*
|
||||||
* (p - p0) . n = 0
|
* A * x + B * y + C * z + D = 0, where
|
||||||
|
* A^2 + B^2 + C^2 = 1.
|
||||||
|
*
|
||||||
|
* The sign of D determines which side of the origin the plane is on.
|
||||||
*
|
*
|
||||||
* where p is a point in the plane, p0 is another point in the plane (the origin point in our case), and n is the
|
* We can figure out the distance from the ray's origin to the intersection
|
||||||
* normal vector. (Periods [.] indicate dot products.) We can plug in the parametric equation for a Ray and solve
|
* point (there will be only one for planes) by substituting the ray's
|
||||||
* for t to get the intersection point.
|
* parameters into the above equation. In the equations below, RO is the
|
||||||
|
* ray's origin, RD is the ray's direction, and components thereof are
|
||||||
|
* indicated with lowercase letters (ROx is the x component of RO).
|
||||||
*
|
*
|
||||||
* ((ro + t*rd) - p0) . n = 0
|
* A(ROx + RDx * t) + B(ROy + RDy * t) + C(ROz + RDz * t) + D = 0
|
||||||
|
*
|
||||||
|
* We then solve for t.
|
||||||
*
|
*
|
||||||
* Simplifying, distributing, and solving for t:
|
* t = -(A * ROx + B * ROy + C * ROz + D) / (A * RDx + B * RDy + C * RDz)
|
||||||
*
|
*
|
||||||
* t = ((p0 - ro) . n) / (ld . n)
|
* In vector notation, this works out more cleanly.
|
||||||
*
|
*
|
||||||
* Note that if the denominator is 0, the ray runs parallel to the plane and there are no intersections. If both the
|
* t = -(n . RO + D) / (n . RD)
|
||||||
* numerator and denominator are 0, the ray is in the plane and intersects everywhere.
|
|
||||||
*
|
|
||||||
* See: http://en.wikipedia.org/wiki/Line-plane_intersection
|
|
||||||
*/
|
*/
|
||||||
Vector3 o = get_origin();
|
|
||||||
int nints = 1;
|
|
||||||
float numer = (o - ray.origin).dot(normal);
|
|
||||||
float denom = ray.direction.dot(normal);
|
|
||||||
|
|
||||||
if (denom == 0.0) {
|
/* The denominator for the t equation above. */
|
||||||
nints = 0;
|
Double ndotd = mNormal.dot(ray.direction);
|
||||||
if (numer == 0.0) {
|
if (ndotd == 0.0) {
|
||||||
// Ray is in plane.
|
/* The ray is parallel to the plane. */
|
||||||
nints = 1;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No intersections.
|
/* The numerator of the equation for t above. */
|
||||||
if (nints == 0) {
|
Double ndoto = -(mNormal.dot(ray.origin) + mDistance);
|
||||||
return nints;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: denom could still be 0 here!
|
Double t0 = ndoto / ndotd;
|
||||||
float t0 = numer / denom;
|
|
||||||
|
|
||||||
// If the t value is negative, it's "behind" the origin of the ray, which we don't care about.
|
|
||||||
if (t0 < 0.0) {
|
if (t0 < 0.0) {
|
||||||
return 0;
|
/* The plane is behind the ray's origin. */
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory, at most one float.
|
t.push_back(t0);
|
||||||
if (t != NULL) {
|
return true;
|
||||||
*t = new float(t0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return nints;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,19 +123,15 @@ Plane::point_is_on_surface(const Vector3 &p)
|
||||||
/*
|
/*
|
||||||
* Plug point p into the equation for a plane:
|
* Plug point p into the equation for a plane:
|
||||||
*
|
*
|
||||||
* a(x - ox) + b(y - oy) + c(z - oz) = 0
|
* A * x + B * y + C * z + D = 0
|
||||||
*
|
*
|
||||||
* where (a, b, c) are the coordinates of the normal vector, and (ox, oy, oz) are the coordinates of the origin
|
* where (A, B, C) are the coordinates of the normal vector, and D is the
|
||||||
* vector.
|
* distance along that vector from the origin.
|
||||||
*
|
|
||||||
* I found this page most helpful:
|
|
||||||
* http://www.math.oregonstate.edu/home/programs/undergrad/CalculusQuestStudyGuides/vcalc/lineplane/lineplane.html
|
|
||||||
*/
|
*/
|
||||||
Vector3 o = get_origin();
|
Double x = mNormal.x * p.x;
|
||||||
float x = normal.x * (p.x - o.x);
|
Double y = mNormal.y * p.y;
|
||||||
float y = normal.y * (p.y - o.y);
|
Double z = mNormal.z * p.z;
|
||||||
float z = normal.z * (p.z - o.z);
|
return (x + y + z + mDistance) == 0.0;
|
||||||
return (x + y + z) == 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,5 +150,7 @@ Plane::compute_normal(const Vector3 &p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This one's easy since planes are defined by their normals. :)
|
// This one's easy since planes are defined by their normals. :)
|
||||||
return normal;
|
return mNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} /* namespace charles */
|
||||||
|
|
|
@ -10,22 +10,41 @@
|
||||||
|
|
||||||
#include "basics.h"
|
#include "basics.h"
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
|
#include "types.hh"
|
||||||
|
|
||||||
|
namespace charles {
|
||||||
|
|
||||||
class Plane
|
class Plane
|
||||||
: public Shape
|
: public Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/** Default constructor. Creates a plane with a normal along the Y axis. */
|
||||||
Plane();
|
Plane();
|
||||||
Plane(Vector3 normal);
|
|
||||||
Plane(Vector3 o, Vector3 normal);
|
|
||||||
|
|
||||||
int does_intersect(const Ray &ray, float **t) const;
|
const Vector3& GetNormal() const;
|
||||||
|
void SetNormal(const Vector3& normal);
|
||||||
|
|
||||||
|
Double GetDistance() const;
|
||||||
|
void SetDistance(Double distance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see charles::Object::DoesIntersect
|
||||||
|
*/
|
||||||
|
bool DoesIntersect(const Ray &ray, TVector& t) const;
|
||||||
bool point_is_on_surface(const Vector3 &p) const;
|
bool point_is_on_surface(const Vector3 &p) const;
|
||||||
Vector3 compute_normal(const Vector3 &p) const;
|
Vector3 compute_normal(const Vector3 &p) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector3 normal;
|
/** A normal vector, which specified the orientation of the plane. */
|
||||||
|
Vector3 mNormal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distance from the origin along the normal vector that this plane is
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
Double mDistance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} /* namespace charles */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue