Compare commits
2 Commits
c91baf9e0c
...
f7d9153ad8
Author | SHA1 | Date | |
---|---|---|---|
f7d9153ad8 | |||
a22b1cb238 |
@ -1,5 +1,6 @@
|
|||||||
package eu.jonahbauer.raytracing;
|
package eu.jonahbauer.raytracing;
|
||||||
|
|
||||||
|
import eu.jonahbauer.raytracing.math.AABB;
|
||||||
import eu.jonahbauer.raytracing.math.Vec3;
|
import eu.jonahbauer.raytracing.math.Vec3;
|
||||||
import eu.jonahbauer.raytracing.render.texture.CheckerTexture;
|
import eu.jonahbauer.raytracing.render.texture.CheckerTexture;
|
||||||
import eu.jonahbauer.raytracing.render.texture.Color;
|
import eu.jonahbauer.raytracing.render.texture.Color;
|
||||||
@ -162,12 +163,11 @@ public class Examples {
|
|||||||
|
|
||||||
return new Example(
|
return new Example(
|
||||||
new Scene(
|
new Scene(
|
||||||
new Parallelogram(new Vec3(555, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), green),
|
new Box(
|
||||||
new Parallelogram(new Vec3(0, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), red),
|
new AABB(new Vec3(0, 0, 0), new Vec3(555, 555, 555)),
|
||||||
|
white, white, red, green, white, null
|
||||||
|
),
|
||||||
new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light),
|
new Parallelogram(new Vec3(343, 554, 332), new Vec3(-130, 0, 0), new Vec3(0, 0, -105), light),
|
||||||
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0, 0), new Vec3(0, 0, 555), white),
|
|
||||||
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0, 0), new Vec3(0, 0, -555), white),
|
|
||||||
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0, 0), new Vec3(0, 555, 0), white),
|
|
||||||
new Box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
new Box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
||||||
new Box(new Vec3(0, 0, 0), new Vec3(165, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65))
|
new Box(new Vec3(0, 0, 0), new Vec3(165, 165, 165), white).rotateY(Math.toRadians(-18)).translate(new Vec3(130, 0, 65))
|
||||||
),
|
),
|
||||||
@ -189,12 +189,11 @@ public class Examples {
|
|||||||
|
|
||||||
return new Example(
|
return new Example(
|
||||||
new Scene(
|
new Scene(
|
||||||
new Parallelogram(new Vec3(555, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), green),
|
new Box(
|
||||||
new Parallelogram(new Vec3(0, 0, 0), new Vec3(0, 555, 0), new Vec3(0, 0, 555), red),
|
new AABB(new Vec3(0, 0, 0), new Vec3(555, 555, 555)),
|
||||||
|
white, white, red, green, white, null
|
||||||
|
),
|
||||||
new Parallelogram(new Vec3(113, 554, 127), new Vec3(330, 0, 0), new Vec3(0, 0, 305), light),
|
new Parallelogram(new Vec3(113, 554, 127), new Vec3(330, 0, 0), new Vec3(0, 0, 305), light),
|
||||||
new Parallelogram(new Vec3(0, 0, 0), new Vec3(555, 0, 0), new Vec3(0, 0, 555), white),
|
|
||||||
new Parallelogram(new Vec3(555, 555, 555), new Vec3(-555, 0, 0), new Vec3(0, 0, -555), white),
|
|
||||||
new Parallelogram(new Vec3(0, 0, 555), new Vec3(555, 0, 0), new Vec3(0, 555, 0), white),
|
|
||||||
new ConstantMedium(
|
new ConstantMedium(
|
||||||
new Box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
new Box(new Vec3(0, 0, 0), new Vec3(165, 330, 165), white).rotateY(Math.toRadians(15)).translate(new Vec3(265, 0, 295)),
|
||||||
0.01, new IsotropicMaterial(Color.BLACK)
|
0.01, new IsotropicMaterial(Color.BLACK)
|
||||||
|
@ -22,7 +22,7 @@ public record DielectricMaterial(double refractionIndex, @NotNull Texture textur
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) {
|
public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) {
|
||||||
var ri = hit.frontFace() ? (1 / refractionIndex) : refractionIndex;
|
var ri = hit.isFrontFace() ? (1 / refractionIndex) : refractionIndex;
|
||||||
|
|
||||||
var cosTheta = Math.min(- ray.direction().unit().times(hit.normal()), 1.0);
|
var cosTheta = Math.min(- ray.direction().unit().times(hit.normal()), 1.0);
|
||||||
var reflectance = reflectance(cosTheta);
|
var reflectance = reflectance(cosTheta);
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package eu.jonahbauer.raytracing.render.material;
|
||||||
|
|
||||||
|
import eu.jonahbauer.raytracing.math.Ray;
|
||||||
|
import eu.jonahbauer.raytracing.math.Vec3;
|
||||||
|
import eu.jonahbauer.raytracing.render.texture.Color;
|
||||||
|
import eu.jonahbauer.raytracing.render.texture.Texture;
|
||||||
|
import eu.jonahbauer.raytracing.scene.HitResult;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.random.RandomGenerator;
|
||||||
|
|
||||||
|
public final class DirectionalMaterial implements Material {
|
||||||
|
private final @Nullable Material front;
|
||||||
|
private final @Nullable Material back;
|
||||||
|
|
||||||
|
private final @NotNull Texture texture;
|
||||||
|
|
||||||
|
public DirectionalMaterial(@Nullable Material front, @Nullable Material back) {
|
||||||
|
this.front = front;
|
||||||
|
this.back = back;
|
||||||
|
this.texture = new DirectionalTexture(
|
||||||
|
front != null ? front.texture() : null,
|
||||||
|
back != null ? back.texture() : null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Texture texture() {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Optional<ScatterResult> scatter(@NotNull Ray ray, @NotNull HitResult hit, @NotNull RandomGenerator random) {
|
||||||
|
if (hit.isFrontFace()) {
|
||||||
|
if (front != null) return front.scatter(ray, hit, random);
|
||||||
|
} else {
|
||||||
|
if (back != null) return back.scatter(ray, hit, random);
|
||||||
|
}
|
||||||
|
// let the ray pass through without obstruction
|
||||||
|
return Optional.of(new ScatterResult(new Ray(ray.at(hit.t()), ray.direction()), Color.WHITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Color emitted(@NotNull HitResult hit) {
|
||||||
|
if (hit.isFrontFace()) {
|
||||||
|
if (front != null) return front.emitted(hit);
|
||||||
|
} else {
|
||||||
|
if (back != null) return back.emitted(hit);
|
||||||
|
}
|
||||||
|
return Color.BLACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record DirectionalTexture(@Nullable Texture front, @Nullable Texture back) implements Texture {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Color get(double u, double v, @NotNull Vec3 p) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isUVRequired() {
|
||||||
|
return front() != null && front().isUVRequired() || back() != null && back().isUVRequired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
public record HitResult(
|
public record HitResult(
|
||||||
double t, @NotNull Vec3 position, @NotNull Vec3 normal,
|
double t, @NotNull Vec3 position, @NotNull Vec3 normal,
|
||||||
@NotNull Material material, double u, double v, boolean frontFace
|
@NotNull Material material, double u, double v, boolean isFrontFace
|
||||||
) implements Comparable<HitResult> {
|
) implements Comparable<HitResult> {
|
||||||
public HitResult {
|
public HitResult {
|
||||||
Objects.requireNonNull(position, "position");
|
Objects.requireNonNull(position, "position");
|
||||||
@ -16,7 +16,7 @@ public record HitResult(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull HitResult withPositionAndNormal(@NotNull Vec3 position, @NotNull Vec3 normal) {
|
public @NotNull HitResult withPositionAndNormal(@NotNull Vec3 position, @NotNull Vec3 normal) {
|
||||||
return new HitResult(t, position, normal, material, u, v, frontFace);
|
return new HitResult(t, position, normal, material, u, v, isFrontFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -8,21 +8,33 @@ import eu.jonahbauer.raytracing.render.material.Material;
|
|||||||
import eu.jonahbauer.raytracing.scene.HitResult;
|
import eu.jonahbauer.raytracing.scene.HitResult;
|
||||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public record Box(@NotNull AABB box, @NotNull Material material) implements Hittable {
|
public final class Box implements Hittable {
|
||||||
|
private final @NotNull AABB box;
|
||||||
public Box {
|
private final @Nullable Material @NotNull[] materials;
|
||||||
Objects.requireNonNull(box, "box");
|
|
||||||
Objects.requireNonNull(material, "material");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Box(@NotNull Vec3 a, @NotNull Vec3 b, @NotNull Material material) {
|
public Box(@NotNull Vec3 a, @NotNull Vec3 b, @NotNull Material material) {
|
||||||
this(new AABB(a, b), material);
|
this(new AABB(a, b), material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Box(@NotNull AABB box, @NotNull Material material) {
|
||||||
|
this(box, Objects.requireNonNull(material, "material"), material, material, material, material, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Box(
|
||||||
|
@NotNull AABB box,
|
||||||
|
@Nullable Material top, @Nullable Material bottom,
|
||||||
|
@Nullable Material left, @Nullable Material right,
|
||||||
|
@Nullable Material front, @Nullable Material back
|
||||||
|
) {
|
||||||
|
this.box = Objects.requireNonNull(box, "box");
|
||||||
|
this.materials = new Material[] { left, bottom, back, right, top, front };
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
|
public @NotNull Optional<HitResult> hit(@NotNull Ray ray, @NotNull Range range) {
|
||||||
// based on AABB#hit with additional detection of the side hit
|
// based on AABB#hit with additional detection of the side hit
|
||||||
@ -70,22 +82,29 @@ public record Box(@NotNull AABB box, @NotNull Material material) implements Hitt
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @NotNull Optional<HitResult> hit0(double tmin, double tmax, @NotNull Side entry, @NotNull Side exit, @NotNull Ray ray, @NotNull Range range) {
|
private @NotNull Optional<HitResult> hit0(double tmin, double tmax, @NotNull Side entry, @NotNull Side exit, @NotNull Ray ray, @NotNull Range range) {
|
||||||
boolean frontFace;
|
|
||||||
double t;
|
double t;
|
||||||
if (range.surrounds(tmin)) {
|
Side side;
|
||||||
frontFace = true;
|
boolean frontFace;
|
||||||
|
Material material;
|
||||||
|
Vec3 normal;
|
||||||
|
if (range.surrounds(tmin) && materials[entry.ordinal()] != null) {
|
||||||
t = tmin;
|
t = tmin;
|
||||||
} else if (range.surrounds(tmax)) {
|
side = entry;
|
||||||
frontFace = false;
|
frontFace = true;
|
||||||
|
material = materials[side.ordinal()];
|
||||||
|
normal = side.normal;
|
||||||
|
} else if (range.surrounds(tmax) && materials[exit.ordinal()] != null) {
|
||||||
t = tmax;
|
t = tmax;
|
||||||
|
side = exit;
|
||||||
|
frontFace = false;
|
||||||
|
material = materials[side.ordinal()];
|
||||||
|
normal = side.normal.neg();
|
||||||
} else {
|
} else {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
var side = frontFace ? entry : exit;
|
|
||||||
var normal = frontFace ? side.normal : side.normal.neg();
|
|
||||||
var position = ray.at(t);
|
var position = ray.at(t);
|
||||||
var uv = material().texture().isUVRequired();
|
var uv = material.texture().isUVRequired();
|
||||||
var u = uv ? side.getTextureU(box, position) : Double.NaN;
|
var u = uv ? side.getTextureU(box, position) : Double.NaN;
|
||||||
var v = uv ? side.getTextureV(box, position) : Double.NaN;
|
var v = uv ? side.getTextureV(box, position) : Double.NaN;
|
||||||
return Optional.of(new HitResult(t, position, normal, material, u, v, frontFace));
|
return Optional.of(new HitResult(t, position, normal, material, u, v, frontFace));
|
||||||
|
@ -32,7 +32,7 @@ public record ConstantMedium(@NotNull Hittable boundary, double density, @NotNul
|
|||||||
if (hitDistance > distance) return Optional.empty();
|
if (hitDistance > distance) return Optional.empty();
|
||||||
|
|
||||||
var t = tmin + hitDistance / length;
|
var t = tmin + hitDistance / length;
|
||||||
return Optional.of(new HitResult(t, ray.at(t), Vec3.UNIT_X, material, 0, 0, true)); // arbitrary normal and frontFace
|
return Optional.of(new HitResult(t, ray.at(t), Vec3.UNIT_X, material, 0, 0, true)); // arbitrary normal, u, v and isFrontFace
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
x
Reference in New Issue
Block a user