add perlin noise texture
This commit is contained in:
parent
e6447fe684
commit
70f2f38e96
@ -6,6 +6,7 @@ import eu.jonahbauer.raytracing.render.texture.Color;
|
||||
import eu.jonahbauer.raytracing.render.camera.SimpleCamera;
|
||||
import eu.jonahbauer.raytracing.render.material.*;
|
||||
import eu.jonahbauer.raytracing.render.texture.ImageTexture;
|
||||
import eu.jonahbauer.raytracing.render.texture.PerlinTexture;
|
||||
import eu.jonahbauer.raytracing.scene.Hittable;
|
||||
import eu.jonahbauer.raytracing.scene.Scene;
|
||||
import eu.jonahbauer.raytracing.scene.SkyBox;
|
||||
@ -34,6 +35,7 @@ public class Examples {
|
||||
register("CORNELL_SMOKE", Examples::getCornellBoxSmoke);
|
||||
register("DIAGRAMM", Examples::getDiagramm);
|
||||
register("EARTH", Examples::getEarth);
|
||||
register("PERLIN", Examples::getPerlin);
|
||||
}
|
||||
|
||||
public static @NotNull IntFunction<Example> getByName(@NotNull String name) {
|
||||
@ -274,6 +276,26 @@ public class Examples {
|
||||
);
|
||||
}
|
||||
|
||||
public static @NotNull Example getPerlin(int height) {
|
||||
if (height <= 0) height = 450;
|
||||
|
||||
var material = new LambertianMaterial(new PerlinTexture(4));
|
||||
|
||||
return new Example(
|
||||
new Scene(
|
||||
getSkyBox(),
|
||||
new Sphere(new Vec3(0, -1000, 0), 1000, material),
|
||||
new Sphere(new Vec3(0, 2, 0), 2, material)
|
||||
),
|
||||
SimpleCamera.builder()
|
||||
.withImage(height * 16 / 9, height)
|
||||
.withFieldOfView(Math.toRadians(20))
|
||||
.withPosition(new Vec3(13, 2, 3))
|
||||
.withTarget(Vec3.ZERO)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
private static @NotNull SkyBox getSkyBox() {
|
||||
return SkyBox.gradient(new Color(0.5, 0.7, 1.0), Color.WHITE);
|
||||
}
|
||||
|
@ -0,0 +1,146 @@
|
||||
package eu.jonahbauer.raytracing.render.texture;
|
||||
|
||||
import eu.jonahbauer.raytracing.math.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
import java.util.function.DoubleFunction;
|
||||
import java.util.random.RandomGenerator;
|
||||
|
||||
public final class PerlinTexture implements Texture {
|
||||
private static final int POINT_COUNT = 256;
|
||||
private static final @NotNull Random RANDOM = new Random();
|
||||
private static final @NotNull DoubleFunction<Color> GREYSCALE = t -> new Color(t, t, t);
|
||||
|
||||
private final double scale;
|
||||
private final int turbulence;
|
||||
private final @NotNull DoubleFunction<Color> color;
|
||||
|
||||
private final int mask;
|
||||
private final Vec3[] randvec;
|
||||
private final int[] permX;
|
||||
private final int[] permY;
|
||||
private final int[] permZ;
|
||||
|
||||
public PerlinTexture() {
|
||||
this(1.0);
|
||||
}
|
||||
|
||||
public PerlinTexture(double scale) {
|
||||
this(scale, 7);
|
||||
}
|
||||
|
||||
public PerlinTexture(double scale, int turbulence) {
|
||||
this(scale, turbulence, GREYSCALE);
|
||||
}
|
||||
|
||||
public PerlinTexture(double scale, int turbulence, @NotNull DoubleFunction<Color> color) {
|
||||
this(scale, turbulence, color, POINT_COUNT, RANDOM);
|
||||
}
|
||||
|
||||
public PerlinTexture(
|
||||
double scale, int turbulence, @NotNull DoubleFunction<Color> color,
|
||||
int count, @NotNull RandomGenerator random
|
||||
) {
|
||||
if ((count & (count - 1)) != 0) throw new IllegalArgumentException("count must be a power of two");
|
||||
if (turbulence <= 0) throw new IllegalArgumentException("turbulence must be positive");
|
||||
|
||||
this.scale = scale;
|
||||
this.turbulence = turbulence;
|
||||
this.color = Objects.requireNonNull(color, "color");
|
||||
|
||||
this.mask = count - 1;
|
||||
this.randvec = new Vec3[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
this.randvec[i] = Vec3.random(random, true);
|
||||
}
|
||||
this.permX = generatePerm(count, random);
|
||||
this.permY = generatePerm(count, random);
|
||||
this.permZ = generatePerm(count, random);
|
||||
}
|
||||
|
||||
private static int @NotNull[] generatePerm(int count, @NotNull RandomGenerator random) {
|
||||
int[] p = new int[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
p[i] = i;
|
||||
}
|
||||
permutate(p, random);
|
||||
return p;
|
||||
}
|
||||
|
||||
private static void permutate(int @NotNull[] p, @NotNull RandomGenerator random) {
|
||||
for (int i = p.length - 1; i > 0; i--) {
|
||||
int target = random.nextInt(i);
|
||||
int tmp = p[i];
|
||||
p[i] = p[target];
|
||||
p[target] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
public double getNoise(@NotNull Vec3 p) {
|
||||
var x = p.x() * scale;
|
||||
var y = p.y() * scale;
|
||||
var z = p.z() * scale;
|
||||
|
||||
var u = x - Math.floor(x);
|
||||
var v = y - Math.floor(y);
|
||||
var w = z - Math.floor(z);
|
||||
|
||||
int i = (int) Math.floor(x);
|
||||
int j = (int) Math.floor(y);
|
||||
int k = (int) Math.floor(z);
|
||||
|
||||
var c = new Vec3[2][2][2];
|
||||
for (int di = 0; di < 2; di++) {
|
||||
for (int dj = 0; dj < 2; dj++) {
|
||||
for (int dk = 0; dk < 2; dk++) {
|
||||
c[di][dj][dk] = randvec[permX[(i + di) & mask] ^ permY[(j + dj) & mask] ^ permZ[(k + dk) & mask]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return interpolate(c, u, v, w);
|
||||
}
|
||||
|
||||
public double getNoise(@NotNull Vec3 p, int depth) {
|
||||
var accum = 0.0;
|
||||
var temp = p;
|
||||
var weight = 1.0;
|
||||
|
||||
for (int i = 0; i < depth; i++) {
|
||||
accum += weight * getNoise(temp);
|
||||
weight *= 0.5;
|
||||
temp = temp.times(2);
|
||||
}
|
||||
|
||||
return accum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Color get(double u, double v, @NotNull Vec3 p) {
|
||||
var noise = getNoise(p, turbulence);
|
||||
var t = Math.fma(0.5, Math.sin(Math.PI * noise), 0.5);
|
||||
return color.apply(t);
|
||||
}
|
||||
|
||||
private static double interpolate(Vec3[][][] c, double u, double v, double w) {
|
||||
var uu = u * u * (3 - 2 * u);
|
||||
var vv = v * v * (3 - 2 * v);
|
||||
var ww = w * w * (3 - 2 * w);
|
||||
|
||||
var accum = 0.0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int j = 0; j < 2; j++) {
|
||||
for (int k = 0; k < 2; k++) {
|
||||
var weight = new Vec3(u - i, v - j, w - k);
|
||||
accum += (i * uu + (1 - i) * (1 - uu))
|
||||
* (j * vv + (1 - j) * (1 - vv))
|
||||
* (k * ww + (1 - k) * (1 - ww))
|
||||
* c[i][j][k].times(weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
return accum;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user