-
-
Notifications
You must be signed in to change notification settings - Fork 35.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
requestAnimationFrame called on "self" might not work on multi-window environments #24549
Comments
I think this is the best solution. |
This is a problem of |
@Mugen87 The reality is that the use case that I present in the original message behaves exactly the same way on a normal browser + vanilla js. Consider the following example directly adapted from the three.js docs: const child = window.open('', 'newwindow', 'width=300,height=250');
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, 300 / 250, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize( 300, 250 );
child.document.body.appendChild( renderer.domElement );
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5;
function animate() {
requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
};
animate(); Here, the only difference is that the renderer's canvas is being mounted on the child window's document. Sure enough, when the parent window is minimized, or occluded by another (or otherwise not visible), the child window stops the animation loop, even though this one is still visible. This is exactly what happens when using setAnimationLoop in my use case. Here it's simply fixed by... child.requestAnimationFrame( animate ); ...which can't be done when using the now recommended setAnimationLoop. However, every scenario would work if the WebGLRenderer set the WebGLAnimation context as "_canvas.ownerDocument.defaultView". I believe it only makes sense to have the animation callback fired in the window that contains the canvas (of course, if the window exists and the canvas is provided). Most application won't ever encounter this issue, since it's very common to only use isolated window contexts (for example, in this case having children windows with their own script tags that manage their own renderers, scenes, etc...). However, as previously mentioned, this makes it very hard to share data back and forth (for context, in my particular case I'm managing streaming sensor data that I wanted to visualize in a separated window). If you guys consider this particular use case too niche and believe my workarounds are enough (as per LeviPesin's recommendation, which I appreciate), that's OK, I merely wanted to provide feedback and suggest a possible improvement based on my experience with the library. I don't see how that's inappropriate: don't assume I expect things to just work, especially when I've provided plenty enough evidence that I understand what the issue is, possible workarounds and a potential solution. Thanks and kind regards. ~Sky |
Seems fine to me 👍 |
Is your feature request related to a problem? Please describe.
On a NW.js application which runs in separated context mode, the global window object corresponds to a background, invisible window where requestAnimationFrame never fires. Additional windows spawned using the NW.js API have their own window variable (different from global.window). This causes problems with this line:
three.js/src/renderers/WebGLRenderer.js
Line 951 in 8de7680
Since "self" will be pointing to the global window (background, invisible), the animation callback will never be triggered.
Describe the solution you'd like
A mechanism for the WebGLRenderer to set a custom window object, rather than having the global self hard-coded. For instance:
Describe alternatives you've considered
1 -> Overwrite the window.requestAnimationFrame function, so that it's executed by another window: this is very hackish and only works with one window, so if my application spawns two, each with a three.js canvas, it would break.
2 -> Use NW.js in mixed context mode: this way each spawned window has its own global window object. However, this works by running each window on a different process, which makes it hard to pass information back and forth.
4 -> Thanks to #23686 I can do something like:
window.self = nw.Window.get().window; //Get NW.js child window object into the self reference three.js will use
renderer = new THREE.WebGLRenderer({ antialias: true });
window.self = window; //Set the original window back to the global self reference
This seems to work fine as well, but it's also extremely hackish.
4 -> Directly use requestAnimationFrame on the child window object, as it used to be done.
As far as I understand, this is currently discouraged in favor of setAnimationLoop for WebXR compatibility, but so far it's the best I've come up with. I guess it's an acceptable solution if WebXR support is never to be considered, and if everything else works as expected (please confirm?).
Additional context
Nw.js is a development platform by Intel which allows application programmers to combine a nodejs back-end with a HTML/CSS/JS front-end into a standalone app (similar to Electron):
https://nwjs.io/
https://docs.nwjs.io/en/latest/For%20Users/Advanced/JavaScript%20Contexts%20in%20NW.js/
In Nw.js, visible HTML interfaces don't use the default, global "window". Rather, the global window corresponds to an invisible, background object. This is an useful design choice for headless environments.
Thanks and kind regards.
~Sky
The text was updated successfully, but these errors were encountered: