added physically based materials
This commit is contained in:
parent
e97416c8ea
commit
efc094e8cd
|
@ -105,7 +105,7 @@ public class Vector {
|
||||||
}
|
}
|
||||||
|
|
||||||
// based on https://bheisler.github.io/post/writing-raytracer-in-rust-part-3/
|
// based on https://bheisler.github.io/post/writing-raytracer-in-rust-part-3/
|
||||||
public Vector refract(Vector normal, Vector incoming, double ior) {
|
public static Vector refract(Vector normal, Vector incoming, double ior) {
|
||||||
|
|
||||||
double iDotN = incoming.dot(normal);
|
double iDotN = incoming.dot(normal);
|
||||||
double etaI = 1;
|
double etaI = 1;
|
||||||
|
|
|
@ -11,7 +11,7 @@ public class Main {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
Resolution resolution = new Resolution(800, 800, 2);
|
Resolution resolution = new Resolution(800, 800, 4);
|
||||||
|
|
||||||
PlayerController controller = new PlayerController();
|
PlayerController controller = new PlayerController();
|
||||||
|
|
||||||
|
|
|
@ -3,17 +3,16 @@ package geometry.scene;
|
||||||
import basics.math.algebra.Ray;
|
import basics.math.algebra.Ray;
|
||||||
import basics.math.algebra.Vector;
|
import basics.math.algebra.Vector;
|
||||||
import optics.light.Color;
|
import optics.light.Color;
|
||||||
import optics.light.Directional;
|
|
||||||
import optics.light.LightSource;
|
import optics.light.LightSource;
|
||||||
import optics.light.Point;
|
import optics.light.Point;
|
||||||
import pathtracing.BSDF;
|
import pathtracing.pbr.Dielectric;
|
||||||
|
import pathtracing.pbr.Emissive;
|
||||||
|
import pathtracing.pbr.PhysicallyBasedMaterial;
|
||||||
import raytracing.BasicMaterial;
|
import raytracing.BasicMaterial;
|
||||||
import renderer.mesh.BasicMesh;
|
import renderer.mesh.BasicMesh;
|
||||||
import renderer.mesh.Mesh;
|
import renderer.mesh.Mesh;
|
||||||
import renderer.primitive.Disk;
|
|
||||||
import renderer.primitive.Plane;
|
import renderer.primitive.Plane;
|
||||||
import renderer.primitive.Sphere;
|
import renderer.primitive.Sphere;
|
||||||
import shading.Material;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -62,11 +61,11 @@ public class Scene {
|
||||||
public static Scene generatePathtracingExampleScene() {
|
public static Scene generatePathtracingExampleScene() {
|
||||||
Scene scene = new Scene(new LinearList());
|
Scene scene = new Scene(new LinearList());
|
||||||
|
|
||||||
BSDF red = new BSDF(new Color(1, 0.3, 0.3), new Color(0), 1.0);
|
var red = new Dielectric(new Color(1.0, 0.3, 0.3), 1.0, false, 1.5);
|
||||||
BSDF green = new BSDF(new Color(0.3,1, 0.3), new Color(0), 1);
|
var green = new Dielectric(new Color(0.3, 1.0, 0.3), 1.0, false, 1.5);
|
||||||
BSDF blue = new BSDF(new Color(0.3, 0.3, 1), new Color(0), 1);
|
var blue = new Dielectric(new Color(0.3, 0.3, 1.0), 1.0, false, 1.5);
|
||||||
BSDF white = new BSDF(new Color(1, 1, 1), new Color(0), 1);
|
var white = new Dielectric(new Color(1.0, 1.0, 1.0), 1.0, false, 1.5);
|
||||||
BSDF light = new BSDF(Color.BLACK, new Color(300), 1.0);
|
var light = new Emissive(Color.WHITE, 8.0);
|
||||||
|
|
||||||
scene.addMesh(new BasicMesh(white, new Sphere(new Vector(0,0,0), 1.0)));
|
scene.addMesh(new BasicMesh(white, new Sphere(new Vector(0,0,0), 1.0)));
|
||||||
scene.addMesh(new BasicMesh(white, new Sphere(new Vector(3,2,1), 1.0)));
|
scene.addMesh(new BasicMesh(white, new Sphere(new Vector(3,2,1), 1.0)));
|
||||||
|
|
|
@ -105,17 +105,11 @@ public class Color {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color lerp(Color other, double k) {
|
public Color lerp(Color other, double k) {
|
||||||
return this.scale(k).add(other.scale(1.0 - k));
|
return this.scale(1.0 - k).add(other.scale(k));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void colorCorrect() {
|
public Color lerp(Color other, Color k) {
|
||||||
this.r = tonemap(this.r);
|
return this.mul(Color.WHITE.sub(k)).add(other.mul(k));
|
||||||
this.g = tonemap(this.g);
|
|
||||||
this.b = tonemap(this.b);
|
|
||||||
}
|
|
||||||
|
|
||||||
private double tonemap(double k) {
|
|
||||||
return -1 / (k + 1) + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIntRGB() {
|
public int getIntRGB() {
|
||||||
|
@ -126,6 +120,10 @@ public class Color {
|
||||||
return 0xff000000 | (r << 16) | (g << 8) | b;
|
return 0xff000000 | (r << 16) | (g << 8) | b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double max() {
|
||||||
|
return Math.max(Math.max(this.r, this.g), this.b);
|
||||||
|
}
|
||||||
|
|
||||||
public enum SwizzleMask {
|
public enum SwizzleMask {
|
||||||
rgb,
|
rgb,
|
||||||
grb,
|
grb,
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package pathtracing;
|
|
||||||
|
|
||||||
import optics.light.Color;
|
|
||||||
import shading.Material;
|
|
||||||
|
|
||||||
public class BSDF implements Material {
|
|
||||||
|
|
||||||
private Color reflectance;
|
|
||||||
private Color emission;
|
|
||||||
|
|
||||||
private double roughness;
|
|
||||||
|
|
||||||
public BSDF(Color reflectance, Color emission, double roughness) {
|
|
||||||
this.reflectance = reflectance;
|
|
||||||
this.emission = emission;
|
|
||||||
this.roughness = roughness;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color getReflectance() {
|
|
||||||
return reflectance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Color getEmission() {
|
|
||||||
return emission;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getRoughness() {
|
|
||||||
return roughness;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,14 @@
|
||||||
package pathtracing;
|
package pathtracing;
|
||||||
|
|
||||||
import basics.math.algebra.Basis;
|
|
||||||
import basics.math.algebra.Ray;
|
import basics.math.algebra.Ray;
|
||||||
import basics.math.algebra.Vector;
|
import basics.math.algebra.Vector;
|
||||||
import geometry.scene.Hit;
|
import geometry.scene.Hit;
|
||||||
import geometry.scene.Scene;
|
import geometry.scene.Scene;
|
||||||
import optics.light.Color;
|
import optics.light.Color;
|
||||||
import optics.light.LightSource;
|
|
||||||
import optics.view.Camera;
|
import optics.view.Camera;
|
||||||
import optics.view.PinholeCamera;
|
import optics.view.PinholeCamera;
|
||||||
|
import pathtracing.pbr.Emissive;
|
||||||
|
import pathtracing.pbr.PhysicallyBasedMaterial;
|
||||||
import renderer.Renderer;
|
import renderer.Renderer;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -30,15 +30,8 @@ public class Pathtracer implements Renderer {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double castShadow(LightSource target, Vector point, Vector surfaceNormal) {
|
public Color traceDirect(Ray directRay, int depth) {
|
||||||
Vector lightDirection = target.getDirection(point);
|
if (depth == 4) {
|
||||||
double distance = target.getDistance(point);
|
|
||||||
double shadow = traceShadow(point, lightDirection, distance);
|
|
||||||
return Math.max(surfaceNormal.dot(lightDirection), 0.0) * shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color traceDirect(Ray directRay, int depth) {
|
|
||||||
if (depth == 8) {
|
|
||||||
return Color.BLACK;
|
return Color.BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,58 +45,9 @@ public class Pathtracer implements Renderer {
|
||||||
Vector intersection = directRay.travel(result.get().getDistance());
|
Vector intersection = directRay.travel(result.get().getDistance());
|
||||||
Vector normal = result.get().getMesh().normalAt(intersection, directRay.getDirection());
|
Vector normal = result.get().getMesh().normalAt(intersection, directRay.getDirection());
|
||||||
|
|
||||||
BSDF material = (BSDF) result.get().getMesh().getMaterial();
|
var material = (PhysicallyBasedMaterial) result.get().getMesh().getMaterial();
|
||||||
|
|
||||||
var diffuse = diffuseCosineWeightedBRDF(intersection, normal, material, depth);
|
return material.surfaceColor(normal, directRay.getDirection(), intersection, this, depth + 1);
|
||||||
|
|
||||||
return diffuse.add(material.getEmission());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color diffuseCosineWeightedBRDF(Vector intersection, Vector normal, BSDF bsdf, int depth) {
|
|
||||||
var next = new Ray(intersection, sampleNormalHemisphere(normal, bsdf.getRoughness()), 1e-3, 1e3);
|
|
||||||
|
|
||||||
var cosTheta = next.getDirection().dot(normal);
|
|
||||||
|
|
||||||
var pdf = cosTheta / Math.PI;
|
|
||||||
|
|
||||||
var indirectLight = traceDirect(next, depth + 1).scale(pdf);
|
|
||||||
|
|
||||||
// direct light
|
|
||||||
|
|
||||||
Color directLight = Color.BLACK;
|
|
||||||
|
|
||||||
for (LightSource light : scene.getLights()) {
|
|
||||||
double directInfluence = castShadow(light, intersection, normal);
|
|
||||||
|
|
||||||
Color incoming = bsdf.getReflectance().scale(directInfluence).mul(light.getColor());
|
|
||||||
|
|
||||||
directLight = directLight.add(incoming);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bsdf.getReflectance().mul(indirectLight.add(directLight));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector cosineHemisphere() {
|
|
||||||
double u1 = Math.random();
|
|
||||||
double u2 = Math.random();
|
|
||||||
|
|
||||||
double r = Math.sqrt(u1);
|
|
||||||
double theta = 2 * Math.PI * u2;
|
|
||||||
|
|
||||||
double x = r * Math.cos(theta);
|
|
||||||
double y = r * Math.sin(theta);
|
|
||||||
|
|
||||||
return new Vector(x, y, Math.sqrt(1 - u1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vector sampleNormalHemisphere(Vector normal, double roughness) {
|
|
||||||
Vector hemisphereSample = cosineHemisphere();
|
|
||||||
|
|
||||||
var orthnormalBasis = Basis.constructOrthonormalBasis(normal);
|
|
||||||
|
|
||||||
return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
|
|
||||||
.add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
|
|
||||||
.add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package pathtracing.bdf;
|
||||||
|
|
||||||
|
import basics.math.algebra.Basis;
|
||||||
|
import basics.math.algebra.Vector;
|
||||||
|
|
||||||
|
public abstract class BDF {
|
||||||
|
|
||||||
|
public static Vector sampleBTDF(Vector normal, Vector incoming, double roughness, double ior) {
|
||||||
|
Vector up = Vector.refract(normal, incoming, ior).lerp(normal.negate(), roughness);
|
||||||
|
|
||||||
|
Vector hemisphereSample = BDF.cosineHemisphere(roughness);
|
||||||
|
|
||||||
|
var orthnormalBasis = Basis.constructOrthonormalBasis(up);
|
||||||
|
|
||||||
|
return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
|
||||||
|
.add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
|
||||||
|
.add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector sampleBRDF(Vector normal, Vector incoming, double roughness) {
|
||||||
|
Vector up = incoming.reflect(normal).lerp(normal, roughness);
|
||||||
|
|
||||||
|
Vector hemisphereSample = BDF.cosineHemisphere(roughness);
|
||||||
|
|
||||||
|
var orthnormalBasis = Basis.constructOrthonormalBasis(up);
|
||||||
|
|
||||||
|
return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
|
||||||
|
.add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
|
||||||
|
.add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vector cosineHemisphere(double maximumAngle) {
|
||||||
|
double u1 = Math.random();
|
||||||
|
double u2 = Math.random() * maximumAngle;
|
||||||
|
|
||||||
|
double r = Math.sqrt(u1);
|
||||||
|
double theta = 2 * Math.PI * u2;
|
||||||
|
|
||||||
|
double x = r * Math.cos(theta);
|
||||||
|
double y = r * Math.sin(theta);
|
||||||
|
|
||||||
|
return new Vector(x, y, Math.sqrt(1 - u1));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package pathtracing.bdf;
|
||||||
|
|
||||||
|
import basics.math.algebra.Basis;
|
||||||
|
import basics.math.algebra.Vector;
|
||||||
|
|
||||||
|
public class BRDF {
|
||||||
|
|
||||||
|
public static Vector sampleDirection(Vector incoming, Vector normal, double roughness) {
|
||||||
|
Vector hemisphereSample = BDF.cosineHemisphere(roughness);
|
||||||
|
|
||||||
|
var direction = incoming.reflect(normal).lerp(normal, roughness);
|
||||||
|
|
||||||
|
var orthnormalBasis = Basis.constructOrthonormalBasis(direction);
|
||||||
|
|
||||||
|
return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
|
||||||
|
.add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
|
||||||
|
.add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package pathtracing.bdf;
|
||||||
|
|
||||||
|
import basics.math.algebra.Basis;
|
||||||
|
import basics.math.algebra.Vector;
|
||||||
|
|
||||||
|
public class BTDF {
|
||||||
|
|
||||||
|
public static Vector sampleDirection(Vector incoming, Vector normal, double roughness, double ior) {
|
||||||
|
Vector hemisphereSample = BDF.cosineHemisphere(roughness);
|
||||||
|
|
||||||
|
var direction = Vector.refract(normal, incoming, ior)
|
||||||
|
.lerp(normal.negate(), roughness);
|
||||||
|
|
||||||
|
var orthnormalBasis = Basis.constructOrthonormalBasis(direction);
|
||||||
|
|
||||||
|
return orthnormalBasis.vectors[0].scale(hemisphereSample.z)
|
||||||
|
.add(orthnormalBasis.vectors[1].scale(hemisphereSample.x))
|
||||||
|
.add(orthnormalBasis.vectors[2].scale(hemisphereSample.y));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package pathtracing.pbr;
|
||||||
|
|
||||||
|
import basics.math.algebra.Basis;
|
||||||
|
import basics.math.algebra.Ray;
|
||||||
|
import basics.math.algebra.Vector;
|
||||||
|
import optics.light.Color;
|
||||||
|
import pathtracing.Pathtracer;
|
||||||
|
import pathtracing.bdf.BDF;
|
||||||
|
|
||||||
|
public class Dielectric extends PhysicallyBasedMaterial {
|
||||||
|
|
||||||
|
private final Color reflectance;
|
||||||
|
private final double roughness;
|
||||||
|
private final boolean transmissive;
|
||||||
|
private final double ior;
|
||||||
|
|
||||||
|
public Dielectric(Color reflectance, double roughness, boolean transmissive, double ior) {
|
||||||
|
this.reflectance = reflectance;
|
||||||
|
this.roughness = roughness;
|
||||||
|
this.transmissive = transmissive;
|
||||||
|
this.ior = ior;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color schlickFresnel(double cosTheta) {
|
||||||
|
return reflectance.lerp(Color.WHITE, Math.pow(1.0 - cosTheta, 5.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color surfaceColor(Vector normal, Vector incident, Vector intersection, Pathtracer pathtracer, int depth) {
|
||||||
|
var cosTheta = Math.abs(incident.dot(normal));
|
||||||
|
|
||||||
|
var schlick = schlickFresnel(cosTheta).scale(1.0 - roughness);
|
||||||
|
|
||||||
|
var reflectionRay = new Ray(intersection, BDF.sampleBRDF(normal, incident, roughness), 1e-3, 1e3);
|
||||||
|
var reflectedColor = pathtracer.traceDirect(reflectionRay, depth);
|
||||||
|
|
||||||
|
//if (transmissive) {
|
||||||
|
// var refractionRay = new Ray(intersection, BDF.sampleBTDF(normal, incident, roughness, ior), 1e-3, 1e3);
|
||||||
|
// var refractionColor = reflectance.mul(pathtracer.traceDirect(refractionRay, depth));
|
||||||
|
|
||||||
|
// return refractionColor.lerp(reflectedColor, schlick);
|
||||||
|
//} else {
|
||||||
|
var diffuseRay = new Ray(intersection, BDF.sampleBRDF(normal, incident, 1.0), 1e-3, 1e3);
|
||||||
|
var diffuseColor = reflectance.mul(pathtracer.traceDirect(diffuseRay, depth));
|
||||||
|
|
||||||
|
return diffuseColor.lerp(reflectedColor, schlick);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package pathtracing.pbr;
|
||||||
|
|
||||||
|
import basics.math.algebra.Vector;
|
||||||
|
import optics.light.Color;
|
||||||
|
import pathtracing.Pathtracer;
|
||||||
|
|
||||||
|
public class Emissive extends PhysicallyBasedMaterial {
|
||||||
|
|
||||||
|
private final Color emission;
|
||||||
|
private final double strength;
|
||||||
|
|
||||||
|
public Emissive(Color emission, double strength) {
|
||||||
|
this.emission = emission;
|
||||||
|
this.strength = strength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color surfaceColor(Vector normal, Vector incident, Vector intersection, Pathtracer pathtracer, int depth) {
|
||||||
|
return emission.scale(strength);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package pathtracing.pbr;
|
||||||
|
|
||||||
|
import basics.math.algebra.Vector;
|
||||||
|
import optics.light.Color;
|
||||||
|
import pathtracing.Pathtracer;
|
||||||
|
import shading.Material;
|
||||||
|
|
||||||
|
public abstract class PhysicallyBasedMaterial implements Material {
|
||||||
|
|
||||||
|
public abstract Color surfaceColor(Vector normal, Vector incident, Vector intersection, Pathtracer pathtracer, int depth);
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ public class Scheduler implements AutoCloseable {
|
||||||
|
|
||||||
private static final Scheduler INSTANCE = new Scheduler();
|
private static final Scheduler INSTANCE = new Scheduler();
|
||||||
|
|
||||||
private ExecutorService executorService = Executors.newCachedThreadPool();
|
private final ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
private Scheduler() {
|
private Scheduler() {
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ public class Scheduler implements AutoCloseable {
|
||||||
int tileWidth = buffer.getWidth() / THREADS_PER_SIDE;
|
int tileWidth = buffer.getWidth() / THREADS_PER_SIDE;
|
||||||
int tileHeight = buffer.getHeight() / THREADS_PER_SIDE;
|
int tileHeight = buffer.getHeight() / THREADS_PER_SIDE;
|
||||||
|
|
||||||
ArrayList processors = new ArrayList(totalThreads);
|
var processors = new ArrayList(totalThreads);
|
||||||
|
|
||||||
for (int x = 0; x < THREADS_PER_SIDE; x++) {
|
for (int x = 0; x < THREADS_PER_SIDE; x++) {
|
||||||
int x0 = x * tileWidth;
|
int x0 = x * tileWidth;
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package renderer.canvas;
|
package renderer.canvas;
|
||||||
|
|
||||||
import basics.math.algebra.Vector;
|
|
||||||
import optics.light.Color;
|
import optics.light.Color;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class ContributionBuffer {
|
public class ContributionBuffer {
|
||||||
|
|
||||||
// linear rgb colors
|
// linear rgb colors
|
||||||
private volatile Color[][] buffer;
|
private final Color[][] buffer;
|
||||||
// amount of samples for every pixel
|
// amount of samples for every pixel
|
||||||
private volatile double[][] samples;
|
private final double[][] samples;
|
||||||
|
|
||||||
private int width;
|
private final int width;
|
||||||
private int height;
|
private final int height;
|
||||||
|
|
||||||
private int maxSample;
|
private int maxSample;
|
||||||
|
|
||||||
|
@ -22,15 +23,17 @@ public class ContributionBuffer {
|
||||||
this.buffer = new Color[width][height];
|
this.buffer = new Color[width][height];
|
||||||
this.samples = new double[width][height];
|
this.samples = new double[width][height];
|
||||||
|
|
||||||
|
for (int i = 0; i < width; i++) {
|
||||||
|
Arrays.fill(this.samples[i], 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
for (int y = 0; y < height; y++) {
|
Arrays.fill(this.buffer[x], Color.BLACK);
|
||||||
this.buffer[x][y] = Color.BLACK;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void contribute(int x, int y, Color color) {
|
public void contribute(int x, int y, Color color) {
|
||||||
buffer[x][y] = buffer[x][y].add(color);
|
buffer[x][y] = buffer[x][y].lerp(color, 1.0 / samples[x][y]);
|
||||||
samples[x][y]++;
|
samples[x][y]++;
|
||||||
|
|
||||||
maxSample = Math.max(maxSample, (int) samples[x][y]);
|
maxSample = Math.max(maxSample, (int) samples[x][y]);
|
||||||
|
@ -47,15 +50,13 @@ public class ContributionBuffer {
|
||||||
Color color = buffer[x][y];
|
Color color = buffer[x][y];
|
||||||
color.r = color.g = color.b = 0;
|
color.r = color.g = color.b = 0;
|
||||||
// reset sample count
|
// reset sample count
|
||||||
samples[x][y] = 0;
|
samples[x][y] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getRGB(int x, int y) {
|
private int getRGB(int x, int y) {
|
||||||
Color linearRGB = buffer[x][y].scale(1.0 / samples[x][y]);
|
Color linearRGB = buffer[x][y];
|
||||||
|
|
||||||
linearRGB.colorCorrect();
|
|
||||||
|
|
||||||
int red = (int) (linearRGB.r* 255.0);
|
int red = (int) (linearRGB.r* 255.0);
|
||||||
int green = (int) (linearRGB.g * 255.0);
|
int green = (int) (linearRGB.g * 255.0);
|
||||||
|
|
Reference in New Issue