-
-
Notifications
You must be signed in to change notification settings - Fork 400
fix(RenderWindow): Support custom sizes for screenshots #1907
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
Conversation
|
@jourdain This is working for MIQA, but let me know what you think. Doing the |
| } else { | ||
| // Create a stand-in image overlay while we resize and render | ||
| const tmpImg = document.createElement('img'); | ||
| tmpImg.width = model.size[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is that needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, I think probably not needed. Will fix.
| // Create a stand-in image overlay while we resize and render | ||
| const tmpImg = document.createElement('img'); | ||
| tmpImg.width = model.size[0]; | ||
| tmpImg.height = model.size[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is that needed?
| // Without this resetCamera(), we can end up showing only a subset | ||
| // of the prop(s) depending on the difference between the aspect | ||
| // ratios of the original size and the custom capture size. | ||
| ren.resetCamera(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be optional and off by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was wondering about that. It's kind of best effort anyway. To really allow you to get what you want in your screenshot, we'd probably have to call you back before we render and let you compute/set what you want.
But you think if we just make it optional (and default off), the way it is now could be good enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should we call that option? screenshotResetCamera or resetCameraOnResizeScreenshot? Or just resetCamera and document it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
opts = {
resetCamera?: false, // Should only be needed if aspect ratio is different (Maybe auto on if size provided / but not sure)
size?: [width, height],
scale?: 1, // maintain aspect ratio but allow to adjust size based on original size?
}
| publicAPI.modified(); | ||
| // save camera parameters before resetCamera so we can restore | ||
| // them later | ||
| model.activeCamParamMap = new WeakMap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not use a weak map but just rely on the order of the renderer because it really happen in a non-interactive setup.
You should use a private object on the model.
model._screenshot = {
originalSize: [],
imagePaceHolder: ...,
cameras: [],
};
| model.originalSize = [model.size[0], model.size[1]]; | ||
|
|
||
| // hide it | ||
| model.canvas.style.display = 'none'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see you reversing it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reversing it is done in the updateWindow method as a result of calling publicAPI.modified().
| // save camera parameters before resetCamera so we can restore | ||
| // them later | ||
| model.activeCamParamMap = new WeakMap(); | ||
| model.renderable.getRenderers().forEach((ren) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The camera stuff is only required if we do the reset camera.
You can write it better like:
mode._screenshots.cameras = model.renderable.getRenderers().map(
(renderer) => renderer.getActiveCamera().get('focalPoint', 'position', 'parallelScale')
);
Then when you revert it you can do
model.renderable.getRenderers().forEach((renderer, idx) => {
renderer.getActiveCamera().set(model._screenshot.cameras[idx]);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thx.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could even bundle the fn with it like
mode._screenshots.cameras = model.renderable.getRenderers().map((renderer) => {
const camera = renderer.getActiveCamera();
const arg = camera.get('focalPoint', 'position', 'parallelScale');
const fn = camera.set;
const resetCamera = renderer.resetCamera;
return { fn, arg, resetCamera };
});
// resetCamera (after all the param capture as cross camera link could mess up your parameter capture)
mode._screenshots.cameras.forEach(({ resetCamera }) => resetCamera());
// reset
mode._screenshots.cameras.forEach(({ fn, arg }) => fn(arg));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you may have to clone the arg depending if you get a ref or a copy of each array.
clone = (obj) => JSON.parse(JSON.stringify(obj))
| model.canvas.style.display = 'none'; | ||
|
|
||
| // resize it | ||
| model.size[0] = model.customCaptureSize[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
model._screenshot.originalSize = model.size;
model.size = model._screenshot.size;
[...]
model.size = model._screenshot.originalSize;
| }; | ||
|
|
||
| publicAPI.captureImages = (format = 'image/png') => { | ||
| publicAPI.captureImages = (opts = {}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add opts as a second argument to prevent a BREAKING_CHANGE...
| const tmpImg = document.createElement('img'); | ||
| tmpImg.width = model.size[0]; | ||
| tmpImg.height = model.size[1]; | ||
| tmpImg.style = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may want to have that style as a const at the module level. tmpImg.style = SCREENSHOT_PLACE_HOLDER;
e22423e to
097074c
Compare
097074c to
b4e0114
Compare
|
@jourdain Let me know if I should at least document the duplication between the |
|
@jourdain Do you think this is still missing something? If just rebase and force-push the branch and the checks are still green, could we merge it? |
b4e0114 to
ab45a23
Compare
|
🎉 This PR is included in version 18.1.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
|
Thanks @jourdain 👍 |
Currently the screenshot capture functionality captures the render window image as it appears on the screen. However, some applications could benefit from the ability to specify an arbitrary size when capturing an image and have it rendered at full resolution rather than resampled.
I haven't tried this with WebGPU, but just provided an implementation the same as that for OpenGL.