Chrome 三台显示器的 Webgl 失真

Webgl Distortion in Chrome with three Monitors

我正在开发一个 webgl 应用程序(一个简单的太阳系),在一台显示器上 Chrome 和 Firefox 上一切看起来都很好 但是如果我启动 eyefinity(三个显示器每个全高清 + 边框补偿)太阳系在 chrome 中扭曲。

在 Firefox 中,它看起来正确而且非常好: http://kritten.org/pictures/firefox.jpg

在 Chrome 中它看起来像这样: http://kritten.org/pictures/chrome.jpg

似乎主要点(这个名字对吗?)在错误的位置。 如果我在 Firefox 中向前移动,我实际上是向前移动,但在 Chrome 中我向右移动。所以它随时保持这种失真。

有什么想法可能是错误的吗?

Chrome 的问题是它对 canvas 的大小有限制。这是 WebGL 规范的一部分,尽管可以说 Chrome 应该修复它。你可以试试encourage them to fix it here.

具体问题是 WebGL 规范指出,即使您可能要求 canvas 特定大小,WebGL 也可能会为您提供更小的绘图缓冲区。这是因为显卡有大小限制。有些低至 1024。假设某些卡的限制为 2048。您有一台 1280x1024 的显示器。没问题。

您现在为 2560x1024 的总桌面 space 添加第二台显示器。您现在在两台显示器上拉伸 window。您要求尺寸为 2560x1024 的 canvas。应该发生什么? WebGL 不能做那么大,GPU 说它有 2048 的限制。所以有 3 个选项

  1. 崩溃。那不行

  2. 强制 canvas 保持在 2048 以下

  3. 将 canvas 拉伸到 2560,但将绘图缓冲区设置为 2048 的限制,在此示例中为 2048

WebGL 委员会选择了 #3,因为它是最不可能引起问题的一个。最糟糕的情况是你得到一个扭曲的图像,但用户可以缩小 window 直到一切正常,这样你的网页就不会死掉。

不幸的是,99.99% 的 WebGL 程序忽略了 WebGL 的这一特性,因此当您 运行 进入规范的那一部分时,您会得到这个扭曲的图像。

在这种特殊情况下,虽然限制不在您的 GPU 中,但在 Chrome 中。证据是它可以在 Firefox 中运行。您可以再次尝试 encourage them to fix it here.

如果你想让你的程序绕过它,你需要查看 canvas 的绘图缓冲区的实际大小,并在正确的地方使用它。你可以找到但检查 gl.drawingBufferWidthgl.drawingBufferHeight

这意味着首先将相机纵横比设置为 canvas 实际显示的大小。你真的应该经常这样做

aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
perspective = yourPerspectiveFunction(fov, aspect, zNear, zFar);

在 three.js 中会是

camera.aspect = renderer.domElement.clientWidth /
                renderer.domElement.clientHeight;
camera.updateProjectionMatrix();

您应该将视口设置为绘图缓冲区的大小

gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawBufferHeight);

在 three.js 中会是

renderer.setViewport(0, 0, renderer.context.drawingBufferWidth,
                           renderer.context.drawingBufferHeight);

这也应该始终有效。

如果您正在做与 canvas 的宽度和高度相关的任何其他操作(采摘、剪刀等),您需要进行适当的数学运算以将 canvas 显示为绘图缓冲区的大小

这将消除失真,当然,因为 Chrome 实际上只会创建一个较小的 drawingBuffer,您会得到一些缩放。