diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..72f98fa
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..712ab9d
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..2738f8e
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/basics/math/algebra/Vector.java b/src/main/java/basics/math/algebra/Vector.java
index f71e133..4717086 100644
--- a/src/main/java/basics/math/algebra/Vector.java
+++ b/src/main/java/basics/math/algebra/Vector.java
@@ -100,6 +100,16 @@ public class Vector {
return this.sub(normal.scale(this.dot(normal) * 2.0));
}
+ public Vector refract(Vector normal, Vector incoming, double ior) {
+ double len2 = normal.dot(incoming);
+ double k = 1.0 - ior * ior * (1.0 - len2 * len2);
+
+ if (k < 0)
+ return Vector.origin();
+
+ return incoming.scale(ior).sub(normal.scale(ior * len2 + Math.sqrt(k)));
+ }
+
public Vector lerp(Vector other, double k) {
return this.scale(k).add(other.scale(1.0 - k));
}
@@ -108,6 +118,7 @@ public class Vector {
return this.sub(vector).length();
}
+
public enum SwizzleMask {
XYZ,
YXZ,
diff --git a/src/main/java/entry/Main.java b/src/main/java/entry/Main.java
index 34d0938..808f7a6 100644
--- a/src/main/java/entry/Main.java
+++ b/src/main/java/entry/Main.java
@@ -9,7 +9,7 @@ public class Main {
public static void main(String[] args) {
- Resolution resolution = new Resolution(800, 800, 2);
+ Resolution resolution = new Resolution(800, 800, 3);
PlayerController controller = new PlayerController();
diff --git a/src/main/java/geometry/scene/Scene.java b/src/main/java/geometry/scene/Scene.java
index f192c4a..60bf6cc 100644
--- a/src/main/java/geometry/scene/Scene.java
+++ b/src/main/java/geometry/scene/Scene.java
@@ -9,8 +9,10 @@ import optics.light.Point;
import raytracing.BasicMaterial;
import renderer.mesh.BasicMesh;
import renderer.mesh.Mesh;
+import renderer.primitive.Disk;
import renderer.primitive.Plane;
import renderer.primitive.Sphere;
+import shading.Material;
import java.util.ArrayList;
import java.util.List;
@@ -30,14 +32,27 @@ public class Scene {
public static Scene generateExampleScene() {
Scene scene = new Scene(new LinearList());
- scene.addMesh(new BasicMesh(new BasicMaterial(new Color(0.8, 0.4, 0.2), 1.0, new Color(1,0.4,0.1)), new Sphere(new Vector(2,0,0), 1.0)));
- scene.addMesh(new BasicMesh(new BasicMaterial(new Color(0.8, 0.4, 0.2), 0.0, new Color(1,0.4,0.1)), new Sphere(Vector.origin(), 1.0)));
- scene.addMesh(new BasicMesh(new BasicMaterial(new Color(1, 1, 1), 0.2, new Color(1.0)), new Plane(new Vector(1, 0, 0), 1.0)));
- scene.addMesh(new BasicMesh(new BasicMaterial(new Color(1, 1, 1), 0.0, new Color(1.0)), new Plane(new Vector(0, 1, 0), 1.0)));
+ BasicMaterial mirror = new BasicMaterial(Color.BLACK, 1.0, Color.WHITE, true);
+ BasicMaterial white = new BasicMaterial(new Color(0.8, 0.8, 0.8), 0.1, new Color(0.8, 0.8, 0.8), false);
+ BasicMaterial red = new BasicMaterial(new Color(0.8, 0.0, 0.0), 0.1, new Color(0.8, 0.8, 0.8), false);
+ BasicMaterial green = new BasicMaterial(new Color(0.0, 0.8, 0.0), 0.1, new Color(0.8, 0.8, 0.8), false);
+ BasicMaterial blue = new BasicMaterial(new Color(0.0, 0.0, 0.8), 0.1, new Color(0.8, 0.8, 0.8), false);
- scene.addLight(new Point(new Color(0.9, 0, 0), new Vector(8,3,-2)));
- scene.addLight(new Point(new Color(0,0.8,0), new Vector(4,3,2)));
- //scene.addLight(new Directional(new Color(1), new Vector(1, 1, 0).normalize()));
+ scene.addMesh(new BasicMesh(mirror, new Sphere(new Vector(0,1.5,0), 1.0)));
+ scene.addMesh(new BasicMesh(white, new Sphere(new Vector(3,2,0), 0.25)));
+ scene.addMesh(new BasicMesh(red, new Sphere(new Vector(2.5,2,-3), 0.33)));
+
+ scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 1, 0), 1)));
+ scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 1, 0), -6)));
+
+ scene.addMesh(new BasicMesh(red, new Plane(new Vector(1, 0, 0), -4)));
+ scene.addMesh(new BasicMesh(green, new Plane(new Vector(1, 0, 0), 4)));
+
+ scene.addMesh(new BasicMesh(blue, new Plane(new Vector(0, 0, 1), 5)));
+ scene.addMesh(new BasicMesh(white, new Plane(new Vector(0, 0, 1), -4)));
+
+ scene.addLight(new Point(Color.WHITE.scale(0.5), new Vector(0, 4, 0)));
+ scene.addLight(new Point(Color.WHITE.scale(0.5), new Vector(1, 3, 1)));
return scene;
}
diff --git a/src/main/java/optics/light/Color.java b/src/main/java/optics/light/Color.java
index cf8f764..0e83332 100644
--- a/src/main/java/optics/light/Color.java
+++ b/src/main/java/optics/light/Color.java
@@ -5,6 +5,7 @@ import basics.math.algebra.Vector;
public class Color {
public static final Color BLACK = new Color(0,0,0);
+ public static final Color WHITE = Color.diagonal(1.0);
public double r;
public double g;
diff --git a/src/main/java/raytracing/BasicMaterial.java b/src/main/java/raytracing/BasicMaterial.java
index 5e9311b..4f9a4d1 100644
--- a/src/main/java/raytracing/BasicMaterial.java
+++ b/src/main/java/raytracing/BasicMaterial.java
@@ -9,10 +9,13 @@ public class BasicMaterial implements Material {
private double glossieness;
private Color reflectionTint;
- public BasicMaterial(Color diffuse, double glossieness, Color reflectionTint) {
+ private boolean refracts;
+
+ public BasicMaterial(Color diffuse, double glossieness, Color reflectionTint, boolean refracts) {
this.diffuse = diffuse;
this.glossieness = glossieness;
this.reflectionTint = reflectionTint;
+ this.refracts = refracts;
}
public Color getDiffuse() {
@@ -26,4 +29,8 @@ public class BasicMaterial implements Material {
public Color getReflectionTint() {
return reflectionTint;
}
+
+ public boolean refracts() {
+ return this.refracts;
+ }
}
diff --git a/src/main/java/raytracing/Raytracer.java b/src/main/java/raytracing/Raytracer.java
index e4ff27f..0d22992 100644
--- a/src/main/java/raytracing/Raytracer.java
+++ b/src/main/java/raytracing/Raytracer.java
@@ -30,7 +30,7 @@ public class Raytracer implements Renderer {
}
private Color traceDirect(Ray directRay, int depth) {
- if (depth == 4) {
+ if (depth == 8) {
return Color.BLACK;
}
@@ -42,13 +42,17 @@ public class Raytracer implements Renderer {
}
Vector intersection = directRay.travel(result.get().getDistance());
- Vector normal = result.get().getMesh().normalAt(intersection);
+ Vector normal = result.get().getMesh().normalAt(intersection, directRay.getDirection());
BasicMaterial material = (BasicMaterial) result.get().getMesh().getMaterial();
// indirect light sum
Color incoming = new Color(0,0,0);
+ if (material.refracts()) {
+ return refractedLight(directRay, material, normal, intersection, depth);
+ }
+
Color reflectedLight = reflectedLight(directRay, material, normal, intersection, depth);
for (LightSource light : scene.getLights()) {
@@ -56,20 +60,26 @@ public class Raytracer implements Renderer {
Color directLight = material.getDiffuse().scale(directInfluence).mul(light.getColor());
- incoming = incoming.add(directLight).add(reflectedLight);
+ incoming = incoming.add(directLight);
}
- return incoming.add(reflectedLight);
+ return reflectedLight.lerp(incoming, material.getGlossieness());
}
private Color reflectedLight(Ray incomingRay, BasicMaterial material, Vector normal, Vector point, int depth) {
Vector reflected = incomingRay.getDirection().reflect(normal);
- Color reflectedLight = traceDirect(new Ray(point, reflected, 1e-3, 1e3), depth + 1);
+ Color reflectedLight = traceDirect(new Ray(point, reflected, 1e-3, incomingRay.getFar()), depth + 1);
- double highlightFactor = reflected.dot(normal);
+ return reflectedLight.mul(material.getReflectionTint());
+ }
- return reflectedLight.add(new Color(highlightFactor)).mul(material.getReflectionTint());
+ private Color refractedLight(Ray incomingRay, BasicMaterial material, Vector normal, Vector point, int depth) {
+ Vector refracted = incomingRay.getDirection().refract(normal, incomingRay.getDirection(), 1.45);
+
+ Color refractedLight = traceDirect(new Ray(point, refracted, 1e-3, incomingRay.getFar()), depth + 1);
+
+ return refractedLight;
}
private double castShadow(LightSource target, Vector point, Vector surfaceNormal) {
diff --git a/src/main/java/renderer/Display.java b/src/main/java/renderer/Display.java
index f134337..e55d94b 100644
--- a/src/main/java/renderer/Display.java
+++ b/src/main/java/renderer/Display.java
@@ -80,7 +80,7 @@ public class Display {
};
this.window.setContentPane(target);
- this.window.setLocationRelativeTo(null);
+ this.window.setLocationByPlatform(true);
this.window.setVisible(true);
try (Scheduler scheduler = Scheduler.getInstance()) {
diff --git a/src/main/java/renderer/canvas/ContributionBuffer.java b/src/main/java/renderer/canvas/ContributionBuffer.java
index e360104..81ccfee 100644
--- a/src/main/java/renderer/canvas/ContributionBuffer.java
+++ b/src/main/java/renderer/canvas/ContributionBuffer.java
@@ -48,19 +48,12 @@ public class ContributionBuffer {
}
}
- private double tonemap(double x) {
- final double g = 5;
- final double k = 4;
-
- return x < g ? 1 - 1 / Math.pow(g, k) * Math.pow(x - g, k) : 1.0;
- }
-
private int getRGB(int x, int y) {
Color linearRGB = buffer[x][y].scale(1.0 / samples[x][y]);
- int red = (int) (tonemap(linearRGB.r) * 255.0);
- int green = (int) (tonemap(linearRGB.g) * 255.0);
- int blue = (int) (tonemap(linearRGB.b) * 255.0);
+ int red = (int) (linearRGB.r* 255.0);
+ int green = (int) (linearRGB.g * 255.0);
+ int blue = (int) (linearRGB.b * 255.0);
red = Math.max(Math.min(red, 255), 0);
green = Math.max(Math.min(green, 255), 0);
diff --git a/src/main/java/renderer/canvas/RenderTarget.java b/src/main/java/renderer/canvas/RenderTarget.java
index 0302cbf..9f6ff16 100644
--- a/src/main/java/renderer/canvas/RenderTarget.java
+++ b/src/main/java/renderer/canvas/RenderTarget.java
@@ -17,7 +17,7 @@ public class RenderTarget extends JPanel {
private ContributionBuffer buffer;
private DebugOverlay overlay;
- private boolean visualizeThreads = true;
+ private boolean visualizeThreads = false;
public RenderTarget(Resolution resolution) {
super();
diff --git a/src/main/java/renderer/mesh/BasicMesh.java b/src/main/java/renderer/mesh/BasicMesh.java
index 768e73c..a444ce6 100644
--- a/src/main/java/renderer/mesh/BasicMesh.java
+++ b/src/main/java/renderer/mesh/BasicMesh.java
@@ -28,7 +28,7 @@ public class BasicMesh extends Mesh {
}
@Override
- public Vector normalAt(Vector surfacePoint) {
- return shape.normalAt(surfacePoint);
+ public Vector normalAt(Vector surfacePoint, Vector incoming) {
+ return shape.normalAt(surfacePoint, incoming);
}
}
diff --git a/src/main/java/renderer/mesh/Mesh.java b/src/main/java/renderer/mesh/Mesh.java
index 25e6a2f..bc12761 100644
--- a/src/main/java/renderer/mesh/Mesh.java
+++ b/src/main/java/renderer/mesh/Mesh.java
@@ -8,7 +8,7 @@ public abstract class Mesh {
public abstract double intersect(Ray ray);
- public abstract Vector normalAt(Vector surfacePoint);
+ public abstract Vector normalAt(Vector surfacePoint, Vector incoming);
public abstract Material getMaterial();
}
diff --git a/src/main/java/renderer/primitive/Disk.java b/src/main/java/renderer/primitive/Disk.java
new file mode 100644
index 0000000..5ef66d7
--- /dev/null
+++ b/src/main/java/renderer/primitive/Disk.java
@@ -0,0 +1,34 @@
+package renderer.primitive;
+
+import basics.math.algebra.Ray;
+import basics.math.algebra.Vector;
+
+public class Disk implements Primitive {
+
+ private double offset;
+ private double radius;
+ private Vector normal;
+
+ public Disk(Vector normal, double offset, double radius) {
+ this.offset = offset;
+ this.radius = radius;
+ this.normal = normal;
+ }
+
+ @Override
+ public double intersect(Ray ray) {
+ double distance = -(ray.getOrigin().dot(normal) + offset) / ray.getDirection().dot(normal);
+ Vector intersection = ray.travel(distance);
+
+ if (intersection.dot(intersection) > this.radius * this.radius) {
+ return -1.0;
+ }
+
+ return distance;
+ }
+
+ @Override
+ public Vector normalAt(Vector surfacePoint, Vector incoming) {
+ return normal.scale(-Math.signum(normal.dot(incoming)));
+ }
+}
diff --git a/src/main/java/renderer/primitive/Plane.java b/src/main/java/renderer/primitive/Plane.java
index 26bae37..07ded69 100644
--- a/src/main/java/renderer/primitive/Plane.java
+++ b/src/main/java/renderer/primitive/Plane.java
@@ -19,7 +19,7 @@ public class Plane implements Primitive {
}
@Override
- public Vector normalAt(Vector surfacePoint) {
- return normal;
+ public Vector normalAt(Vector surfacePoint, Vector incoming) {
+ return normal.scale(-Math.signum(normal.dot(incoming)));
}
}
diff --git a/src/main/java/renderer/primitive/Primitive.java b/src/main/java/renderer/primitive/Primitive.java
index b95d09b..7c1b631 100644
--- a/src/main/java/renderer/primitive/Primitive.java
+++ b/src/main/java/renderer/primitive/Primitive.java
@@ -7,5 +7,5 @@ public interface Primitive {
double intersect(Ray ray);
- Vector normalAt(Vector surfacePoint);
+ Vector normalAt(Vector surfacePoint, Vector incoming);
}
diff --git a/src/main/java/renderer/primitive/Sphere.java b/src/main/java/renderer/primitive/Sphere.java
index 6cf56e1..793853d 100644
--- a/src/main/java/renderer/primitive/Sphere.java
+++ b/src/main/java/renderer/primitive/Sphere.java
@@ -17,18 +17,23 @@ public class Sphere implements Primitive {
public double intersect(Ray ray) {
Vector oc = ray.getOrigin().sub(this.center);
- double b = ray.getDirection().dot(oc);
+ double b = ray.getDirection().scale(2).dot(oc);
double c = oc.dot(oc) - this.radius * this.radius;
- double h = b * b - c;
+ double h = b * b - 4.0 * c;
if (h < 0.0)
return -1.0;
- return -b - h;
+ h = Math.sqrt(h);
+
+ double u = -b - h;
+ double v = -b + h;
+
+ return (u > ray.getNear() ? u : u > ray.getNear() ? v : 0) * 0.5;
}
@Override
- public Vector normalAt(Vector surfacePoint) {
+ public Vector normalAt(Vector surfacePoint, Vector incoming) {
return surfacePoint.sub(center).normalize();
}
}