Fix some issues, add the mesh rendering. General code improvements

This commit is contained in:
Clément Pons 2022-12-12 17:37:35 +01:00
parent e4217d3f4d
commit 0410e3d709
4 changed files with 119 additions and 48 deletions

View File

@ -1,9 +1,11 @@
import { Thread, supportThreads } from "./utils/workerUtils.mjs"; import { Thread, supportThreads } from "./utils/workerUtils.mjs";
import Renderer from "./modules/renderer/renderer.mjs"; import Renderer from "./modules/renderer/renderer.mjs";
import Noise from '../libs/alea.mjs'
import Delaunator from 'https://cdn.skypack.dev/delaunator@5.0.0';
(async function() (async function()
{ {
globalThis.DEBUG = localStorage.getItem("debug"); globalThis.DEBUG = !!localStorage.getItem("debug");
globalThis.VERBOSE = DEBUG && localStorage.getItem("verbose"); globalThis.VERBOSE = DEBUG && localStorage.getItem("verbose");
globalThis.TIMINGS = DEBUG && localStorage.getItem("timings"); globalThis.TIMINGS = DEBUG && localStorage.getItem("timings");
globalThis.RELEASE = !DEBUG; globalThis.RELEASE = !DEBUG;
@ -11,15 +13,17 @@ import Renderer from "./modules/renderer/renderer.mjs";
const thread = new Thread("./workers/base.mjs", "model", true); const thread = new Thread("./workers/base.mjs", "model", true);
await thread.setup(); await thread.setup();
const settings = { x: 200, y: 200, seed: 0, jitter: 0.5, width: window.innerWidth, height: window.innerHeight }; //await new Promise(r => setTimeout(r, 3000));
await thread.model.generatePoints(settings);
await thread.model.generateTriangles(settings);
const delaunay = await thread.debug.getDelaunay(); const settings = { model: { x: 50, y: 25, seed: 0, jitter: 0.2, }, view: { width: window.innerWidth, height: window.innerHeight, }, };
console.log(delaunay); await thread.global.updateSettings(settings);
const view = new Float32Array(await thread.view.lerpToViewport(settings)); await thread.model.generateTriangles();
const view = await thread.view.lerpToViewport();
const debug = await thread.debug.getAll();
Renderer.init(); Renderer.init();
Renderer.initGrid(view, settings); Renderer.initGrid(view.position, view.vertices);
})(); })();

View File

@ -23,8 +23,11 @@ class Renderer
this._width = window.innerWidth; this._width = window.innerWidth;
this._height = window.innerHeight; this._height = window.innerHeight;
this._clock = new Three.Clock();
this._scene = new Three.Scene(); 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); this._camera = new Three.OrthographicCamera(0, this._width, 0, this._height, 0.1, 1000);
this._camera.zoom = 0.98;
this._camera.updateProjectionMatrix();
Renderer.render(); Renderer.render();
} }
@ -36,22 +39,30 @@ class Renderer
this._rAF = requestAnimationFrame(Renderer.render.bind(Renderer)); this._rAF = requestAnimationFrame(Renderer.render.bind(Renderer));
/*this._camera.zoom = 1 + (0.5 + Math.sin(this._clock.getElapsedTime()) / 2) * 5;
this._camera.updateProjectionMatrix();*/
this._renderer.render(this._scene, this._camera); 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 static async initGrid(position, vertices) //Share the list of cell and the resolution in the model with the view
{ {
if(this._threaded) 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 //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); await this._renderer_thread.view.lerpToView(position, settings);
} }
else else
{ {
const geometry = new Three.BufferGeometry(); const geometry = new Three.BufferGeometry();
geometry.setAttribute('position', new Three.Float32BufferAttribute(grid, 3)); geometry.setIndex( new Three.Uint32BufferAttribute( vertices, 1 ) );
geometry.setAttribute('position', new Three.Float32BufferAttribute( position, 3));
const points = new Three.Points(geometry); const material = new Three.MeshBasicMaterial( { color: 0xff0000, wireframe: true, } );
this._scene.add(points); const mesh = new Three.Mesh( geometry, material );
this._scene.add( mesh );
/*const points = new Three.Points( geometry, new Three.PointsMaterial( { size: 3.0 } ) );
this._scene.add( points );*/
} }
} }
} }

View File

