From 5e2d72b937ce1253bb76c8979d1358679a32fff8 Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Thu, 31 Aug 2023 21:03:06 -0400 Subject: [PATCH 1/3] kill ray.emittance (good riddance) --- .../chunky/renderer/scene/PathTracer.java | 59 +++++++------------ chunky/src/java/se/llbit/math/Ray.java | 7 --- 2 files changed, 20 insertions(+), 46 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java index da75ea168a..4209f78923 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java @@ -45,7 +45,7 @@ public class PathTracer implements RayTracer { } else { ray.setCurrentMaterial(Air.INSTANCE); } - pathTrace(scene, ray, state, 1, true); + pathTrace(scene, ray, state, true); } /** @@ -54,7 +54,7 @@ public class PathTracer implements RayTracer { * @param firstReflection {@code true} if the ray has not yet hit the first * diffuse or specular reflection */ - public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int addEmitted, + public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, boolean firstReflection) { boolean hit = false; @@ -141,7 +141,7 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add if (doMetal || (pSpecular > Ray.EPSILON && random.nextFloat() < pSpecular)) { hit |= doSpecularReflection(ray, next, cumulativeColor, doMetal, random, state, scene); } else if(random.nextFloat() < pDiffuse) { - hit |= doDiffuseReflection(ray, next, currentMat, cumulativeColor, addEmitted, random, state, scene); + hit |= doDiffuseReflection(ray, next, currentMat, cumulativeColor, random, state, scene); } else if (n1 != n2) { hit |= doRefraction(ray, next, currentMat, prevMat, cumulativeColor, n1, n2, pDiffuse, random, state, scene); } else { @@ -204,10 +204,7 @@ public static boolean pathTrace(Scene scene, Ray ray, WorkerState state, int add private static boolean doSpecularReflection(Ray ray, Ray next, Vector4 cumulativeColor, boolean doMetal, Random random, WorkerState state, Scene scene) { boolean hit = false; next.specularReflection(ray, random); - if (pathTrace(scene, next, state, 1, false)) { - ray.emittance.x = ray.color.x * next.emittance.x; - ray.emittance.y = ray.color.y * next.emittance.y; - ray.emittance.z = ray.color.z * next.emittance.z; + if (pathTrace(scene, next, state, false)) { if (doMetal) { // use the albedo color as specular color @@ -224,20 +221,15 @@ private static boolean doSpecularReflection(Ray ray, Ray next, Vector4 cumulativ return hit; } - private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMat, Vector4 cumulativeColor, int addEmitted, Random random, WorkerState state, Scene scene) { + private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMat, Vector4 cumulativeColor, Random random, WorkerState state, Scene scene) { boolean hit = false; - float emittance = 0; + Vector3 emittance = new Vector3(); Vector4 indirectEmitterColor = new Vector4(0, 0, 0, 0); if (scene.emittersEnabled && (!scene.isPreventNormalEmitterWithSampling() || scene.getEmitterSamplingStrategy() == EmitterSamplingStrategy.NONE || ray.depth == 0) && currentMat.emittance > Ray.EPSILON) { - emittance = addEmitted; - ray.emittance.x = ray.color.x * ray.color.x * - currentMat.emittance * scene.emitterIntensity; - ray.emittance.y = ray.color.y * ray.color.y * - currentMat.emittance * scene.emitterIntensity; - ray.emittance.z = ray.color.z * ray.color.z * - currentMat.emittance * scene.emitterIntensity; + emittance = new Vector3(ray.color.x, ray.color.y, ray.color.z); + emittance.scale(currentMat.emittance * scene.emitterIntensity); hit = true; } else if (scene.emittersEnabled && scene.emitterSamplingStrategy != EmitterSamplingStrategy.NONE && scene.getEmitterGrid() != null) { @@ -294,14 +286,11 @@ private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMa } next.diffuseReflection(ray, random); - hit = pathTrace(scene, next, state, 0, false) || hit; + hit = pathTrace(scene, next, state, false) || hit; if (hit) { - cumulativeColor.x += ray.color.x * (emittance + directLightR * scene.sun.emittance.x + ( - next.color.x + next.emittance.x) + (indirectEmitterColor.x)); - cumulativeColor.y += ray.color.y * (emittance + directLightG * scene.sun.emittance.y + ( - next.color.y + next.emittance.y) + (indirectEmitterColor.y)); - cumulativeColor.z += ray.color.z * (emittance + directLightB * scene.sun.emittance.z + ( - next.color.z + next.emittance.z) + (indirectEmitterColor.z)); + cumulativeColor.x += ray.color.x * (emittance.x + directLightR * scene.sun.emittance.x + next.color.x + (indirectEmitterColor.x)); + cumulativeColor.y += ray.color.y * (emittance.y + directLightG * scene.sun.emittance.y + next.color.y + (indirectEmitterColor.y)); + cumulativeColor.z += ray.color.z * (emittance.z + directLightB * scene.sun.emittance.z + next.color.z + (indirectEmitterColor.z)); } else if (indirectEmitterColor.x > Ray.EPSILON || indirectEmitterColor.y > Ray.EPSILON || indirectEmitterColor.z > Ray.EPSILON) { hit = true; cumulativeColor.x += ray.color.x * indirectEmitterColor.x; @@ -312,11 +301,11 @@ private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMa } else { next.diffuseReflection(ray, random); - hit = pathTrace(scene, next, state, 0, false) || hit; + hit = pathTrace(scene, next, state, false) || hit; if (hit) { - cumulativeColor.x += ray.color.x * (emittance + (next.color.x + next.emittance.x) + (indirectEmitterColor.x)); - cumulativeColor.y += ray.color.y * (emittance + (next.color.y + next.emittance.y) + (indirectEmitterColor.y)); - cumulativeColor.z += ray.color.z * (emittance + (next.color.z + next.emittance.z) + (indirectEmitterColor.z)); + cumulativeColor.x += ray.color.x * (emittance.x + next.color.x + (indirectEmitterColor.x)); + cumulativeColor.y += ray.color.y * (emittance.y + next.color.y + (indirectEmitterColor.y)); + cumulativeColor.z += ray.color.z * (emittance.z + next.color.z + (indirectEmitterColor.z)); } else if (indirectEmitterColor.x > Ray.EPSILON || indirectEmitterColor.y > Ray.EPSILON || indirectEmitterColor.z > Ray.EPSILON) { hit = true; cumulativeColor.x += ray.color.x * indirectEmitterColor.x; @@ -338,10 +327,7 @@ private static boolean doRefraction(Ray ray, Ray next, Material currentMat, Mate if (doRefraction && radicand < Ray.EPSILON) { // Total internal reflection. next.specularReflection(ray, random); - if (pathTrace(scene, next, state, 1, false)) { - ray.emittance.x = ray.color.x * next.emittance.x; - ray.emittance.y = ray.color.y * next.emittance.y; - ray.emittance.z = ray.color.z * next.emittance.z; + if (pathTrace(scene, next, state, false)) { cumulativeColor.x += next.color.x; cumulativeColor.y += next.color.y; @@ -362,10 +348,7 @@ private static boolean doRefraction(Ray ray, Ray next, Material currentMat, Mate if (random.nextFloat() < Rtheta) { next.specularReflection(ray, random); - if (pathTrace(scene, next, state, 1, false)) { - ray.emittance.x = ray.color.x * next.emittance.x; - ray.emittance.y = ray.color.y * next.emittance.y; - ray.emittance.z = ray.color.z * next.emittance.z; + if (pathTrace(scene, next, state, false)) { cumulativeColor.x += next.color.x; cumulativeColor.y += next.color.y; @@ -401,7 +384,7 @@ private static boolean doRefraction(Ray ray, Ray next, Material currentMat, Mate next.o.scaleAdd(Ray.OFFSET, next.d); } - if (pathTrace(scene, next, state, 1, false)) { + if (pathTrace(scene, next, state, false)) { // Calculate the color and emittance of the refracted ray translucentRayColor(scene, ray, next, cumulativeColor, pDiffuse); hit = true; @@ -416,7 +399,7 @@ private static boolean doTransmission(Ray ray, Ray next, Vector4 cumulativeColor next.set(ray); next.o.scaleAdd(Ray.OFFSET, next.d); - if (pathTrace(scene, next, state, 1, false)) { + if (pathTrace(scene, next, state, false)) { // Calculate the color and emittance of the refracted ray translucentRayColor(scene, ray, next, cumulativeColor, pDiffuse); hit = true; @@ -474,8 +457,6 @@ private static void translucentRayColor(Scene scene, Ray ray, Ray next, Vector4 Vector4 outputColor = new Vector4(0, 0, 0, 0); outputColor.multiplyEntrywise(new Vector4(rgbTrans, 1), next.color); cumulativeColor.add(outputColor); - // Use emittance from next ray - ray.emittance.multiplyEntrywise(rgbTrans, next.emittance); } private static double reassignTransmissivity(double from, double to, double other, double trans, double cap) { diff --git a/chunky/src/java/se/llbit/math/Ray.java b/chunky/src/java/se/llbit/math/Ray.java index 064efb6ed2..34d2183ef1 100644 --- a/chunky/src/java/se/llbit/math/Ray.java +++ b/chunky/src/java/se/llbit/math/Ray.java @@ -69,11 +69,6 @@ public class Ray { */ public Vector4 color = new Vector4(); - /** - * Emittance of previously intersected surface. - */ - public Vector3 emittance = new Vector3(); - /** * Previous material. */ @@ -150,7 +145,6 @@ public void setDefault() { currentMaterial = Air.INSTANCE; depth = 0; color.set(0, 0, 0, 0); - emittance.set(0, 0, 0); specular = true; } @@ -167,7 +161,6 @@ public void set(Ray other) { n.set(other.n); geomN.set(other.geomN); color.set(0, 0, 0, 0); - emittance.set(0, 0, 0); specular = other.specular; } From 132d779cea7530f2c9bcdcf323b4a5c45a31a971 Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Thu, 31 Aug 2023 21:29:32 -0400 Subject: [PATCH 2/3] remove special case for torches so they don't look ridiculous --- .../src/java/se/llbit/chunky/chunk/BlockPalette.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/chunk/BlockPalette.java b/chunky/src/java/se/llbit/chunky/chunk/BlockPalette.java index f6031b65f8..633dc4d4d2 100644 --- a/chunky/src/java/se/llbit/chunky/chunk/BlockPalette.java +++ b/chunky/src/java/se/llbit/chunky/chunk/BlockPalette.java @@ -346,10 +346,10 @@ public static Map> getDefaultMaterialProperties() { } }); materialProperties.put("minecraft:torch", block -> { - block.emittance = 50.0f; + block.emittance = 1.0f; }); materialProperties.put("minecraft:wall_torch", block -> { - block.emittance = 50.0f; + block.emittance = 1.0f; }); materialProperties.put("minecraft:fire", block -> { block.emittance = 1.0f; @@ -447,16 +447,16 @@ public static Map> getDefaultMaterialProperties() { block.emittance = 0.6f; }); materialProperties.put("minecraft:soul_fire_torch", block -> { // MC 20w06a-20w16a - block.emittance = 35.0f; + block.emittance = 0.6f; }); materialProperties.put("minecraft:soul_torch", block -> { // MC >= 20w17a - block.emittance = 35.0f; + block.emittance = 0.6f; }); materialProperties.put("minecraft:soul_fire_wall_torch", block -> { // MC 20w06a-20w16a - block.emittance = 35.0f; + block.emittance = 0.6f; }); materialProperties.put("minecraft:soul_wall_torch", block -> { // MC >= 20w17a - block.emittance = 35.0f; + block.emittance = 0.6f; }); materialProperties.put("minecraft:soul_fire", block -> { block.emittance = 0.6f; From bfcaa1d8d0227cdd3213cf13b8500fcb454eac54 Mon Sep 17 00:00:00 2001 From: JustinTimeCuber Date: Fri, 1 Sep 2023 14:43:26 -0400 Subject: [PATCH 3/3] rearrange algebra to improve readability --- .../llbit/chunky/renderer/scene/PathTracer.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java index 4209f78923..7020efd2a7 100644 --- a/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java +++ b/chunky/src/java/se/llbit/chunky/renderer/scene/PathTracer.java @@ -228,7 +228,9 @@ private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMa if (scene.emittersEnabled && (!scene.isPreventNormalEmitterWithSampling() || scene.getEmitterSamplingStrategy() == EmitterSamplingStrategy.NONE || ray.depth == 0) && currentMat.emittance > Ray.EPSILON) { - emittance = new Vector3(ray.color.x, ray.color.y, ray.color.z); + // Quadratic emittance mapping, so a pixel that's 50% darker will emit only 25% as much light + // This is arbitrary but gives pretty good results in most cases. + emittance = new Vector3(ray.color.x * ray.color.x, ray.color.y * ray.color.y, ray.color.z * ray.color.z); emittance.scale(currentMat.emittance * scene.emitterIntensity); hit = true; @@ -288,9 +290,9 @@ private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMa next.diffuseReflection(ray, random); hit = pathTrace(scene, next, state, false) || hit; if (hit) { - cumulativeColor.x += ray.color.x * (emittance.x + directLightR * scene.sun.emittance.x + next.color.x + (indirectEmitterColor.x)); - cumulativeColor.y += ray.color.y * (emittance.y + directLightG * scene.sun.emittance.y + next.color.y + (indirectEmitterColor.y)); - cumulativeColor.z += ray.color.z * (emittance.z + directLightB * scene.sun.emittance.z + next.color.z + (indirectEmitterColor.z)); + cumulativeColor.x += emittance.x + ray.color.x * (directLightR * scene.sun.emittance.x + next.color.x + indirectEmitterColor.x); + cumulativeColor.y += emittance.y + ray.color.y * (directLightG * scene.sun.emittance.y + next.color.y + indirectEmitterColor.y); + cumulativeColor.z += emittance.z + ray.color.z * (directLightB * scene.sun.emittance.z + next.color.z + indirectEmitterColor.z); } else if (indirectEmitterColor.x > Ray.EPSILON || indirectEmitterColor.y > Ray.EPSILON || indirectEmitterColor.z > Ray.EPSILON) { hit = true; cumulativeColor.x += ray.color.x * indirectEmitterColor.x; @@ -303,9 +305,9 @@ private static boolean doDiffuseReflection(Ray ray, Ray next, Material currentMa hit = pathTrace(scene, next, state, false) || hit; if (hit) { - cumulativeColor.x += ray.color.x * (emittance.x + next.color.x + (indirectEmitterColor.x)); - cumulativeColor.y += ray.color.y * (emittance.y + next.color.y + (indirectEmitterColor.y)); - cumulativeColor.z += ray.color.z * (emittance.z + next.color.z + (indirectEmitterColor.z)); + cumulativeColor.x += emittance.x + ray.color.x * (next.color.x + indirectEmitterColor.x); + cumulativeColor.y += emittance.y + ray.color.y * (next.color.y + indirectEmitterColor.y); + cumulativeColor.z += emittance.z + ray.color.z * (next.color.z + indirectEmitterColor.z); } else if (indirectEmitterColor.x > Ray.EPSILON || indirectEmitterColor.y > Ray.EPSILON || indirectEmitterColor.z > Ray.EPSILON) { hit = true; cumulativeColor.x += ray.color.x * indirectEmitterColor.x;