package org.sunflow.core;
import org.sunflow.math.Matrix4;
import org.sunflow.math.Point3;
import org.sunflow.math.Vector3;
/**
* This class represents a ray as a oriented half line segment. The ray
* direction is always normalized. The valid region is delimted by two distances
* along the ray, tMin and tMax.
*/
public final class Ray {
public float ox, oy, oz;
public float dx, dy, dz;
private float tMin;
private float tMax;
private static final float EPSILON = 0;// 0.01f;
private Ray() {
}
/**
* Creates a new ray that points from the given origin to the given
* direction. The ray has infinite length. The direction vector is
* normalized.
*
* @param ox ray origin x
* @param oy ray origin y
* @param oz ray origin z
* @param dx ray direction x
* @param dy ray direction y
* @param dz ray direction z
*/
public Ray(float ox, float oy, float oz, float dx, float dy, float dz) {
this.ox = ox;
this.oy = oy;
this.oz = oz;
this.dx = dx;
this.dy = dy;
this.dz = dz;
float in = 1.0f / (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
this.dx *= in;
this.dy *= in;
this.dz *= in;
tMin = EPSILON;
tMax = Float.POSITIVE_INFINITY;
}
/**
* Creates a new ray that points from the given origin to the given
* direction. The ray has infinite length. The direction vector is
* normalized.
*
* @param o ray origin
* @param d ray direction (need not be normalized)
*/
public Ray(Point3 o, Vector3 d) {
ox = o.x;
oy = o.y;
oz = o.z;
dx = d.x;
dy = d.y;
dz = d.z;
float in = 1.0f / (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
dx *= in;
dy *= in;
dz *= in;
tMin = EPSILON;
tMax = Float.POSITIVE_INFINITY;
}
/**
* Creates a new ray that points from point a to point b. The created ray
* will set tMin and tMax to limit the ray to the segment (a,b)
* (non-inclusive of a and b). This is often used to create shadow rays.
*
* @param a start point
* @param b end point
*/
public Ray(Point3 a, Point3 b) {
ox = a.x;
oy = a.y;
oz = a.z;
dx = b.x - ox;
dy = b.y - oy;
dz = b.z - oz;
tMin = EPSILON;
float n = (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
float in = 1.0f / n;
dx *= in;
dy *= in;
dz *= in;
tMax = n - EPSILON;
}
/**
* Create a new ray by transforming the supplied one by the given matrix. If
* the matrix is
* null
, the original ray is returned.
*
* @param m matrix to transform the ray by
*/
public Ray transform(Matrix4 m) {
if (m == null) {
return this;
}
Ray r = new Ray();
r.ox = m.transformPX(ox, oy, oz);
r.oy = m.transformPY(ox, oy, oz);
r.oz = m.transformPZ(ox, oy, oz);
r.dx = m.transformVX(dx, dy, dz);
r.dy = m.transformVY(dx, dy, dz);
r.dz = m.transformVZ(dx, dy, dz);
r.tMin = tMin;
r.tMax = tMax;
return r;
}
/**
* Normalize the direction component of the ray.
*/
public void normalize() {
float in = 1.0f / (float) Math.sqrt(dx * dx + dy * dy + dz * dz);
dx *= in;
dy *= in;
dz *= in;
}
/**
* Gets the minimum distance along the ray - usually 0.
*
* @return value of the smallest distance along the ray
*/
public final float getMin() {
return tMin;
}
/**
* Gets the maximum distance along the ray. May be infinite.
*
* @return value of the largest distance along the ray
*/
public final float getMax() {
return tMax;
}
/**
* Creates a vector to represent the direction of the ray.
*
* @return a vector equal to the direction of this ray
*/
public final Vector3 getDirection() {
return new Vector3(dx, dy, dz);
}
/**
* Checks to see if the specified distance falls within the valid range on
* this ray. This should always be used before an intersection with the ray
* is detected.
*
* @param t distance to be tested
* @return true
if t falls between the minimum and maximum
* distance of this ray, false
otherwise
*/
public final boolean isInside(float t) {
return (tMin < t) && (t < tMax);
}
/**
* Gets the end point of the ray. A reference to
* dest
is returned to support chaining.
*
* @param dest reference to the point to store
* @return reference to dest
*/
public final Point3 getPoint(Point3 dest) {
dest.x = ox + (tMax * dx);
dest.y = oy + (tMax * dy);
dest.z = oz + (tMax * dz);
return dest;
}
/**
* Computes the dot product of an arbitrary vector with the direction of the
* ray. This method avoids having to call getDirection() which would
* instantiate a new Vector object.
*
* @param v vector
* @return dot product of the ray direction and the specified vector
*/
public final float dot(Vector3 v) {
return dx * v.x + dy * v.y + dz * v.z;
}
/**
* Computes the dot product of an arbitrary vector with the direction of the
* ray. This method avoids having to call getDirection() which would
* instantiate a new Vector object.
*
* @param vx vector x coordinate
* @param vy vector y coordinate
* @param vz vector z coordinate
* @return dot product of the ray direction and the specified vector
*/
public final float dot(float vx, float vy, float vz) {
return dx * vx + dy * vy + dz * vz;
}
/**
* Updates the maximum to the specified distance if and only if the new
* distance is smaller than the current one.
*
* @param t new maximum distance
*/
public final void setMax(float t) {
tMax = t;
}
}