add depth of field
This commit is contained in:
parent
d89d15f1a4
commit
1080711229
@ -28,6 +28,8 @@ public class Main {
|
||||
.withPosition(new Vec3(-2, 2, 1))
|
||||
.withTarget(new Vec3(0, 0, -1))
|
||||
.withFieldOfView(Math.toRadians(20))
|
||||
.withFocusDistance(3.4)
|
||||
.withBlurAngle(Math.toRadians(10))
|
||||
.build();
|
||||
|
||||
var image = camera.render(scene);
|
||||
|
@ -21,6 +21,7 @@ public final class Camera {
|
||||
private final int samplesPerPixel;
|
||||
private final int maxDepth;
|
||||
private final double gamma;
|
||||
private final double blurRadius;
|
||||
|
||||
// internal properties
|
||||
private final @NotNull Vec3 u;
|
||||
@ -42,7 +43,7 @@ public final class Camera {
|
||||
this.width = builder.imageWidth;
|
||||
this.height = builder.imageHeight;
|
||||
|
||||
var viewportHeight = 2 * Math.tan(0.5 * builder.fov);
|
||||
var viewportHeight = 2 * Math.tan(0.5 * builder.fov) * builder.focusDistance;
|
||||
var viewportWidth = viewportHeight * ((double) width / height);
|
||||
|
||||
this.origin = builder.position;
|
||||
@ -51,6 +52,7 @@ public final class Camera {
|
||||
this.samplesPerPixel = builder.samplePerPixel;
|
||||
this.maxDepth = builder.maxDepth;
|
||||
this.gamma = builder.gamma;
|
||||
this.blurRadius = Math.tan(0.5 * builder.blurAngle) * builder.focusDistance;
|
||||
|
||||
// project direction the horizontal plane
|
||||
var dXZ = direction.withY(0).unit();
|
||||
@ -63,7 +65,7 @@ public final class Camera {
|
||||
this.pixelU = u.times(viewportWidth / width);
|
||||
this.pixelV = v.times(viewportHeight / height);
|
||||
|
||||
this.pixel00 = origin.plus(direction)
|
||||
this.pixel00 = origin.plus(direction.times(builder.focusDistance))
|
||||
.minus(u.times(0.5 * viewportWidth)).minus(v.times(0.5 * viewportHeight))
|
||||
.plus(pixelU.div(2)).plus(pixelV.div(2));
|
||||
}
|
||||
@ -97,6 +99,17 @@ public final class Camera {
|
||||
}
|
||||
|
||||
private @NotNull Ray getRay(int x, int y) {
|
||||
var origin = this.origin;
|
||||
if (blurRadius > 0) {
|
||||
double bu, bv;
|
||||
do {
|
||||
bu = 2 * Math.random() - 1;
|
||||
bv = 2 * Math.random() - 1;
|
||||
} while (bu * bu + bv * bv >= 1);
|
||||
|
||||
origin = origin.plus(u.times(blurRadius * bu)).plus(v.times(blurRadius * bv));
|
||||
}
|
||||
|
||||
return new Ray(origin, getPixel(x, y).minus(origin));
|
||||
}
|
||||
|
||||
@ -147,6 +160,8 @@ public final class Camera {
|
||||
private double rotation = 0.0;
|
||||
|
||||
private double fov = 0.5 * Math.PI;
|
||||
private double focusDistance = 10;
|
||||
private double blurAngle = 0.0;
|
||||
|
||||
private int samplePerPixel = 100;
|
||||
private int maxDepth = 10;
|
||||
@ -190,6 +205,18 @@ public final class Camera {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder withFocusDistance(double focusDistance) {
|
||||
if (focusDistance <= 0 || !Double.isFinite(focusDistance)) throw new IllegalArgumentException("focus distance must be positive");
|
||||
this.focusDistance = focusDistance;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder withBlurAngle(double angle) {
|
||||
if (angle < 0 || angle >= Math.PI || !Double.isFinite(angle)) throw new IllegalArgumentException("blur-angle must be in the range [0, π)");
|
||||
this.blurAngle = angle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder withSamplesPerPixel(int samples) {
|
||||
if (samples <= 0) throw new IllegalArgumentException("samples must be positive");
|
||||
this.samplePerPixel = samples;
|
||||
|
Loading…
x
Reference in New Issue
Block a user