Hi Folks,
I’m trying to create a page that generates a number of screenshots for me. I want to do this by creating a bunch of cameras in an array, and then adding an onReadyObservable
that iterates through them and generates the screenshots.
I’ve got a playground page https://playground.babylonjs.com/#1YQBZO#1 that does what I want.
The problem I have is that in my local branch BABYLON.Tools.CreateScreenshotUsingRenderTargetAsync
seems to just hang. I’ve tried wrapping it in a try
/catch
but no error seems to be thrown either. Adding console.log
statements I can see that it’s getting to the line before that and then not getting any further.
Here’s the code snippet I have locally:
scene.onReadyObservable.add(async () => {
for (i = 0; i < POICameraArray.length; i++){
console.log(i);
POICameraArray[i].attachControl(canvas, false);
scene.activeCamera = POICameraArray[i];
scene.render();
console.log("Scene rendered");
try {
console.log("About to try");
const data = await BABYLON.Tools.CreateScreenshotUsingRenderTargetAsync(
engine,
scene.activeCamera,
{width: 1000, height: 1000, precision: 2.0, finalWidth: 1000, finalHeight: 1000}
);
console.log("Screenshotted");
} catch (error){
console.log(error);
}
console.log(data);
}
});
All I see in the console is 0
, Scene rendered
and then About to try
. If I replace the CreateScreenshot call with something harmless like an async function that logs “Hello” to a console that seems to work fine. And obviously it works fine in the playground.
Any ideas how I’d troubleshoot this?
Thanks, Tom
Seems like the promise hangs. Can you put a “debugger” before CreateScreenshotUsingRenderTargetAsync and step through until it stops? Maybe this could give some clues.
Other than that: double check parameters to CreateScreenshotUsingRenderTargetAsync. Double check camera array. Does a camera need to be ready? If you assign an active camera, will this be active immediately or does it need a frame to be set up? Right when the callback to scene.onReadyObservable starts, can you wait 2 or so seconds to ensure the scene is really ready? Try any of the other Screenshot functions?
Looking at the source
- Try en-/disabling antialiasing (the parameter)?
- Switch between WebGL and WebGPU?
I’ve tried adding a debugger and stepping through the code. It seems to get “all the way through” eventually but then just goes back to not doing anything (presumably still waiting for the promise to return?).
I’ve triple checked the parameters and they seem fine, I’ve also tried CreateScreenshotAsync
but that also has the same effect.
I’ve also tried adding a 2 second wait at various points but that doesn’t seem to help either 
Note that the line scene.render();
doesn’t have any effect on the result - https://playground.babylonjs.com/#1YQBZO#2
I’ve downloaded babylon.max.js from the cdn and am using that locally so I can make modifications to try and pinpoint what’s happening. I can see that the renderWhenReady
function is firing (see Babylon.js/packages/dev/core/src/Misc/screenshotTools.ts at 472cd97a1ad2fd2612adb0e3e66b97edc7467dd1 · BabylonJS/Babylon.js · GitHub) at which point texture.isReadyForRendering()
and camera.isReady(true)
are both true
. I can also see that scene.render()
(see Babylon.js/packages/dev/core/src/Misc/screenshotTools.ts at 472cd97a1ad2fd2612adb0e3e66b97edc7467dd1 · BabylonJS/Babylon.js · GitHub) is being fired.
I don’t quite understand all the code here, but I think engine.onEndFrameObservable.addOnce
might not be being fired (if I add a console.log
statement before if (finalWidth === width && finalHeight === height) {
I don’t see it). Could that be the problem?
If I add a console.log statement at the end of the finally
after the scene is rendered, I see that logged (see Babylon.js/packages/dev/core/src/Misc/screenshotTools.ts at 472cd97a1ad2fd2612adb0e3e66b97edc7467dd1 · BabylonJS/Babylon.js · GitHub) and if I check the list of engine.onEndFrameObservable
I do see the one added from line 333 of the code, so it looks like the engine is never finishing the current frame per Babylon.js docs.
For onEndFrameObservable
to be fired, you must setup a render loop (engine.runRenderLoop(...)
). Maybe you don’t have one?
1 Like
Er, yeah, that was it! Thanks!