Skip to content
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

WebGLRenderer: Change scissor, viewport functions to use "round" instead of "floor" #27703

Merged
merged 2 commits into from
Feb 8, 2024

Conversation

gkjohnson
Copy link
Collaborator

@gkjohnson gkjohnson commented Feb 7, 2024

Fixed #27655

Description

Use "round" instead of "floor" to compute the scissor and viewport functions to prevent rounding errors. From the WebGL spec there doesn't seem to be any requirement that the max value be within the width of the canvas so no value clamp has been added.

@gkjohnson gkjohnson added this to the r162 milestone Feb 7, 2024
Copy link

github-actions bot commented Feb 7, 2024

📦 Bundle size

Full ESM build, minified and gzipped.

Filesize dev Filesize PR Diff
676.2 kB (167.9 kB) 676.2 kB (167.9 kB) +0 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Filesize dev Filesize PR Diff
456.8 kB (110.7 kB) 456.8 kB (110.8 kB) +0 B

@gkjohnson
Copy link
Collaborator Author

Do we know if there's anything unique about the device pixel ratio in the CI checks? When generating a new screenshot locally for "webgl_effects_peppersghost" I'm seeing that there's no diff but in CI it's failing.

dev screenshot artifact screenshot delta screenshot
webgl_effects_peppersghost-expected webgl_effects_peppersghost-actual webgl_effects_peppersghost-diff

@mrdoob
Copy link
Owner

mrdoob commented Feb 8, 2024

What I started doing for these cases is to download the screenshot that the CI generated and add it to the PR... 😇

You can get it here:
https://github.com/mrdoob/three.js/actions/runs/7814629999/artifacts/1227023113

@WestLangley
Copy link
Collaborator

#18326 may need to be revisited if this is merged. It was required because of the use of .floor().

@gkjohnson
Copy link
Collaborator Author

#18326 may need to be revisited if this is merged. It was required because of the use of .floor().

This isn't something I'd be able to test, unfortunately. cc @elalish

@elalish
Copy link
Contributor

elalish commented Feb 8, 2024

Well, it should be pretty obvious with a Pixel and this example: #18265 (comment)

I can't test just now either, but I will once I pull this into MV.

@gkjohnson
Copy link
Collaborator Author

gkjohnson commented Feb 8, 2024

Looking at the PR - it might be best to set the viewport settings on the render target rather than the renderer. Setting the viewport on the render target itself (here) allows you to set exact pixel values instead of dealing with these rounding issues and DPR.

The discrepancy in behavior when dealing with WebGLRenderTarget.viewport and WebGLRenderer.setViewport (and scissor) is fairly confusing and it might be worth looking into how to simplify this another time.

@donmccurdy
Copy link
Collaborator

donmccurdy commented Feb 8, 2024

From the WebGL spec there doesn't seem to be any requirement that the max value be within the width of the canvas so no value clamp has been added.

Examples like https://threejs.org/examples/#webgl_multiple_elements rely on being able to set scissor and viewports that extend partially offscreen, so +1 for not clamping this. 🙂

@Mugen87
Copy link
Collaborator

Mugen87 commented Feb 8, 2024

@gkjohnson Do you mind temporarily updating the build files in this PR? I can make a test with a Pixel 4a which has a device pixel ratio of 2.75. If there is an issue with PMREM, examples like webgl_materials_envmaps_exr or webgl_materials_physical_clearcoat should show the banding artifacts from #18265.

@gkjohnson
Copy link
Collaborator Author

gkjohnson commented Feb 8, 2024

In #18447 the _setViewport function in PMREMGenerator was already refactored to remove use of WebGLRenderer.setViewport in favor of "WebGLRenderTarget.viewport" so this issue shouldn't be a concern anymore.

@gkjohnson gkjohnson merged commit 49f785b into mrdoob:dev Feb 8, 2024
12 checks passed
@gkjohnson gkjohnson deleted the fix-stencil-tiling branch February 8, 2024 11:39
@@ -489,7 +489,7 @@ class WebGLRenderer {

}

state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() );
state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).round() );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In at least six other instances in the code, floor() is still used when applying pixelRatio. Was this an oversight, or was this intentional?

/ping @Mugen87
/ping @gkjohnson

Copy link
Collaborator

@Mugen87 Mugen87 May 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me that is an oversight. When looking at the code, the usage in setRenderTarget() should be updated to round() as well.

_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();

Not sure about getDrawingBufferSize() though.

return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();

Depending on how we decide, the code in examples/jsm/renderers/common/Renderer.js should be updated accordingly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebGLRenderer: Setting Scissor and Viewport is imprecise due to rounding issues
6 participants