From 37d1051838621c72cbd38928e9f2f3e0b93dc477 Mon Sep 17 00:00:00 2001 From: Peaceultime Date: Mon, 22 Nov 2021 16:57:57 +0100 Subject: [PATCH] First generation of points and debug rendering --- src/main.mjs | 15 ++++++--- src/modules/renderer/renderer.mjs | 56 +++++++++++++++++++++++++++---- src/utils/workerUtils.mjs | 46 +++++++++++++++++++++---- src/workers/base.mjs | 31 ++++++++++++++--- src/workers/renderer.mjs | 10 ++++++ 5 files changed, 136 insertions(+), 22 deletions(-) create mode 100644 src/workers/renderer.mjs diff --git a/src/main.mjs b/src/main.mjs index e0f042f..38bdfb8 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -8,10 +8,15 @@ import Renderer from "./modules/renderer/renderer.mjs"; globalThis.TIMINGS = DEBUG && localStorage.getItem("timings"); globalThis.RELEASE = !DEBUG; - /*const renderer = new Renderer(); - renderer.render();*/ - - const thread = new Thread("./workers/base.mjs", "backend", true); + const thread = new Thread("./workers/base.mjs", "model", true); await thread.setup(); - const grid = await thread.test.fillArr([{x: 20, y: 20, seed: 0, jitter: 3 }]); + const settings = { x: 200, y: 200, seed: 0, jitter: 0.5, width: window.innerWidth, height: window.innerHeight }; + const grid = new Float32Array(await thread.model.fillArr(settings)); + console.log(grid); + + const view = new Float32Array(await thread.view.lerpToViewport(grid.buffer, settings)); + console.log(view); + + Renderer.init(); + Renderer.initGrid(view, settings); })(); \ No newline at end of file diff --git a/src/modules/renderer/renderer.mjs b/src/modules/renderer/renderer.mjs index e45a856..183ce95 100644 --- a/src/modules/renderer/renderer.mjs +++ b/src/modules/renderer/renderer.mjs @@ -3,13 +3,57 @@ import { Thread } from "../../utils/workerUtils.mjs"; class Renderer { - static async init() + static async init(threaded) { - const renderer_thread = new Thread("../../workers/renderer.mjs", "renderer", true); - await renderer_thread.setup(); - const offcanvas = document.createElement("canvas").transferControlToOffscreen(); - await renderer_thread.render.init([offcanvas, window.innerWidth, window.innerHeight], [offcanvas]); + this._threaded = threaded === undefined ? false : threaded; + if(threaded) + { + this._renderer_thread = new Thread("../../workers/renderer.mjs", "view", true); + await this._renderer_thread.setup(); + this._canvas = document.createElement("canvas"); + const offcanvas = this._canvas.transferControlToOffscreen(); + await this._renderer_thread.render.init(offcanvas, window.innerWidth, window.innerHeight); + } + else + { + this._renderer = new Three.WebGLRenderer(); + this._renderer.setSize(window.innerWidth, window.innerHeight); + document.body.appendChild(this._renderer.domElement); + + this._width = window.innerWidth; + this._height = window.innerHeight; + + this._scene = new Three.Scene(); + this._camera = new Three.OrthographicCamera(this._width / - 2, this._width / 2, this._height / 2, this._height / - 2, 0.1, 1000); + + Renderer.render(); + } + } + static render() + { + if(this._threaded) + return; + + this._rAF = requestAnimationFrame(Renderer.render.bind(Renderer)); + + this._renderer.render(this._scene, this._camera); + } + static async initGrid(grid, settings) //Share the list of cell and the resolution in the model with the view + { + if(this._threaded) + { + //We can share the cells with the rendering thread because it will only be used as read-only to create the point data + await this._renderer_thread.view.lerpToView(grid, settings); + } + else + { + const geometry = new Three.BufferGeometry(); + geometry.setAttribute('position', new Three.Float32BufferAttribute(grid, 3)); + + const points = new Three.Points(geometry); + this._scene.add(points); + } } } -export default Renderer; +export default Renderer; \ No newline at end of file diff --git a/src/utils/workerUtils.mjs b/src/utils/workerUtils.mjs index d9e6c13..f8e389a 100644 --- a/src/utils/workerUtils.mjs +++ b/src/utils/workerUtils.mjs @@ -14,8 +14,19 @@ const Constants = { WAKEUP: 1, SETUP: 2, CALL: 3, - TERMINATE: 4 + TERMINATE: 4, }, + TRANSFERABLE: [ + ArrayBuffer, + MessagePort, + ReadableStream, + WritableStream, + TransformStream, + AudioData, + ImageBitmap, + VideoFrame, + OffscreenCanvas, + ] }; function cleanUp(thread) @@ -39,6 +50,28 @@ function request(thread, req, shared) return thread._promise; } +function getTransferables(args) +{ + const arr = []; + + if(!Array.isArray(args)) + args = [args]; + + for(let i = 0; i < args.length; ++i) + { + for(let j = 0; j < Constants.TRANSFERABLE.length; ++j) + { + if(args[i] instanceof Constants.TRANSFERABLE[j]) + { + arr.push(args[i]); + break; + } + } + } + + return arr.length === 0 ? undefined : arr; +} + function parseReturns(data) { if(data.length != 2) @@ -53,7 +86,7 @@ function parseReturns(data) } function wrapper(thread, mod, fn) { - return function(args, shared) + return function(...args) { if(globalThis.TIMINGS) { @@ -61,7 +94,7 @@ function wrapper(thread, mod, fn) thread._calledMod = mod; thread._calledFn = fn; } - return request(thread, [Constants.REQUEST.CALL, mod, fn, args], shared); + return request(thread, [Constants.REQUEST.CALL, mod, fn, [...args]], getTransferables([...args])); } } @@ -115,7 +148,7 @@ const Thread = Object.freeze(class */ async setup() { - const result = await request(this, [Constants.REQUEST.SETUP]); + const result = await request(this, [Constants.REQUEST.SETUP], undefined); if(result) { @@ -142,7 +175,7 @@ const Thread = Object.freeze(class function send(ret) { globalThis.VERBOSE && console.debug(`Sending `, ret, ` back to the main thread`); - postMessage([Constants.STATE.OK, ret]); + postMessage([Constants.STATE.OK, ret], getTransferables(ret)); } class Process @@ -176,7 +209,8 @@ class Process break; case Constants.REQUEST.CALL: - send(Process._customFn[e.data[1]][e.data[2]](...e.data[3])); + const args = e.data[3]; + send(Process._customFn[e.data[1]][e.data[2]](...args)); break; case Constants.REQUEST.TERMINATE: diff --git a/src/workers/base.mjs b/src/workers/base.mjs index df3b123..a9df0ed 100644 --- a/src/workers/base.mjs +++ b/src/workers/base.mjs @@ -1,17 +1,38 @@ import { Process } from "../utils/workerUtils.mjs"; import Noise from '../libs/alea.mjs' +import Delaunator from '../libs/delaunator.mjs' //Settings contains x, y depth, seed, jitter function fillArr(settings) { const noise = Noise(settings.seed); - const arr = new Float32Array(settings.x * settings.y * 2); - for(let i = arr.length - 1; i >= 0; --i) + const grid = new Float32Array(settings.x * settings.y * 2); + for(let i = grid.length * 2 - 2; i > 0; i -= 2) { - const _x = i % settings.x; - const _y = (i - _x) / settings.x; + const _x = i / 2 % settings.x; + const _y = (i / 2 - _x) / settings.x; + + grid[i] = _x + (noise() - 0.5) * settings.jitter; + grid[i + 1] = _y + (noise() - 0.5) * settings.jitter; } + + return grid.buffer; +} + +function lerpToViewport(buffer, settings) +{ + const size = settings.x * settings.y; + const grid = new Float32Array(buffer); + const view = new Float32Array(size * 3); + for(let i = size - 1; i >= 0; --i) + { + view[i * 3] = settings.width * grid[i * 2] / settings.x - settings.width / 2; + view[i * 3 + 1] = settings.height * grid[i * 2 + 1] / settings.y - settings.height / 2; + view[i * 3 + 2] = -3; + } + return view.buffer; } //Process.register is the equivalent of export -Process.register("test", [fillArr]); +Process.register("model", [fillArr]); +Process.register("view", [lerpToViewport]); diff --git a/src/workers/renderer.mjs b/src/workers/renderer.mjs new file mode 100644 index 0000000..26426f0 --- /dev/null +++ b/src/workers/renderer.mjs @@ -0,0 +1,10 @@ +import { Process } from "../utils/workerUtils.mjs"; +import * as Three from '../libs/three.mjs' + +class Renderer +{ + static init(canvas, width, height) +} + +//Process.register is the equivalent of export +Process.register("render", [Renderer.init]);