From e075667cd2dc878dd9dceb07c85719f6712bcda1 Mon Sep 17 00:00:00 2001 From: James Barnett Date: Sun, 2 Jan 2022 18:23:36 +0000 Subject: Implement multi-threaded rendering --- src/index.ts | 84 ++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 36 deletions(-) (limited to 'src/index.ts') diff --git a/src/index.ts b/src/index.ts index f10ef84..5696fe0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,21 +3,16 @@ import {Framebuffer} from './Framebuffer'; import {Plane, Sphere} from './Geometry'; import {Light} from './Light'; import {Material} from './Material'; -import {Raytracer, RaytracerOptions} from './Raytracer'; +import {RaytraceDispatcher} from './RaytraceDispatcher'; +import {RaytraceContext, RaytracerOptions} from './RaytraceContext'; import {Vector} from './Vector'; -function parseOptions(): RaytracerOptions { - return { - shadows: getInputElement('shadows-toggle').checked, - diffuseLighting: getInputElement('diffuse-toggle').checked, - specularLighting: getInputElement('specular-toggle').checked, - reflections: getInputElement('reflections-toggle').checked, - maxRecurseDepth: 5, - maxDrawDistance: 1000, - }; +function render() { + const dispatcher = initDispatcher(parseOptions()); + dispatcher.requestRender(); } -function initRaytracer(options: RaytracerOptions): Raytracer { +function initDispatcher(options: RaytracerOptions): RaytraceDispatcher { const width = 960; const height = 720; const fov = Math.PI / 3; @@ -27,18 +22,16 @@ function initRaytracer(options: RaytracerOptions): Raytracer { const matWhite = new Material(new Colour(102, 102, 77), 0.6, 0.3, 0.1, 50); const matRed = new Material(new Colour(77, 26, 26), 0.9, 0.1, 0.0, 10); const matMirror = new Material(new Colour(193, 193, 193), 0.0, 10, 0.8, 1000); - const matGreen= new Material(new Colour(77, 255, 26), 0.3, 0.1, 0.0, 2); + const matGreen = new Material(new Colour(77, 255, 26), 0.3, 0.1, 0.0, 2); const spheres = [ - new Sphere(new Vector(-3, 0, -16), 2, matWhite), - new Sphere(new Vector(-1, -1.5, -12), 2, matGreen), - new Sphere(new Vector(1.5, -0.5, -18), 3, matRed), - new Sphere(new Vector(7, 5, -18), 4, matMirror), + new Sphere(2, new Vector(-3, 0, -16), matWhite), + new Sphere(2, new Vector(-1, -1.5, -12), matGreen), + new Sphere(3, new Vector(1.5, -0.5, -18), matRed), + new Sphere(4, new Vector(7, 5, -18), matMirror), ]; - const planes = [ - new Plane(-4, 10, -10, -30, 0.7) - ]; + const planes = [new Plane(-4, 10, -10, -30, 0.7)]; const lights = [ new Light(new Vector(-20, 20, 20), 1.5), @@ -46,32 +39,51 @@ function initRaytracer(options: RaytracerOptions): Raytracer { new Light(new Vector(30, 20, 30), 1.7), ]; - return new Raytracer(framebuffer, fov, spheres, planes, lights, options); + const context = new RaytraceContext( + height, + width, + fov, + spheres, + planes, + lights, + options + ); + + return new RaytraceDispatcher(framebuffer, context); } -function render() { - const raytracer = initRaytracer(parseOptions()); - showLoadingIndicator(); - - // Give browser time to repaint - setTimeout(() => { - const startMs = new Date().getTime(); - raytracer.render(); - console.log(`Render took ${new Date().getTime() - startMs}ms`); - hideLoadingIndicator(); - }, 50); +function parseOptions(): RaytracerOptions { + return { + numThreads: getDesiredThreadCount(), + shadows: getInputElement('shadows-toggle').checked, + diffuseLighting: getInputElement('diffuse-toggle').checked, + specularLighting: getInputElement('specular-toggle').checked, + reflections: getInputElement('reflections-toggle').checked, + maxRecurseDepth: 5, + maxDrawDistance: 1000, + }; } function registerEventListeners() { document.getElementById('render')?.addEventListener('click', render); // TODO disable once clicked -} -function showLoadingIndicator() { - document.getElementById('output-wrapper')?.classList.add('loading'); + const threadsSlider = getInputElement('threads'); + threadsSlider.addEventListener('input', () => { + getInputElement('threads-value').textContent = threadsSlider.value; + }); + + const threadToggle = getInputElement('enable-threads-toggle'); + threadToggle.addEventListener('change', () => { + threadsSlider.disabled = !threadToggle.checked; + }); } -function hideLoadingIndicator() { - document.getElementById('output-wrapper')?.classList.remove('loading'); +function getDesiredThreadCount(): number { + if (getInputElement('enable-threads-toggle').checked) { + return Number.parseInt(getInputElement('threads').value); + } else { + return 1; + } } function getInputElement(elementId: string) { -- cgit v1.2.3