troika-three-text: possible to use in a webworker?
When attempting to get troika text to run in a webworker I get the following error:
ReferenceError: document is not defined
at getTextRenderInfo (troika-three-text.js?v=a6a14d45:4775:20)
at Text.sync (troika-three-text.js?v=a6a14d45:5511:9)
Any interest in fixing this?
How are you trying to use it in a worker? Rendering to an OffscreenCanvas? Gimme some context.
Of course - sorry about that!
Yes, I'm rendering to an OffscreenCanvas with a WebGLRendererer ( NOT webGPU ).
It is something like...
const canvas = document.getElementById('game-canvas') as any;
const offscreen = canvas.transferControlToOffscreen();
// const proxy = new ElementProxy(window as any, orbitalEventHandlers, orbitalExtraArgs, (data: any) => {
// gameHandle.handleProxiedEvent(data)
// });
gameHandle.setupGraphics(
offscreen,
window.innerWidth,
window.innerHeight,
window.devicePixelRatio
);
Then in the worker I do:
function createText() {
const text = new Text();
text.text = this.parent.name.toUpperCase();
text.fontSize = 1;
text.rotateX(Math.PI / 2);
text.scale.set(-1, 1, 1);
text.color = 0xffffff;
text.anchorX = 'center';
text.anchorY = 'top';
text.material.opacity = 0.5;
text.sync();
return text;
}
and it fails.
It looks like in: https://github.com/protectwise/troika/blob/d23f360c4316fa782d351151062ea3b0c2629ca1/packages/troika-three-text/src/TextBuilder.js#L167
We can replace document.createElement('canvas') with new OffscreenCanvas perhaps. That is the only reference to document I see.
Makes sense. If I recall, I originally tried using an OffscreenCanvas instead of (or optionally to) the document.createElement('canvas') but there was some issue with that where the SDFs rendered into it would render incorrectly -- maybe a colorspace difference so the color channel values were wrong?
That was a while ago, though, so if you try it out and it works then I'd definitely be open to merging it.
Makes sense. If I recall, I originally tried using an OffscreenCanvas instead of (or optionally to) the document.createElement('canvas') but there was some issue with that where the SDFs rendered into it would render incorrectly -- maybe a colorspace difference so the color channel values were wrong?
Yeah unfortunately you have to set colorspaces a bit more consistently in the worker/offscreen world than in the main thread. It is a bit of a pain. I'll let you know if I figure it out.
I've done a ton more research here over the last few months and:
Makes sense. If I recall, I originally tried using an OffscreenCanvas instead of (or optionally to) the document.createElement('canvas') but there was some issue with that where the SDFs rendered into it would render incorrectly -- maybe a colorspace difference so the color channel values were wrong?
The issue is sometimes the SDFs just don't show up for some reason, and they load in incrementally instead of suddenly which is weird. Some sort of weird issue. Would we be able to use offscreenCanvas behind a flag or something? I currently have a mini fork of troika-three-text just so I can patch this in which is a bit sad ! Maybe we can just toggle some global?
Well it sounds like you've at least got it closer to working than I had. Maybe open a PR with your changes so I can take a look? I'd be 👍 on putting this in behind a flag.
Sure thing - an easy workaround in the meantime I came up with is...
// inside of worker.ts
self.document = {
createElement: (v) => {
if (v !== 'canvas') {
throw new Error("You tried to create a non-canvas element inside of the worker, this is not supported.")
}
return new OffscreenCanvas()
}
}