add documentation
This commit is contained in:
parent
dbd3d5fc4b
commit
9e79333e1e
@ -35,26 +35,49 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
||||
return Optional.ofNullable(bbox);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the range of x values}
|
||||
*/
|
||||
public @NotNull Range x() {
|
||||
return new Range(min.x(), max.x());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the range of y values}
|
||||
*/
|
||||
public @NotNull Range y() {
|
||||
return new Range(min.y(), max.y());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the range of z values}
|
||||
*/
|
||||
public @NotNull Range z() {
|
||||
return new Range(min.z(), max.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the center of this bounding box}
|
||||
*/
|
||||
public @NotNull Vec3 center() {
|
||||
return Vec3.average(min, max, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands this bounding box to include the other bounding box.
|
||||
* @param box a bounding box
|
||||
* @return the expanded bounding box
|
||||
*/
|
||||
public @NotNull AABB expand(@NotNull AABB box) {
|
||||
return new AABB(Vec3.min(this.min, box.min), Vec3.max(this.max, box.max));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the {@code ray} intersects this bounding box withing the {@code range}
|
||||
* @param ray a ray
|
||||
* @param range a range of valid {@code t}s
|
||||
* @return {@code true} iff the ray intersects this bounding box, {@code false} otherwise
|
||||
*/
|
||||
public boolean hit(@NotNull Ray ray, @NotNull Range range) {
|
||||
var origin = ray.origin();
|
||||
var direction = ray.direction();
|
||||
@ -85,6 +108,13 @@ public record AABB(@NotNull Vec3 min, @NotNull Vec3 max) {
|
||||
return tlmax < tumin && tumin >= range.min() && tlmax <= range.max();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the {@code t} values of the intersections of a ray with the axis-aligned planes through a point.
|
||||
* @param corner the point
|
||||
* @param origin the origin point of the ray
|
||||
* @param invDirection the {@linkplain Vec3#inv() inverted} direction of the ray
|
||||
* @return a three-element array of the {@code t} values of the intersection with the yz-, xz- and xy-plane through {@code corner}
|
||||
*/
|
||||
public static double @NotNull[] intersect(@NotNull Vec3 corner, @NotNull Vec3 origin, @NotNull Vec3 invDirection) {
|
||||
return new double[] {
|
||||
(corner.x() - origin.x()) * invDirection.x(),
|
||||
|
@ -13,10 +13,4 @@ public record Ray(@NotNull Vec3 origin, @NotNull Vec3 direction) {
|
||||
public @NotNull Vec3 at(double t) {
|
||||
return Vec3.fma(t, direction, origin);
|
||||
}
|
||||
|
||||
public int vmask() {
|
||||
return (direction().x() < 0 ? 1 : 0)
|
||||
| (direction().y() < 0 ? 2 : 0)
|
||||
| (direction().z() < 0 ? 4 : 0);
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ public record Vec3(double x, double y, double z) {
|
||||
return new Vec3(x * factor, y * factor, z * factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a uniformly random unit vector on the opposite hemisphere of the given <code>direction</code>}
|
||||
*/
|
||||
public static @NotNull Vec3 randomOppositeHemisphere(@NotNull RandomGenerator random, @NotNull Vec3 direction) {
|
||||
double x, y, z;
|
||||
double squared;
|
||||
@ -52,11 +55,24 @@ public record Vec3(double x, double y, double z) {
|
||||
return new Vec3(x * factor, y * factor, z * factor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflects a vector on the given {@code normal} vector.
|
||||
* @param vec a vector
|
||||
* @param normal the surface normal (must be a unit vector)
|
||||
* @return the reflected vector
|
||||
*/
|
||||
public static @NotNull Vec3 reflect(@NotNull Vec3 vec, @NotNull Vec3 normal) {
|
||||
var factor = - 2 * normal.times(vec);
|
||||
return Vec3.fma(factor, normal, vec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refracts a vector on the given {@code normal} vector.
|
||||
* @param vec a vector
|
||||
* @param normal the surface normal (must be a unit vector)
|
||||
* @param ri the refractive index
|
||||
* @return the refracted vector
|
||||
*/
|
||||
public static @NotNull Optional<Vec3> refract(@NotNull Vec3 vec, @NotNull Vec3 normal, double ri) {
|
||||
vec = vec.unit();
|
||||
var cosTheta = Math.min(- vec.times(normal), 1.0);
|
||||
@ -68,16 +84,35 @@ public record Vec3(double x, double y, double z) {
|
||||
return Optional.of(rOutPerp.plus(rOutParallel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates a vector around an {@code axis}.
|
||||
* @param vec a vector
|
||||
* @param axis the rotation axis
|
||||
* @param angle the angle in radians
|
||||
* @return the rotated vector
|
||||
*/
|
||||
public static @NotNull Vec3 rotate(@NotNull Vec3 vec, @NotNull Vec3 axis, double angle) {
|
||||
Vec3 vxp = axis.cross(vec);
|
||||
Vec3 vxvxp = axis.cross(vxp);
|
||||
return vec.plus(vxp.times(Math.sin(angle))).plus(vxvxp.times(1 - Math.cos(angle)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the euclidean distance between two vectors}
|
||||
* @param a a vector
|
||||
* @param b another vector
|
||||
*/
|
||||
public static double distance(@NotNull Vec3 a, @NotNull Vec3 b) {
|
||||
return a.minus(b).length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a running average of vectors.
|
||||
* @param current the current running average
|
||||
* @param next the next vector
|
||||
* @param index the one-based index of the next vector
|
||||
* @return the new running average
|
||||
*/
|
||||
public static @NotNull Vec3 average(@NotNull Vec3 current, @NotNull Vec3 next, int index) {
|
||||
var factor = 1d / index;
|
||||
return new Vec3(
|
||||
@ -87,6 +122,11 @@ public record Vec3(double x, double y, double z) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a component-wise maximum vector}
|
||||
* @param a a vector
|
||||
* @param b another vector
|
||||
*/
|
||||
public static @NotNull Vec3 max(@NotNull Vec3 a, @NotNull Vec3 b) {
|
||||
return new Vec3(
|
||||
Math.max(a.x(), b.x()),
|
||||
@ -95,6 +135,11 @@ public record Vec3(double x, double y, double z) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a component-wise minimum vector}
|
||||
* @param a a vector
|
||||
* @param b another vector
|
||||
*/
|
||||
public static @NotNull Vec3 min(@NotNull Vec3 a, @NotNull Vec3 b) {
|
||||
return new Vec3(
|
||||
Math.min(a.x(), b.x()),
|
||||
@ -103,6 +148,12 @@ public record Vec3(double x, double y, double z) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return <code>a * b + c</code>}
|
||||
* @param a scalar
|
||||
* @param b a vector
|
||||
* @param c another vector
|
||||
*/
|
||||
public static @NotNull Vec3 fma(double a, @NotNull Vec3 b, @NotNull Vec3 c) {
|
||||
return new Vec3(
|
||||
Math.fma(a, b.x(), c.x()),
|
||||
@ -119,59 +170,113 @@ public record Vec3(double x, double y, double z) {
|
||||
return new Vec3(this.x - x, this.y - y, this.z - z);
|
||||
}
|
||||
|
||||
public @NotNull Vec3 plus(@NotNull Vec3 b) {
|
||||
return new Vec3(this.x + b.x, this.y + b.y, this.z + b.z);
|
||||
}
|
||||
|
||||
public @NotNull Vec3 minus(@NotNull Vec3 b) {
|
||||
return new Vec3(this.x - b.x, this.y - b.y, this.z - b.z);
|
||||
}
|
||||
|
||||
public double times(@NotNull Vec3 b) {
|
||||
return this.x * b.x + this.y * b.y + this.z * b.z;
|
||||
}
|
||||
|
||||
public @NotNull Vec3 times(double b) {
|
||||
return new Vec3(this.x * b, this.y * b, this.z * b);
|
||||
/**
|
||||
* Adds a vector to this vector
|
||||
* @param other a vector
|
||||
* @return the sum of this and the other vector
|
||||
*/
|
||||
public @NotNull Vec3 plus(@NotNull Vec3 other) {
|
||||
return new Vec3(this.x + other.x, this.y + other.y, this.z + other.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts a vector from this vector
|
||||
* @param other a vector
|
||||
* @return the difference of this and the other vector
|
||||
*/
|
||||
public @NotNull Vec3 minus(@NotNull Vec3 other) {
|
||||
return new Vec3(this.x - other.x, this.y - other.y, this.z - other.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the scalar product of this and another vector
|
||||
* @param other a vector
|
||||
* @return the scalar product
|
||||
*/
|
||||
public double times(@NotNull Vec3 other) {
|
||||
return this.x * other.x + this.y * other.y + this.z * other.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this vector with a scalar
|
||||
* @param t a scalar
|
||||
* @return the product of this vector and the scalar
|
||||
*/
|
||||
public @NotNull Vec3 times(double t) {
|
||||
return new Vec3(this.x * t, this.y * t, this.z * t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Negates this vector.
|
||||
* {@return the negated vector}
|
||||
*/
|
||||
public @NotNull Vec3 neg() {
|
||||
return new Vec3(-x, -y, -z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverts each component of this vector.
|
||||
* @return the inverted vector.
|
||||
*/
|
||||
public @NotNull Vec3 inv() {
|
||||
return new Vec3(1 / x, 1 / y, 1 / z);
|
||||
}
|
||||
|
||||
public @NotNull Vec3 cross(@NotNull Vec3 b) {
|
||||
/**
|
||||
* Computes the cross-product of this and another vector
|
||||
* @param other a vector
|
||||
* @return the cross-product
|
||||
*/
|
||||
public @NotNull Vec3 cross(@NotNull Vec3 other) {
|
||||
return new Vec3(
|
||||
this.y() * b.z() - b.y() * this.z(),
|
||||
this.z() * b.x() - b.z() * this.x(),
|
||||
this.x() * b.y() - b.x() * this.y()
|
||||
this.y() * other.z() - other.y() * this.z(),
|
||||
this.z() * other.x() - other.z() * this.x(),
|
||||
this.x() * other.y() - other.x() * this.y()
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull Vec3 div(double b) {
|
||||
return new Vec3(this.x / b, this.y / b, this.z / b);
|
||||
/**
|
||||
* Divides this vector by a scalar
|
||||
* @param t a scalar
|
||||
* @return this vector divided by the scalar
|
||||
*/
|
||||
public @NotNull Vec3 div(double t) {
|
||||
return new Vec3(this.x / t, this.y / t, this.z / t);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the squared length of this vector}
|
||||
*/
|
||||
public double squared() {
|
||||
return this.x * this.x + this.y * this.y + this.z * this.z;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@return the length of this vector}
|
||||
*/
|
||||
public double length() {
|
||||
return Math.sqrt(squared());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return whether this vector is near zero}
|
||||
*/
|
||||
public boolean isNearZero() {
|
||||
var s = 1e-8;
|
||||
return Math.abs(x) < s && Math.abs(y) < s && Math.abs(z) < s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@return a unit vector with the same direction as this vector}
|
||||
*/
|
||||
public @NotNull Vec3 unit() {
|
||||
return div(length());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the n-th component of this vector}
|
||||
* @param axis the component index
|
||||
*/
|
||||
public double get(int axis) {
|
||||
return switch (axis) {
|
||||
case 0 -> x;
|
||||
|
@ -179,7 +179,7 @@ public final class SimpleRenderer implements Renderer {
|
||||
}
|
||||
} else {
|
||||
var mixed = new MixtureProbabilityDensityFunction(new TargetingProbabilityDensityFunction(hit.position(), scene.getTargets()), pdf, 0.5);
|
||||
var direction = mixed.generate(random);
|
||||
var direction = mixed.generate(random).unit();
|
||||
|
||||
var idealPdf = pdf.value(direction);
|
||||
var actualPdf = mixed.value(direction);
|
||||
|
@ -15,7 +15,7 @@ public record CosineProbabilityDensityFunction(@NotNull Vec3 normal) implements
|
||||
|
||||
@Override
|
||||
public double value(@NotNull Vec3 direction) {
|
||||
var cos = normal.times(direction.unit());
|
||||
var cos = normal.times(direction);
|
||||
return Math.max(0, cos / Math.PI);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
import java.util.Objects;
|
||||
import java.util.random.RandomGenerator;
|
||||
|
||||
/**
|
||||
* Mixes between two probability density functions (pdf) using a weight. When the weight is closer to zero, the
|
||||
* influence of the second pdf is stronger. When the weight is closer to one, the influence of the first pdf is stronger.
|
||||
* @param a the first probability density function
|
||||
* @param b the second probability density function
|
||||
* @param weight a weight in the range [0, 1]
|
||||
*/
|
||||
public record MixtureProbabilityDensityFunction(
|
||||
@NotNull ProbabilityDensityFunction a,
|
||||
@NotNull ProbabilityDensityFunction b,
|
||||
|
@ -5,7 +5,21 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.random.RandomGenerator;
|
||||
|
||||
/**
|
||||
* A probability density function used for sampling random directions when scattering a ray.
|
||||
*/
|
||||
public interface ProbabilityDensityFunction {
|
||||
|
||||
/**
|
||||
* {@return the value of this probability density function at the given point}
|
||||
* @param direction the direction
|
||||
*/
|
||||
double value(@NotNull Vec3 direction);
|
||||
|
||||
/**
|
||||
* Generates a random direction based on this probability density function.
|
||||
* @param random a random number generator
|
||||
* @return the random direction
|
||||
*/
|
||||
@NotNull Vec3 generate(@NotNull RandomGenerator random);
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.random.RandomGenerator;
|
||||
|
||||
/**
|
||||
* A probability density function sampling the sphere uniformly.
|
||||
*/
|
||||
public record SphereProbabilityDensityFunction() implements ProbabilityDensityFunction {
|
||||
|
||||
@Override
|
||||
|
@ -11,6 +11,7 @@ import java.util.random.RandomGenerator;
|
||||
|
||||
/**
|
||||
* A probability density function targeting a target.
|
||||
* @see Target
|
||||
*/
|
||||
public final class TargetingProbabilityDensityFunction implements ProbabilityDensityFunction {
|
||||
private final @NotNull Vec3 origin;
|
||||
|
@ -5,7 +5,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record CheckerTexture(double scale, @NotNull Texture even, @NotNull Texture odd) implements Texture {
|
||||
|
||||
|
||||
@Override
|
||||
public @NotNull Color get(double u, double v, @NotNull Vec3 p) {
|
||||
var x = (int) Math.floor(p.x() / scale);
|
||||
|
Loading…
x
Reference in New Issue
Block a user