mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-13 23:48:02 -05:00
819 lines
18 KiB
TypeScript
819 lines
18 KiB
TypeScript
//! bench()
|
|
|
|
// The ray tracer code in this file is written by Adam Burmister. It
|
|
// is available in its original form from:
|
|
//
|
|
// http://labs.flog.nz.co/raytracer/
|
|
//
|
|
// It has been modified slightly by Google to work as a standalone
|
|
// benchmark, but the all the computational code remains
|
|
// untouched. This file also contains a copy of parts of the Prototype
|
|
// JavaScript framework which is used by the ray tracer.
|
|
//
|
|
// It has been further modified by Andrew Morris for use as a benchmark
|
|
// in the ValueScript project.
|
|
|
|
// ------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------
|
|
|
|
// The code below is based on a concatenation of the following files:
|
|
//
|
|
// flog/color.js
|
|
// flog/light.js
|
|
// flog/vector.js
|
|
// flog/ray.js
|
|
// flog/scene.js
|
|
// flog/material/basematerial.js
|
|
// flog/material/solid.js
|
|
// flog/material/chessboard.js
|
|
// flog/shape/baseshape.js
|
|
// flog/shape/sphere.js
|
|
// flog/shape/plane.js
|
|
// flog/intersectioninfo.js
|
|
// flog/camera.js
|
|
// flog/background.js
|
|
// flog/engine.js
|
|
|
|
class Color {
|
|
red;
|
|
green;
|
|
blue;
|
|
|
|
constructor(r = 0, g = 0, b = 0) {
|
|
this.red = r;
|
|
this.green = g;
|
|
this.blue = b;
|
|
}
|
|
|
|
static add(c1: Color, c2: Color) {
|
|
return new Color(
|
|
c1.red + c2.red,
|
|
c1.green + c2.green,
|
|
c1.blue + c2.blue,
|
|
);
|
|
}
|
|
|
|
static addScalar(c1: Color, s: number) {
|
|
let result = new Color(
|
|
c1.red + s,
|
|
c1.green + s,
|
|
c1.blue + s,
|
|
);
|
|
|
|
result.limit();
|
|
|
|
return result;
|
|
}
|
|
|
|
static subtract(c1: Color, c2: Color) {
|
|
return new Color(
|
|
c1.red - c2.red,
|
|
c1.green - c2.green,
|
|
c1.blue - c2.blue,
|
|
);
|
|
}
|
|
|
|
static multiply(c1: Color, c2: Color) {
|
|
return new Color(
|
|
c1.red * c2.red,
|
|
c1.green * c2.green,
|
|
c1.blue * c2.blue,
|
|
);
|
|
}
|
|
|
|
static multiplyScalar(c1: Color, f: number) {
|
|
return new Color(
|
|
c1.red * f,
|
|
c1.green * f,
|
|
c1.blue * f,
|
|
);
|
|
}
|
|
|
|
static divideFactor(c1: Color, f: number) {
|
|
return new Color(
|
|
c1.red / f,
|
|
c1.green / f,
|
|
c1.blue / f,
|
|
);
|
|
}
|
|
|
|
limit() {
|
|
this.red = (this.red > 0.0) ? ((this.red > 1.0) ? 1.0 : this.red) : 0.0;
|
|
this.green = (this.green > 0.0)
|
|
? ((this.green > 1.0) ? 1.0 : this.green)
|
|
: 0.0;
|
|
this.blue = (this.blue > 0.0) ? ((this.blue > 1.0) ? 1.0 : this.blue) : 0.0;
|
|
}
|
|
|
|
distance(color: Color) {
|
|
let d = Math.abs(this.red - color.red) +
|
|
Math.abs(this.green - color.green) + Math.abs(this.blue - color.blue);
|
|
return d;
|
|
}
|
|
|
|
static blend(c1: Color, c2: Color, w: number) {
|
|
return Color.add(
|
|
Color.multiplyScalar(c1, 1 - w),
|
|
Color.multiplyScalar(c2, w),
|
|
);
|
|
}
|
|
|
|
brightness() {
|
|
let r = Math.floor(this.red * 255);
|
|
let g = Math.floor(this.green * 255);
|
|
let b = Math.floor(this.blue * 255);
|
|
return (r * 77 + g * 150 + b * 29) >> 8;
|
|
}
|
|
|
|
toString() {
|
|
let r = Math.floor(this.red * 255);
|
|
let g = Math.floor(this.green * 255);
|
|
let b = Math.floor(this.blue * 255);
|
|
|
|
return "rgb(" + r + "," + g + "," + b + ")";
|
|
}
|
|
}
|
|
|
|
class Light {
|
|
constructor(
|
|
public position: Vector,
|
|
public color: Color,
|
|
public intensity = 10,
|
|
) {}
|
|
|
|
toString() {
|
|
return "Light [" + this.position.x + "," + this.position.y + "," +
|
|
this.position.z + "]";
|
|
}
|
|
}
|
|
|
|
class Vector {
|
|
constructor(
|
|
public x = 0,
|
|
public y = 0,
|
|
public z = 0,
|
|
) {}
|
|
|
|
copy(vector: Vector) {
|
|
this.x = vector.x;
|
|
this.y = vector.y;
|
|
this.z = vector.z;
|
|
}
|
|
|
|
normalize() {
|
|
let m = this.magnitude();
|
|
return new Vector(this.x / m, this.y / m, this.z / m);
|
|
}
|
|
|
|
magnitude() {
|
|
return Math.sqrt((this.x * this.x) + (this.y * this.y) + (this.z * this.z));
|
|
}
|
|
|
|
cross(w: Vector) {
|
|
return new Vector(
|
|
-this.z * w.y + this.y * w.z,
|
|
this.z * w.x - this.x * w.z,
|
|
-this.y * w.x + this.x * w.y,
|
|
);
|
|
}
|
|
|
|
dot(w: Vector) {
|
|
return this.x * w.x + this.y * w.y + this.z * w.z;
|
|
}
|
|
|
|
static add(v: Vector, w: Vector) {
|
|
return new Vector(w.x + v.x, w.y + v.y, w.z + v.z);
|
|
}
|
|
|
|
static subtract(v: Vector, w: Vector) {
|
|
if (!w || !v) throw "Vectors must be defined [" + v + "," + w + "]";
|
|
return new Vector(v.x - w.x, v.y - w.y, v.z - w.z);
|
|
}
|
|
|
|
static multiplyVector(v: Vector, w: Vector) {
|
|
return new Vector(v.x * w.x, v.y * w.y, v.z * w.z);
|
|
}
|
|
|
|
static multiplyScalar(v: Vector, w: number) {
|
|
return new Vector(v.x * w, v.y * w, v.z * w);
|
|
}
|
|
|
|
toString() {
|
|
return "Vector [" + this.x + "," + this.y + "," + this.z + "]";
|
|
}
|
|
}
|
|
|
|
class Ray {
|
|
position;
|
|
direction;
|
|
|
|
constructor(pos: Vector, dir: Vector) {
|
|
this.position = pos;
|
|
this.direction = dir;
|
|
}
|
|
|
|
toString() {
|
|
return "Ray [" + this.position + "," + this.direction + "]";
|
|
}
|
|
}
|
|
|
|
class Scene {
|
|
camera;
|
|
shapes: Shape[];
|
|
lights: Light[];
|
|
background;
|
|
|
|
constructor() {
|
|
this.camera = new Camera(
|
|
new Vector(0, 0, -5),
|
|
new Vector(0, 0, 1),
|
|
new Vector(0, 1, 0),
|
|
);
|
|
this.shapes = [];
|
|
this.lights = [];
|
|
this.background = new Background(
|
|
new Color(0, 0, 0.5),
|
|
0.2,
|
|
);
|
|
}
|
|
}
|
|
|
|
type Material = {
|
|
gloss: number;
|
|
transparency: number;
|
|
reflection: number;
|
|
refraction: number;
|
|
hasTexture: boolean;
|
|
|
|
getColor(u: number, v: number): Color;
|
|
};
|
|
|
|
function wrapUpMaterial(t: number) {
|
|
t = t % 2.0;
|
|
if (t < -1) t += 2.0;
|
|
if (t >= 1) t -= 2.0;
|
|
return t;
|
|
}
|
|
|
|
class SolidMaterial implements Material {
|
|
refraction: number;
|
|
hasTexture: boolean;
|
|
|
|
constructor(
|
|
public color: Color,
|
|
public reflection: number,
|
|
_refraction: number,
|
|
public transparency: number,
|
|
public gloss: number,
|
|
) {
|
|
this.refraction = 0.5; // TODO: Why not use parameter?
|
|
this.hasTexture = false;
|
|
}
|
|
|
|
getColor(_u: number, _v: number) {
|
|
return this.color;
|
|
}
|
|
|
|
toString() {
|
|
return "SolidMaterial [gloss=" + this.gloss + ", transparency=" +
|
|
this.transparency + ", hasTexture=" + this.hasTexture + "]";
|
|
}
|
|
}
|
|
|
|
class ChessboardMaterial implements Material {
|
|
refraction = 0.5;
|
|
hasTexture = true;
|
|
|
|
constructor(
|
|
public colorEven: Color,
|
|
public colorOdd: Color,
|
|
public reflection: number,
|
|
public transparency: number,
|
|
public gloss: number,
|
|
public density: number,
|
|
) {}
|
|
|
|
getColor(u: number, v: number) {
|
|
let t = wrapUpMaterial(u * this.density) * wrapUpMaterial(v * this.density);
|
|
|
|
if (t < 0.0) {
|
|
return this.colorEven;
|
|
} else {
|
|
return this.colorOdd;
|
|
}
|
|
}
|
|
|
|
toString() {
|
|
return "ChessMaterial [gloss=" + this.gloss + ", transparency=" +
|
|
this.transparency + ", hasTexture=" + this.hasTexture + "]";
|
|
}
|
|
}
|
|
|
|
type Shape = {
|
|
material: Material;
|
|
position: Vector;
|
|
intersect(ray: Ray): IntersectionInfo;
|
|
toString(): string;
|
|
};
|
|
|
|
class Sphere implements Shape {
|
|
constructor(
|
|
public position: Vector,
|
|
public radius: number,
|
|
public material: Material,
|
|
) {}
|
|
|
|
intersect(ray: Ray) {
|
|
let info = new IntersectionInfo();
|
|
info.shape = this;
|
|
|
|
let dst = Vector.subtract(
|
|
ray.position,
|
|
this.position,
|
|
);
|
|
|
|
let B = dst.dot(ray.direction);
|
|
let C = dst.dot(dst) - (this.radius * this.radius);
|
|
let D = (B * B) - C;
|
|
|
|
if (D > 0) { // intersection!
|
|
info.isHit = true;
|
|
info.distance = (-B) - Math.sqrt(D);
|
|
info.position = Vector.add(
|
|
ray.position,
|
|
Vector.multiplyScalar(
|
|
ray.direction,
|
|
info.distance,
|
|
),
|
|
);
|
|
info.normal = Vector.subtract(
|
|
info.position,
|
|
this.position,
|
|
).normalize();
|
|
|
|
info.color = this.material.getColor(0, 0);
|
|
} else {
|
|
info.isHit = false;
|
|
}
|
|
return info;
|
|
}
|
|
|
|
toString() {
|
|
return "Sphere [position=" + this.position + ", radius=" + this.radius +
|
|
"]";
|
|
}
|
|
}
|
|
|
|
class Plane implements Shape {
|
|
constructor(
|
|
public position: Vector,
|
|
public d: number,
|
|
public material: Material,
|
|
) {}
|
|
|
|
intersect(ray: Ray) {
|
|
let info = new IntersectionInfo();
|
|
|
|
let Vd = this.position.dot(ray.direction);
|
|
if (Vd == 0) return info; // no intersection
|
|
|
|
let t = -(this.position.dot(ray.position) + this.d) / Vd;
|
|
if (t <= 0) return info;
|
|
|
|
info.shape = this;
|
|
info.isHit = true;
|
|
info.position = Vector.add(
|
|
ray.position,
|
|
Vector.multiplyScalar(
|
|
ray.direction,
|
|
t,
|
|
),
|
|
);
|
|
info.normal = this.position;
|
|
info.distance = t;
|
|
|
|
if (this.material.hasTexture) {
|
|
let vU = new Vector(
|
|
this.position.y,
|
|
this.position.z,
|
|
-this.position.x,
|
|
);
|
|
let vV = vU.cross(this.position);
|
|
let u = info.position.dot(vU);
|
|
let v = info.position.dot(vV);
|
|
info.color = this.material.getColor(u, v);
|
|
} else {
|
|
info.color = this.material.getColor(0, 0);
|
|
}
|
|
|
|
return info;
|
|
}
|
|
|
|
toString() {
|
|
return "Plane [" + this.position + ", d=" + this.d + "]";
|
|
}
|
|
}
|
|
|
|
class IntersectionInfo {
|
|
isHit = false;
|
|
hitCount = 0;
|
|
shape: Shape | null = null;
|
|
position: Vector | null = null;
|
|
normal: Vector | null = null;
|
|
color;
|
|
distance: number | null = null;
|
|
|
|
constructor() {
|
|
this.color = new Color(0, 0, 0);
|
|
}
|
|
|
|
toString() {
|
|
return "Intersection [" + this.position + "]";
|
|
}
|
|
}
|
|
|
|
class Camera {
|
|
equator;
|
|
screen;
|
|
|
|
constructor(
|
|
public position: Vector,
|
|
public lookAt: Vector,
|
|
public up: Vector,
|
|
) {
|
|
this.equator = lookAt.normalize().cross(this.up);
|
|
this.screen = Vector.add(
|
|
this.position,
|
|
this.lookAt,
|
|
);
|
|
}
|
|
|
|
getRay(vx: number, vy: number) {
|
|
let pos = Vector.subtract(
|
|
this.screen,
|
|
Vector.subtract(
|
|
Vector.multiplyScalar(this.equator, vx),
|
|
Vector.multiplyScalar(this.up, vy),
|
|
),
|
|
);
|
|
pos.y = pos.y * -1;
|
|
let dir = Vector.subtract(
|
|
pos,
|
|
this.position,
|
|
);
|
|
|
|
let ray = new Ray(pos, dir.normalize());
|
|
|
|
return ray;
|
|
}
|
|
|
|
toString() {
|
|
return "Ray []";
|
|
}
|
|
}
|
|
|
|
class Background {
|
|
constructor(
|
|
public color: Color,
|
|
public ambience: number,
|
|
) {}
|
|
}
|
|
|
|
type EngineOptions = {
|
|
canvasWidth: number;
|
|
canvasHeight: number;
|
|
pixelWidth: number;
|
|
pixelHeight: number;
|
|
renderDiffuse: boolean;
|
|
renderHighlights: boolean;
|
|
renderShadows: boolean;
|
|
renderReflections: boolean;
|
|
rayDepth: number;
|
|
};
|
|
|
|
class Engine {
|
|
canvas: unknown = null; /* 2d context we can render to */
|
|
|
|
// Variable used to hold a number that can be used to verify that
|
|
// the scene was ray traced correctly.
|
|
checkNumber = 0;
|
|
|
|
constructor(public options: EngineOptions) {
|
|
this.options.canvasHeight /= this.options.pixelHeight;
|
|
this.options.canvasWidth /= this.options.pixelWidth;
|
|
|
|
/* TODO: dynamically include other scripts */
|
|
}
|
|
|
|
setPixel(x: number, y: number, color: Color) {
|
|
let _pxW, _pxH;
|
|
_pxW = this.options.pixelWidth;
|
|
_pxH = this.options.pixelHeight;
|
|
|
|
if (this.canvas) {
|
|
throw new Error("Not implemented: canvas");
|
|
// this.canvas.fillStyle = color.toString();
|
|
// this.canvas.fillRect(x * pxW, y * pxH, pxW, pxH);
|
|
} else {
|
|
if (x === y) {
|
|
this.checkNumber += color.brightness();
|
|
}
|
|
// print(x * pxW, y * pxH, pxW, pxH);
|
|
}
|
|
}
|
|
|
|
renderScene(scene: Scene, canvas: unknown) {
|
|
this.checkNumber = 0;
|
|
/* Get canvas */
|
|
if (canvas) {
|
|
throw new Error("Not implemented: canvas");
|
|
// this.canvas = canvas.getContext("2d");
|
|
} else {
|
|
this.canvas = null;
|
|
}
|
|
|
|
let canvasHeight = this.options.canvasHeight;
|
|
let canvasWidth = this.options.canvasWidth;
|
|
|
|
for (let y = 0; y < canvasHeight; y++) {
|
|
for (let x = 0; x < canvasWidth; x++) {
|
|
let yp = y * 1.0 / canvasHeight * 2 - 1;
|
|
let xp = x * 1.0 / canvasWidth * 2 - 1;
|
|
|
|
let ray = scene.camera.getRay(xp, yp);
|
|
|
|
let color = this.getPixelColor(ray, scene);
|
|
|
|
this.setPixel(x, y, color);
|
|
}
|
|
}
|
|
if (this.checkNumber !== 2321) {
|
|
throw new Error("Scene rendered incorrectly");
|
|
}
|
|
}
|
|
|
|
getPixelColor(ray: Ray, scene: Scene) {
|
|
let info = this.testIntersection(ray, scene, null);
|
|
if (info.isHit) {
|
|
let color = this.rayTrace(info, ray, scene, 0);
|
|
return color;
|
|
}
|
|
return scene.background.color;
|
|
}
|
|
|
|
testIntersection(ray: Ray, scene: Scene, exclude: Shape | null) {
|
|
let hits = 0;
|
|
let best = new IntersectionInfo();
|
|
best.distance = 2000;
|
|
|
|
for (let i = 0; i < scene.shapes.length; i++) {
|
|
let shape = scene.shapes[i];
|
|
|
|
if (!shapesEq(shape, exclude)) {
|
|
let info = shape.intersect(ray);
|
|
if (
|
|
info.isHit && info.distance! >= 0 && info.distance! < best.distance!
|
|
) {
|
|
best = info;
|
|
hits++;
|
|
}
|
|
}
|
|
}
|
|
best.hitCount = hits;
|
|
return best;
|
|
}
|
|
|
|
getReflectionRay(P: Vector, N: Vector, V: Vector) {
|
|
let c1 = -N.dot(V);
|
|
let R1 = Vector.add(
|
|
Vector.multiplyScalar(N, 2 * c1),
|
|
V,
|
|
);
|
|
return new Ray(P, R1);
|
|
}
|
|
|
|
rayTrace(info: IntersectionInfo, ray: Ray, scene: Scene, depth: number) {
|
|
// Calc ambient
|
|
let color = Color.multiplyScalar(
|
|
info.color,
|
|
scene.background.ambience,
|
|
);
|
|
let _oldColor = color;
|
|
let shininess = Math.pow(10, info.shape!.material.gloss + 1);
|
|
|
|
for (let i = 0; i < scene.lights.length; i++) {
|
|
let light = scene.lights[i];
|
|
|
|
// Calc diffuse lighting
|
|
let v = Vector.subtract(
|
|
light.position,
|
|
info.position!,
|
|
).normalize();
|
|
|
|
if (this.options.renderDiffuse) {
|
|
let L = v.dot(info.normal!);
|
|
if (L > 0.0) {
|
|
color = Color.add(
|
|
color,
|
|
Color.multiply(
|
|
info.color,
|
|
Color.multiplyScalar(
|
|
light.color,
|
|
L,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
// The greater the depth the more accurate the colours, but
|
|
// this is exponentially (!) expensive
|
|
if (depth <= this.options.rayDepth) {
|
|
// calculate reflection ray
|
|
if (
|
|
this.options.renderReflections && info.shape!.material.reflection > 0
|
|
) {
|
|
let reflectionRay = this.getReflectionRay(
|
|
info.position!,
|
|
info.normal!,
|
|
ray.direction,
|
|
);
|
|
let refl = this.testIntersection(reflectionRay, scene, info.shape);
|
|
|
|
if (refl.isHit && refl.distance! > 0) {
|
|
refl.color = this.rayTrace(refl, reflectionRay, scene, depth + 1);
|
|
} else {
|
|
refl.color = scene.background.color;
|
|
}
|
|
|
|
color = Color.blend(
|
|
color,
|
|
refl.color,
|
|
info.shape!.material.reflection,
|
|
);
|
|
}
|
|
|
|
// Refraction
|
|
/* TODO */
|
|
}
|
|
|
|
/* Render shadows and highlights */
|
|
|
|
let shadowInfo = new IntersectionInfo();
|
|
|
|
if (this.options.renderShadows) {
|
|
let shadowRay = new Ray(info.position!, v);
|
|
|
|
shadowInfo = this.testIntersection(shadowRay, scene, info.shape);
|
|
if (
|
|
shadowInfo.isHit &&
|
|
!shapesEq(
|
|
shadowInfo.shape,
|
|
info.shape,
|
|
) /*&& shadowInfo.shape.type != 'PLANE'*/
|
|
) {
|
|
let vA = Color.multiplyScalar(color, 0.5);
|
|
let dB = 0.5 * Math.pow(shadowInfo.shape!.material.transparency, 0.5);
|
|
color = Color.addScalar(vA, dB);
|
|
}
|
|
}
|
|
|
|
// Phong specular highlights
|
|
if (
|
|
this.options.renderHighlights && !shadowInfo.isHit &&
|
|
info.shape!.material.gloss > 0
|
|
) {
|
|
let Lv = Vector.subtract(
|
|
info.shape!.position,
|
|
light.position,
|
|
).normalize();
|
|
|
|
let E = Vector.subtract(
|
|
scene.camera.position,
|
|
info.shape!.position,
|
|
).normalize();
|
|
|
|
let H = Vector.subtract(
|
|
E,
|
|
Lv,
|
|
).normalize();
|
|
|
|
let glossWeight = Math.pow(Math.max(info.normal!.dot(H), 0), shininess);
|
|
color = Color.add(
|
|
Color.multiplyScalar(
|
|
light.color,
|
|
glossWeight,
|
|
),
|
|
color,
|
|
);
|
|
}
|
|
}
|
|
color.limit();
|
|
return color;
|
|
}
|
|
}
|
|
|
|
function shapesEq(left: Shape | null, right: Shape | null) {
|
|
if (left === null || right === null) {
|
|
return left === right;
|
|
}
|
|
|
|
// TODO: class instance comparison
|
|
return left.toString() === right.toString();
|
|
}
|
|
|
|
export default function renderScene() {
|
|
let scene = new Scene();
|
|
|
|
scene.camera = new Camera(
|
|
new Vector(0, 0, -15),
|
|
new Vector(-0.2, 0, 5),
|
|
new Vector(0, 1, 0),
|
|
);
|
|
|
|
scene.background = new Background(
|
|
new Color(0.5, 0.5, 0.5),
|
|
0.4,
|
|
);
|
|
|
|
let sphere = new Sphere(
|
|
new Vector(-1.5, 1.5, 2),
|
|
1.5,
|
|
new SolidMaterial(
|
|
new Color(0, 0.5, 0.5),
|
|
0.3,
|
|
0.0,
|
|
0.0,
|
|
2.0,
|
|
),
|
|
);
|
|
|
|
let sphere1 = new Sphere(
|
|
new Vector(1, 0.25, 1),
|
|
0.5,
|
|
new SolidMaterial(
|
|
new Color(0.9, 0.9, 0.9),
|
|
0.1,
|
|
0.0,
|
|
0.0,
|
|
1.5,
|
|
),
|
|
);
|
|
|
|
let plane = new Plane(
|
|
new Vector(0.1, 0.9, -0.5).normalize(),
|
|
1.2,
|
|
new ChessboardMaterial(
|
|
new Color(1, 1, 1),
|
|
new Color(0, 0, 0),
|
|
0.2,
|
|
0.0,
|
|
1.0,
|
|
0.7,
|
|
),
|
|
);
|
|
|
|
scene.shapes.push(plane);
|
|
scene.shapes.push(sphere);
|
|
scene.shapes.push(sphere1);
|
|
|
|
let light = new Light(
|
|
new Vector(5, 10, -1),
|
|
new Color(0.8, 0.8, 0.8),
|
|
);
|
|
|
|
let light1 = new Light(
|
|
new Vector(-3, 5, -15),
|
|
new Color(0.8, 0.8, 0.8),
|
|
100,
|
|
);
|
|
|
|
scene.lights.push(light);
|
|
scene.lights.push(light1);
|
|
|
|
let imageWidth = 100; // $F('imageWidth');
|
|
let imageHeight = 100; // $F('imageHeight');
|
|
let pixelSize = [5, 5]; // $F('pixelSize').split(',');
|
|
let renderDiffuse = true; // $F('renderDiffuse');
|
|
let renderShadows = true; // $F('renderShadows');
|
|
let renderHighlights = true; // $F('renderHighlights');
|
|
let renderReflections = true; // $F('renderReflections');
|
|
let rayDepth = 2; //$F('rayDepth');
|
|
|
|
let raytracer = new Engine(
|
|
{
|
|
canvasWidth: imageWidth,
|
|
canvasHeight: imageHeight,
|
|
pixelWidth: pixelSize[0],
|
|
pixelHeight: pixelSize[1],
|
|
"renderDiffuse": renderDiffuse,
|
|
"renderHighlights": renderHighlights,
|
|
"renderShadows": renderShadows,
|
|
"renderReflections": renderReflections,
|
|
"rayDepth": rayDepth,
|
|
},
|
|
);
|
|
|
|
raytracer.renderScene(scene, null /* , 0 */);
|
|
}
|