I am merging all object of a scene and using another modifier subsequently, this can ttake up to half a minute.
The idea is to move these operations (modify geometries, merge then tessellate) to a web worker, but I get errors as soon as i set up the imports. Is this the best way to proceed?
Note that i am using Angular
/// <reference lib="webworker" />
//import * as THREE from "three";
//import * as BGU from "three/examples/jsm/utils/BufferGeometryUtils.js";
//import { TessellateModifier } from "three/examples/jsm//modifiers/TessellateModifier.js";
//import toonShader from "~shaders/toon-shader";
//import { SceneStore } from "~stores/scene.store";
addEventListener("message", ({ data }) => {
const response = `worker response to ${data}`;
postMessage(response);
});
const wireScene = (scene: any, sceneStore: any): string => {
return "done";
};
I can’t make out much from your brief code. A short live example would be appropriate.
I use a worker for the complex calculation of several geometries. The parameters are passed as an array of { } - objects.
For example, for a number of geometries, the parameters in the array param:
in the main program:
//Assignment for the individual geometries in loop(s) ........
param[ i ] = {
triangleSide: triangleSide,
radius: param[ 0 ].holes[ i1 ][ 2 ], // from first Geo index 0
height: iHeight,
radiusBottom: param[ 0 ].radius, // radius from first Geo index 0
btmDiff: btmDiff[ i ],
topDiff: topDiff[ i ]
}
//..........................................................
worker.postMessage( param );
worker.onmessage = function( e ) {
gc = e.data; // calculated data
for ( let i = 0; i <= count; i ++ ) { // create geometries
geo[ i ] = new BufferGeometry( );
geo[ i ].type = gc[ i ].type;
geo[ i ].ang = gc[ i ].ang;
geo[ i ].div4 = gc[ i ].div4;
// ... further data on geometry
geo[ i ].setIndex( new BufferAttribute( gc[ i ].indices, 1 ) );
geo[ i ].setAttribute( 'position', new BufferAttribute( gc[ i ].positions, 3 ) );
// further calculations for the geometries
...
}
}
in the worker
onmessage = function( e ) {
const param = e.data;
const gc = [];
const buffers = [];
for ( let j = 0; j < param.length; j ++ ) { // calculate geometry values
gc[ j ] = Calculate( param[ j ] );
buffers.push( gc[ j ].positions.buffer );
}
postMessage( gc, buffers );
}
function Calculate( p ) {
indices = [];
positions = [];
// calculation in loop(s) ...
indices[ idx ] = ...
positions[ pIdx ] = ...
//..........................
gc.indices = new Uint32Array( indices );
gc.positions = new Float32Array( positions );
return gc;
}
Hi hofk, I have a live example on github but it’s a bit more extensive. But the part that sends data to the worker and receives from the worker is manageable
//your functions and classes
self.onmessage = (msg) => {
const received datas = msg.data;
//include your code
const result = ...
self.postMessage({data: result});
};
I think I’m doing something similar to what you’re trying to do. My worker is called:
ocean-builder-threaded-worker.js
in the ocean folder. ocean-builder-threaded.js then sends the geometry data created by the worker to ocean-chunk.js, where the geometries are then generated from the data. I use a slightly more extensive worker manager because I distribute the work to 7 workers. You probably won’t need it to that extent. The reason why your worker doesn’t want to do this is, as mentioned, the missing self. I don’t see anything in your worker that triggers it.
For a few connected geometries (my profile picture here shows 3) you don’t need a worker at all. However, if a large number of geometries are involved and the triangle size must therefore be very small, it is no longer possible without a worker.
Using several workers for many partial geometries certainly requires some additional effort. The problem is that the number of geometries can change constantly and within
worker.onmessage = function( e ) { ...
further complex calculations are performed and additional geometries are created. To do this, all geometries geo[ i ] must be retrievable in sequence in the data field geo.
When transfering geometry attributes is is more efficient to take advantage of the fact ArrayBuffers() are ‘transferable’, where the data isn’t copied, just the ownership/visibility of the underlying memory changed.
Hi aardgoose, I usually use SharedArrayBuffers to avoid copies, but I deactivated it in the ocean repo on github because otherwise it wouldn’t work with the guthub server.
That’s why I already use ArrayBuffers instead of SharedArrayBuffers. But I didn’t know that ArrayBuffers also avoid copies. I learned something again there.