diff --git a/.gitignore b/.gitignore index ebf49b8..7f595cf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,60 +1,7 @@ -# Created by .ignore support plugin (hsz.mobi) -### Java template -*.class - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.ear - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* -### JetBrains template -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff: -.idea/workspace.xml -.idea/tasks.xml -.idea/dictionaries -.idea/vcs.xml -.idea/jsLibraryMappings.xml - -# Sensitive or high-churn files: -.idea/dataSources.ids -.idea/dataSources.xml -.idea/dataSources.local.xml -.idea/sqlDataSources.xml -.idea/dynamic.xml -.idea/uiDesigner.xml - -# Gradle: -.idea/gradle.xml -.idea/libraries - -# Mongo Explorer plugin: -.idea/mongoSettings.xml - -## File-based project format: -*.iws - -## Plugin-specific files: - -# IntelliJ -/out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties +.vscode/ +.settings/ +.classpath +.project +*.class +bin/ diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 96cc43e..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml deleted file mode 100644 index e7bedf3..0000000 --- a/.idea/copyright/profiles_settings.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 18d93cc..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index a89ad04..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 71cb9fd..a410568 100644 --- a/README.md +++ b/README.md @@ -1 +1,37 @@ -#Trivial Tracer \ No newline at end of file +# Trivial Tracer + +To compile the project run `make compile`. +To start the tracers run `make run`. + +Run options can be passed through environment variables, the are: +- `CORNEL=true` : Run the cornel room example instead of the spheres room. +- `PATH_TRACE=true` : Uses a path tracer instead of a ray tracer. +- `THREADS=true` : Enables multi-threading. + +#### Examples: +```shell +$ make run +$ CORNEL=true make run +$ PATH_TRACE=true make run +$ CORNEL=true PATH_TRACE=true THREADS=true make run +``` + +### Spheres Room + +Ray tracing + +![](docs/spheres-room-rt.png) + +Path tracing + +![](docs/spheres-room-pt.png) + +### Cornel Room + +Ray tracing + +![](docs/cornel-room-rt.png) + +Path tracing + +![](docs/cornel-room-pt.png) diff --git a/TrivialTracer.iml b/TrivialTracer.iml deleted file mode 100644 index c90834f..0000000 --- a/TrivialTracer.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/docs/cornel-room-pt.png b/docs/cornel-room-pt.png new file mode 100644 index 0000000..f66fbc2 Binary files /dev/null and b/docs/cornel-room-pt.png differ diff --git a/docs/cornel-room-rt.png b/docs/cornel-room-rt.png new file mode 100644 index 0000000..02a261b Binary files /dev/null and b/docs/cornel-room-rt.png differ diff --git a/docs/spheres-room-pt.png b/docs/spheres-room-pt.png new file mode 100644 index 0000000..3cf33f8 Binary files /dev/null and b/docs/spheres-room-pt.png differ diff --git a/docs/spheres-room-rt.png b/docs/spheres-room-rt.png new file mode 100644 index 0000000..3e64a52 Binary files /dev/null and b/docs/spheres-room-rt.png differ diff --git a/makefile b/makefile new file mode 100644 index 0000000..6f625ca --- /dev/null +++ b/makefile @@ -0,0 +1,5 @@ +build: + mvn clean compile + +run: build + mvn exec:exec diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..bba9204 --- /dev/null +++ b/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + trivialtracer + trivial-tracer + 1.0.0 + + + 14 + 14 + + + + ${project.basedir}/src + ${project.basedir}/bin + + + ${project.basedir}/res + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 14 + 14 + + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + java + + -classpath + + Main + + + + + + + diff --git a/model/back.obj b/res/model/back.obj similarity index 100% rename from model/back.obj rename to res/model/back.obj diff --git a/model/ceiling.obj b/res/model/ceiling.obj similarity index 100% rename from model/ceiling.obj rename to res/model/ceiling.obj diff --git a/model/cornellroom.sdl b/res/model/cornellroom.sdl similarity index 100% rename from model/cornellroom.sdl rename to res/model/cornellroom.sdl diff --git a/model/cube1.obj b/res/model/cube1.obj similarity index 100% rename from model/cube1.obj rename to res/model/cube1.obj diff --git a/model/cube2.obj b/res/model/cube2.obj similarity index 100% rename from model/cube2.obj rename to res/model/cube2.obj diff --git a/model/floor.obj b/res/model/floor.obj similarity index 100% rename from model/floor.obj rename to res/model/floor.obj diff --git a/model/leftwall.obj b/res/model/leftwall.obj similarity index 100% rename from model/leftwall.obj rename to res/model/leftwall.obj diff --git a/model/luzcornell.obj b/res/model/luzcornell.obj similarity index 100% rename from model/luzcornell.obj rename to res/model/luzcornell.obj diff --git a/model/rightwall.obj b/res/model/rightwall.obj similarity index 100% rename from model/rightwall.obj rename to res/model/rightwall.obj diff --git a/src/Main.java b/src/Main.java index 14f3674..13723bb 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,8 +1,11 @@ +import java.io.IOException; +import javax.swing.JFrame; import loader.SDLLoader; -import tracer.data.base.Matrix4; import tracer.data.base.Vector3; import tracer.data.visual.Color; -import tracer.model.Model; +import tracer.data.visual.Material; +import tracer.model.Sphere; +import tracer.renderer.AbstractRenderer; import tracer.renderer.MTRenderer; import tracer.renderer.PTRenderer; import tracer.renderer.RTRenderer; @@ -11,10 +14,7 @@ import tracer.scene.Display; import tracer.scene.Scene; import tracer.scene.display.JDisplay; -import tracer.util.TTRand; -import javax.swing.*; -import java.io.IOException; /** * @author Pedro Henrique @@ -22,33 +22,98 @@ public class Main { public static void main(String[] args) throws IOException { - Scene scene = SDLLoader.load("model\\cornellroom.sdl"); - Camera camera = new Camera(new Vector3(0, 0, 1f), - Vector3.zero(), Vector3.up(), (float) Math.toRadians(25) - ); - Display display = new JDisplay(650, 650); + var env = System.getenv(); + boolean cornelExample = env.containsKey("CORNEL") && env.get("CORNEL").equals("true"); + boolean pathTracer = env.containsKey("PATH_TRACE") && env.get("PATH_TRACE").equals("true"); + boolean multiThreaded = env.containsKey("THREADS") && env.get("THREADS").equals("true"); + System.out.println(cornelExample); + if (!cornelExample) spheres(pathTracer, multiThreaded); + else cornellRoom(pathTracer, multiThreaded); + } + + static void frameUpdateConsumer(Renderer r) { + System.out.println(r.getFrameRate()); + } + + static void spheres(boolean pathTracer, boolean multiThreaded) { + Scene scene = new Scene(); + Camera camera = new Camera(Vector3.back().scale(30).sum(Vector3.up().scale(10)), Vector3.up().scale(10)); + Display display = new JDisplay(800, 800); + // + + // + Material lightMat = new Material(Color.white()); + + Material redWallMat = new Material(Color.red(), 1, 0, 0, 1); + Material whiteWallMat = new Material(Color.white(), 1, 0, 0, 1); + Material greenWallMat = new Material(Color.green(), 1, 0, 0, 1); + + Material sphere1Mat = new Material(Color.black(), 0, 1, 0, 1); + Material sphere2Mat = new Material(Color.black(), 0, 0, 1, 1.2f); + // + + // + scene.addModel(new Sphere(Vector3.up().scale(19), 2, lightMat)); + + scene.addModel(new Sphere(Vector3.left().scale(10010), 10000, redWallMat)); + scene.addModel(new Sphere(Vector3.forward().scale(10010), 10000, whiteWallMat)); + scene.addModel(new Sphere(Vector3.up().scale(10020), 10000, whiteWallMat)); + scene.addModel(new Sphere(Vector3.right().scale(10010), 10000, greenWallMat)); + scene.addModel(new Sphere(Vector3.down().scale(10000), 10000, whiteWallMat)); + + scene.addModel(new Sphere(new Vector3(5, 5, 3), 5, sphere1Mat)); + scene.addModel(new Sphere(new Vector3(-4, 3, 1), 3, sphere2Mat)); + + // scene + // .addModel( + // new Torus(redWallMat, Vector3.up().scale(8).sum(Vector3.forward().scale(7)), Vector3.forward(), 2f, 5f) + // ); JFrame frame = new JFrame(); - frame.setSize(700, 700); + frame.setSize(800, 800); frame.add((JDisplay) display); - Renderer renderer = new MTRenderer(new PTRenderer(scene, camera, display, Main::frameUpdateConsumer), 8); + frame.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent windowEvent) { + System.exit(0); + } + }); + + // Renderer renderer = new RTRenderer(scene, camera, display); + AbstractRenderer renderer = pathTracer + ? new PTRenderer(scene, camera, display, Main::frameUpdateConsumer) + : new RTRenderer(scene, camera, display, Main::frameUpdateConsumer); + if (multiThreaded) renderer = new MTRenderer(renderer, Runtime.getRuntime().availableProcessors()); renderer.start(); frame.setVisible(true); } - static void frameUpdateConsumer(Renderer r) { - Vector3 cameraPosition = r.getCamera().getPosition(); - r.getCamera().setPosition( - Matrix4.rotationY( - (float) Math.toRadians(0) * r.getFrameTime() - ).transformAsPoint(cameraPosition) - ); - for (Model light : r.getScene().getLights()) { - //light.getMaterial().setEmissiveColor(Color.white().scale(TTRand.range(0.1f, 1))); - } - System.out.println(r.getFrameRate()); + static void cornellRoom(boolean pathTracer, boolean multiThreaded) throws IOException { + String scenePath = Main.class.getResource("model/cornellroom.sdl").getPath(); + Scene scene = SDLLoader.load(scenePath); + Camera camera = new Camera(new Vector3(0, 0, 1f), Vector3.zero(), Vector3.up(), (float) Math.toRadians(25)); + Display display = new JDisplay(800, 800); + JFrame frame = new JFrame(); + frame.setSize(800, 800); + frame.add((JDisplay) display); + + frame.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent windowEvent) { + System.exit(0); + } + }); + + AbstractRenderer renderer = pathTracer + ? new PTRenderer(scene, camera, display, Main::frameUpdateConsumer) + : new RTRenderer(scene, camera, display, Main::frameUpdateConsumer); + if (multiThreaded) renderer = new MTRenderer(renderer, Runtime.getRuntime().availableProcessors()); + renderer.start(); + + frame.setVisible(true); } + } diff --git a/src/Main2.java b/src/Main2.java deleted file mode 100644 index 12f1d3e..0000000 --- a/src/Main2.java +++ /dev/null @@ -1,88 +0,0 @@ -import tracer.data.base.Matrix4; -import tracer.data.base.Vector3; -import tracer.data.visual.Color; -import tracer.data.visual.Material; -import tracer.model.Model; -import tracer.model.Sphere; -import tracer.model.Torus; -import tracer.renderer.MTRenderer; -import tracer.renderer.PTRenderer; -import tracer.renderer.RTRenderer; -import tracer.renderer.Renderer; -import tracer.scene.Camera; -import tracer.scene.Display; -import tracer.scene.Scene; -import tracer.scene.display.JDisplay; - -import javax.swing.*; -import java.io.IOException; - -/** - * @author Pedro Henrique - */ -public class Main2 { - - public static void main(String[] args) throws IOException { - - // - Scene scene = new Scene(); - Camera camera = new Camera(Vector3.back().scale(30).sum(Vector3.up().scale(10)), Vector3.up().scale(10)); - Display display = new JDisplay(600, 600); - // - - // - Material lightMat = new Material(Color.white()); - - Material redWallMat = new Material(Color.red(), 1, 0, 0, 1); - Material whiteWallMat = new Material(Color.white(), 1, 0, 0, 1); - Material greenWallMat = new Material(Color.green(), 1, 0, 0, 1); - - Material sphere1Mat = new Material(Color.black(), 0, 1, 0, 1); - Material sphere2Mat = new Material(Color.black(), 0, 0, 1, 1.2f); - // - - // - scene.addModel(new Sphere(Vector3.up().scale(19), 2, lightMat)); - - scene.addModel(new Sphere(Vector3.left().scale(10010), 10000, redWallMat)); - scene.addModel(new Sphere(Vector3.forward().scale(10010), 10000, whiteWallMat)); - scene.addModel(new Sphere(Vector3.up().scale(10020), 10000, whiteWallMat)); - scene.addModel(new Sphere(Vector3.right().scale(10010), 10000, greenWallMat)); - scene.addModel(new Sphere(Vector3.down().scale(10000), 10000, whiteWallMat)); - - scene.addModel(new Sphere(new Vector3(5, 5, 3), 5, sphere1Mat)); - scene.addModel(new Sphere(new Vector3(-4, 3, 1), 3, sphere2Mat)); - - //scene.addModel(new Torus(redWallMat, Vector3.up().scale(8).sum(Vector3.forward().scale(7)), Vector3.forward(), 2f, 5f)); - // - - JFrame frame = new JFrame(); - frame.setSize(700, 700); - frame.add((JDisplay) display); - - frame.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent windowEvent) { - System.exit(0); - } - }); - - //Renderer renderer = new RTRenderer(scene, camera, display); - Renderer renderer = new PTRenderer(scene, camera, display, Main2::frameUpdateConsumer); - renderer.start(); - - frame.setVisible(true); - } - - static void frameUpdateConsumer(Renderer r) { - Matrix4 rot = Matrix4.rotationY((float) Math.toRadians(10)); - for (Model m : r.getScene().getModels()) { - if (m instanceof Torus) { - Torus t = (Torus) m; - t.setAxis(rot.transformAsDirection(t.getAxis())); - } - } - System.out.println(r.getFrameRate()); - - } -} diff --git a/src/loader/SDLLoader.java b/src/loader/SDLLoader.java index b17f7d0..b929b3a 100644 --- a/src/loader/SDLLoader.java +++ b/src/loader/SDLLoader.java @@ -47,7 +47,7 @@ public static Scene load(String sdlFilePath) throws IOException { )); break; case "light": - String objLightFilePath = path.getParent().toString() + "\\" + parts[1]; + String objLightFilePath = path.getParent().toString() + "/" + parts[1]; Model light = OBJLoader.load(objLightFilePath); Color emissiveColor = new Color( @@ -58,7 +58,7 @@ public static Scene load(String sdlFilePath) throws IOException { scene.addModel(light); break; case "object": - String objFilePath = path.getParent().toString() + "\\" + parts[1]; + String objFilePath = path.getParent().toString() + "/" + parts[1]; Model model = OBJLoader.load(objFilePath); Color surfaceColor = new Color( diff --git a/src/tracer/renderer/AbstractRenderer.java b/src/tracer/renderer/AbstractRenderer.java index 5c25eb9..1004b28 100644 --- a/src/tracer/renderer/AbstractRenderer.java +++ b/src/tracer/renderer/AbstractRenderer.java @@ -1,5 +1,8 @@ package tracer.renderer; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import tracer.data.base.Matrix4; import tracer.data.base.Vector3; import tracer.data.trace.Hit; @@ -10,11 +13,6 @@ import tracer.scene.Display; import tracer.scene.Scene; import tracer.util.TTRand; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - /** * Abstract Renderer implementation with the necessary objects and methods. Only the method {@link #renderPixel(Ray)} * needs to be implemented to the renderer work, but the method {@link #renderFrame()} too can be override. @@ -145,6 +143,11 @@ public void setDisplay(Display display) { public void setFrameUpdate(Consumer frameUpdate) { this.frameUpdate = frameUpdate; } + + @Override + public Consumer getFrameUpdate() { + return frameUpdate; + } // Rendering thread methods diff --git a/src/tracer/renderer/MTRenderer.java b/src/tracer/renderer/MTRenderer.java index d6a715a..e2af067 100644 --- a/src/tracer/renderer/MTRenderer.java +++ b/src/tracer/renderer/MTRenderer.java @@ -1,5 +1,6 @@ package tracer.renderer; +import java.util.concurrent.atomic.AtomicInteger; import tracer.data.base.Matrix4; import tracer.data.base.Vector3; import tracer.data.trace.Ray; @@ -8,9 +9,6 @@ import tracer.scene.Display; import tracer.scene.Scene; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - /** * @author Pedro Henrique */ @@ -29,6 +27,7 @@ public class MTRenderer extends AbstractRenderer { public MTRenderer(AbstractRenderer internalRenderer, int numberOfThreads) { this.internalRenderer = internalRenderer; this.numberOfThreads = numberOfThreads; + setFrameUpdate(internalRenderer.getFrameUpdate()); } @Override @@ -61,11 +60,6 @@ public void setDisplay(Display display) { internalRenderer.setDisplay(display); } - @Override - public void setFrameUpdate(Consumer frameUpdate) { - internalRenderer.setFrameUpdate(frameUpdate); - } - // Multi-threading attributes private AtomicInteger currentPixel; private final int pixelsPerThreadLoop = 100; diff --git a/src/tracer/renderer/PTRenderer.java b/src/tracer/renderer/PTRenderer.java index 3f22a67..537be80 100644 --- a/src/tracer/renderer/PTRenderer.java +++ b/src/tracer/renderer/PTRenderer.java @@ -1,5 +1,6 @@ package tracer.renderer; +import java.util.function.Consumer; import tracer.data.base.Matrix4; import tracer.data.base.Vector3; import tracer.data.trace.Hit; @@ -12,8 +13,6 @@ import tracer.scene.Scene; import tracer.util.TTRand; -import java.util.function.Consumer; - /** * Renderer implementation using the path tracer techniques. * @@ -57,7 +56,6 @@ protected void renderFrame() { ).normalize(); frontBuffer[x + y * width] = renderPixel(new Ray(rayOrigin, rayDirection)).getIntValue(); } - System.out.println("column " + x); display.flush(); // flushes each column } } diff --git a/src/tracer/renderer/Renderer.java b/src/tracer/renderer/Renderer.java index 0361db7..8821015 100644 --- a/src/tracer/renderer/Renderer.java +++ b/src/tracer/renderer/Renderer.java @@ -1,11 +1,10 @@ package tracer.renderer; +import java.util.function.Consumer; import tracer.scene.Camera; import tracer.scene.Display; import tracer.scene.Scene; -import java.util.function.Consumer; - /** * The Renderer interface, any rendering algorithm should implement this interface. * @@ -61,6 +60,7 @@ public interface Renderer { * @param frameUpdate the received frame update consumer in the renderer. */ void setFrameUpdate(Consumer frameUpdate); + Consumer getFrameUpdate(); /** * Starts the thread that renders the frames. To stop, call the stop() method. If is already running throws an