mrdoob / three.js

JavaScript 3D Library.
https://threejs.org/
MIT License
102.78k stars 35.38k forks source link

WebGLRenderer: Setting Scissor and Viewport is imprecise due to rounding issues #27655

Closed gkjohnson closed 9 months ago

gkjohnson commented 9 months ago

Description

For three-gpu-pathtracer I've been rendering the image in tiles for the sake of performance but found that it's not possible to set the exact pixels that the renderer rasterize due to the multiplication with the pixel ration and subsequent rounding that occurs in the setScissor and setViewport functions.

This means that when rendering tiles side by side the rounding can result in pixels being missed when rendering tiles. For three-gpu-pathtracer I've switched to using the WebGLRenderTarget's .scissor property since it affords setting the sciossor via exact pixel values.

Reproduction steps

  1. Try to render in a tiled fashion with a combination of pixel ratio and dimensions that do not cleanly divide
  2. See that the tiles miss rows and columns of pixels due to rounding error

Code

See live example.

Live example

Demo with selected pixel ratio and dimensions that result in the skipped pixels.

https://jsfiddle.net/cfhwous9/

Screenshots

image
image

https://twitter.com/mrdoob/status/1752366500621746617

Version

r160

Device

Desktop, Mobile

Browser

Chrome, Firefox, Safari, Edge

OS

Windows, MacOS, Android

Mugen87 commented 9 months ago

According to the WebGL/OpenGL spec the values passed to gl.viewport() and gl.scissor() are supposed to be GLint. To be spec compliant, the engine should round values. So maybe the usage of floor() is incorrect? Would using round() solve the issue?

gkjohnson commented 9 months ago

Yeah perhaps using "round" with a clamp to the max width of the canvas would work best.