@ -9,12 +9,13 @@ const Constants = {
WAITING: 1, WAITING: 1,
OK: 2, OK: 2,
ERROR: 3, ERROR: 3,
LOG: 4,
}, },
REQUEST: { REQUEST: {
WAKEUP: 1, WAKEUP: 1,
SETUP: 2, SETUP: 2,
CALL: 3, CALL: 3,
TERMINATE: 4, TERMINATE: 4
}, },
TRANSFERABLE: [ TRANSFERABLE: [
ArrayBuffer, ArrayBuffer,
@ -101,6 +102,17 @@ function wrapper(thread, mod, fn)
function onmessage(thread) function onmessage(thread)
{ {
return function(e) { return function(e) {
if(e.data[0] === Constants.STATE.LOG)
{
globalThis.VERBOSE && console.debug(ret);
return;
}
if(e.data[0] === Constants.STATE.ERROR)
{
console.error(e.data[1]);
return;
}
const ret = parseReturns(e.data); const ret = parseReturns(e.data);
globalThis.VERBOSE && console.debug(`Received message from ${thread._name} containing `, ret); globalThis.VERBOSE && console.debug(`Received message from ${thread._name} containing `, ret);
globalThis.TIMINGS && thread._calledFn !== "" && console.timeEnd("Measuring " + thread._calledMod + "." + thread._calledFn); globalThis.TIMINGS && thread._calledFn !== "" && console.timeEnd("Measuring " + thread._calledMod + "." + thread._calledFn);
@ -178,6 +190,16 @@ function send(ret)
postMessage([Constants.STATE.OK, ret], getTransferables(ret)); postMessage([Constants.STATE.OK, ret], getTransferables(ret));
} }
function error(err)
{
postMessage([Constants.STATE.ERROR, err]);
}
function log(msg)
{
postMessage([Constants.STATE.LOG, msg]);
}
class Process class Process
{ {
static _isSetup = false; static _isSetup = false;
@ -187,10 +209,11 @@ class Process
Process._isSetup = true; Process._isSetup = true;
Process._customFn = {}; Process._customFn = {};
globalThis.onmessage = Process.onmessage; globalThis.onmessage = Process.onmessage;
globalThis.onerror = Process.onerror;
} }
static onmessage(e) static onmessage(e)
{ {
globalThis.VERBOSE && console.debug(`Received `, e.data); globalThis.VERBOSE && log(`Received `, e.data);
if(e && e.data) if(e && e.data)
{ {
switch(e.data[0]) switch(e.data[0])
@ -210,7 +233,14 @@ class Process
case Constants.REQUEST.CALL: case Constants.REQUEST.CALL:
const args = e.data[3]; const args = e.data[3];
try
{
send(Process._customFn[e.data[1]][e.data[2]](...args)); send(Process._customFn[e.data[1]][e.data[2]](...args));
}
catch(e)
{
error(e);
}
break; break;
case Constants.REQUEST.TERMINATE: case Constants.REQUEST.TERMINATE:

View File

@ -4,33 +4,37 @@ import Delaunator from 'https://cdn.skypack.dev/delaunator@5.0.0';
let settings = {}; let settings = {};
const model = {}; const model = {};
const view = {};
//Settings contains x, y, seed, jitter function lerp(a, b, x)
function generatePoints(settings)
{ {
const noise = Noise(settings.seed); return a + (b - a) * x;
const grid = new Float32Array(settings.x * settings.y * 2); }
function inverse_lerp(a, b, x)
{
return (x - a) / (b - a);
}
//Settings model contains x, y, seed, jitter
function generateTriangles()
{
const rand = Noise(settings.model.seed);
const grid = new Float32Array(settings.model.x * settings.model.y * 2);
for(let i = grid.length * 2 - 2; i > 0; i -= 2) for(let i = grid.length * 2 - 2; i > 0; i -= 2)
{ {
const _x = i / 2 % settings.x; const _x = i / 2 % settings.model.x;
const _y = (i / 2 - _x) / settings.x; const _y = (i / 2 - _x) / settings.model.x;
grid[i] = _x + (noise() - 0.5) * settings.jitter; const angle = lerp(0, Math.PI * 2, rand());
grid[i + 1] = _y + (noise() - 0.5) * settings.jitter; const magnitude = lerp(0, settings.model.jitter, rand());
grid[i ] = _x + Math.sin(angle) * magnitude;
grid[i + 1] = _y + Math.cos(angle) * magnitude;
} }
model.grid = grid; model.delaunay = new Delaunator(grid);
} }
function generateTriangles(settings) function generateVoronoi()
{
if(!model.hasOwnProperty("grid"))
generatePoints(settings);
const delaunay = new Delaunator(model.grid);
model.delaunay = delaunay;
}
function generateVoronoi(settings)
{ {
function circumcenter(a, b, c) function circumcenter(a, b, c)
{ {
@ -44,30 +48,52 @@ function generateVoronoi(settings)
]; ];
} }
const coords = model.delaunay.coords;
const tri = model.delaunay.triangles;
for(let i = model.delaunay.trianglesLen - 1; i >= 0; --i)
{
tri[]
}
} }
function getDelaunay() function getDelaunay()
{ {
return model.delaunay; return model.delaunay;
} }
function getAll()
function lerpToViewport(settings)
{ {
const size = settings.x * settings.y; return { model: model, view: view };
const grid = model.grid; }
const view = new Float32Array(size * 3);
//Settings view contains width & height
function lerpToViewport()
{
const size = settings.model.x * settings.model.y;
const grid = model.delaunay.coords;
view.grid = new Float32Array(size * 3);
for(let i = size - 1; i >= 0; --i) for(let i = size - 1; i >= 0; --i)
{ {
view[i * 3] = settings.width * grid[i * 2] / settings.x - settings.width / 2; view.grid[i * 3 ] = lerp(0, settings.view.width , inverse_lerp(0, settings.model.x - 1, grid[i * 2 ]));
view[i * 3 + 1] = settings.height * grid[i * 2 + 1] / settings.y - settings.height / 2; view.grid[i * 3 + 1] = lerp(0, settings.view.height, inverse_lerp(0, settings.model.y - 1, grid[i * 2 + 1]));
view[i * 3 + 2] = -3; view.grid[i * 3 + 2] = -3;
} }
return view.buffer;
return { position: view.grid, vertices: model.delaunay.triangles };
} }
//Process.register is the equivalent of export //Process.register is the equivalent of export
Process.register("model", [generatePoints, generateTriangles]); Process.register("model", [generateTriangles]);
Process.register("view", [lerpToViewport]); Process.register("view", [lerpToViewport]);
Process.register("debug", [getDelaunay]); function updateSettings(s)
{
const old_settings = settings;
settings = s;
//Check which property has change and regenerate the appropriate objects.
}
Process.register("global", [updateSettings]);
Process.register("debug", [getDelaunay, getAll]);