旋转相机时重复的纹理严重扭曲/晃动
编辑 1 开始
原始帖子的行为仅适用于 Windows XP 和 Windows 7、浏览器 Firefox 和 Chrome。在 Ubuntu 上,不存在这种失真,而是在旋转相机时纹理“抖动”。当旋转停止时,晃动就会停止,但纹理可能不会处于完全正确的位置。
编辑 1 结束
编辑 3 开始
该程序已在 4 台不同的计算机上进行了测试,但未在其中任何一台上按预期运行。
编辑 3 端
我在 WebGL 中有一个大体素,我想用平铺纹理覆盖它,每个图块在顶点空间中的边长为 1。在此测试场景中,相机指向负 z 方向,体素的侧面位于 xy、xz、yz 平面中。
较小的体素(即较少的重复)效果很好,但在每个面大约 2000 个 x 和 y 重复(即体素大小 200020002000)时,纹理开始看起来非常难看。当相机垂直指向脸部时,无论重复的大小/数量如何,纹理看起来都是正确的,但对于上述大小的体素,即使是几度的旋转也会导致明显的问题。增加体素大小会增加失真。反之亦然:对于小体素,无论相机如何旋转,纹理看起来都是正确的。在我看来,尺寸没有硬性阈值,但当体素的尺寸从每边约 2000 增加时,效果开始从零逐渐增加。
请参阅此可视化:
第一个图像应该是这样的,但是当旋转相机时,线条开始像第二个图像一样扭曲。通过增加体素大小和更多地旋转相机,效果会变得更糟。
其中包含两个具有更严重影响的附加图像:
纹理(每个纹理一个 X)最初为 512*512 像素。屏幕截图没有以任何方式缩放。
我的第一个猜测是浮点不准确,但这很难相信,因为该对象只有 1000 量级的尺寸。
我的第二个猜测是某种奇怪的 int/float 舍入错误,但由于所有内容总是以浮点数处理,所以我不明白这是怎么发生的。
我能想到的第三种可能性是,这是不可能的,并且纹理不应该重复很多次。然而,在我看来,这似乎不太可能。我的猜测(也是希望)是存在某种非常基本的问题。
关于什么可能导致或通常导致这种事情有什么建议吗?
我正在使用:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.generateMipmap(gl.TEXTURE_2D);
在着色器中:
#ifdef GL_ES
precision highp float;
#endif
我还执行了一些非常基本的计算:对于 32 位浮点数,最大有效数约为 840 万。对于体素边长 2000(我注意到这是效果可见的水平),人们可以天真地期望坐标中的浮点舍入误差约为 0.00025。假设每次重复在屏幕上占用大约 100 个像素,则误差应明显小于 1 个像素,但事实并非如此。除非我上面的计算错误,否则我认为 Float32 不应该受到指责,原因一定是在其他地方。
线条纹理仅用于可视化问题。其他(更自然的)类型的纹理也存在这个问题。
编辑 2 开始
启用或禁用抗锯齿功能没有明显差异
编辑 2 结束
Edit 1 begins
The behaviour of the original post applies only to Windows XP and Windows 7, browsers Firefox and Chrome. On Ubuntu, there is no such distortion, but instead the textures "shake" while the camera is being rotated. When the rotation is halted, the shaking stops, but the textures may not be in the completely correct position.
Edit 1 ends
Edit 3 begins
The program has been tested on 4 different computers, and haven't worked as intended on any of them.
Edit 3 ends
I have a large voxel in WebGL which I want to cover with tiled texture each tile has the side length of 1 in the vertex space. In this test scenario the camera is pointing to the negative z direction and the sides of the voxel are in the x-y, x-z, y-z planes.
Smaller voxels (i.e. fewer repeats) work quite well, but at around 2000 x and y repeats per face (ie voxel size 200020002000) the textures start to look really ugly. When the camera points perpendicularly to the face the textures look correct regardless of the size/amount of repeats, but for voxels of the size mentioned above any rotation of even a couple of degrees causes a visible problem. Increasing the voxel size increases the distortion. The inverse is also true: with small voxels the textures look correct regardless of camera rotation. It seems to me that there is no hard threshold value for the size but that the effect starts to increase gradually from zero when the voxel is increased in size from the approx 2000 per side.
See this for a visualization:
The first image is how it should look like, but when the camera is rotated, the lines start to become distorted as in the second image. The effect gets worse by increasing the voxel size and by rotating the camera more.
This contains two additional images with more severe effect:
The textures (one X per texture) are originally 512*512 px. The screenshots have not been scaled in any way.
My first guess was float inaccuracies, but that's quite hard to believe since the object has only the dimensions of the order of 1000.
My second guess was some kind of weird int/float rounding error, but since everything is always handled in floats, I don't see how this could happen.
The third possibility I could think of is that this is just impossible and that textures should not be repeated that many times. However, this seems quite unlikely IMO. My guess (and hope) is that there is some kind of quite elementary problem.
Any suggestions about what can cause or commonly does cause this kind of thing?
I'm using:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.generateMipmap(gl.TEXTURE_2D);
and in the shader:
#ifdef GL_ES
precision highp float;
#endif
I also performed some very elementary calculations: For 32-bit floats the maximum significand is around 8.4 million. For voxel side length 2000 (which I noticed was the level where the effect became visible), one could naively expect approximately 0.00025 of a float rounding error in the coordinates. Assuming each repeat takes around 100 pixels in screen, the error should be significantly less than 1 pixel, which is not the case. Unless my calculation above was done incorrectly, I therefore would nominate that Float32 is not to blame and that the reason must be somewhere else.
The line texture is used only for visualizing the problem. The problem persists also with other (more natural) kinds of textures.
Edit 2 begins
Enabling or disabling antialiasing makes no visible difference
Edit 2 ends
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我相信你所看到的可能确实是由精度造成的。您正确地计算出浮点坐标应该足够漂亮,问题是硬件不使用浮点来查找纹理。纹理插值器单元的精度确实相当低(不知道现在怎么样,但在较旧的 GeForce 卡上它曾经低至 16 位)。
那么……如何才能超越插值器精度呢?通过在大型几何体上使用大型纹理坐标(许多重复),这正是您正在做的事情。补救?使用较小的纹理坐标细分几何体(您可以以整数步长移动纹理坐标,使它们更接近 0)。
这是一个屏幕截图,显示了它的极端情况(我无法重现该错误在我的 GeForce 260 上,但在我的 Tegra 2 平板电脑上清晰可见,如下图所示)。
i believe that what you are seeing may really be caused by the precission. You correctly calculated that the floating-point coordinates should be pretty enough, the problem is the hardware is not using floats to lookup the textures. The texture interpolator units do have considerably lower precision (don't know how is it today, but it used to be as low as 16 bits on older GeForce cards).
So ... how can one exceed interpolator precision? By using large texture coordinates (many repeats) on a large geometry, which is exactly what you are doing. Remedy? Subdivide your geometry to be using smaller texture coordinates (you can shift texture coordinates in integer steps so they are closer to 0).
Here is a screenshot of how extreme it can look like (i weren't able to reproduce the error on my GeForce 260, but it is clearly visible on my Tegra 2 tablet, as shown in the image below).
我在iOS下也遇到了类似的问题。重复纹理 127 次后,糟糕的事情开始发生。
有效的解决方案是这样的:
我使用了 GL_TRIANGLE_STRIP 和一些退化三角形。纹理与顶点对齐,因此在纹理的边缘有一个不可见(退化)三角形,当我将纹理坐标设置为原点时,纹理将“显示”镜像。因此,下一个可见三角形显示来自坐标
(0.0, 0.0)
的纹理,并且它永远不会超过坐标(x, 127.0)
。有一篇博客文章用一些例子和图片解释这一点。
I ran into similar problem under iOS. After repeating the texture 127 times, bad things started to happen.
The solution that worked was this:
I used
GL_TRIANGLE_STRIP
with some degenerate triangles. The texture is aligned to the vertieces, so at the edge of the texture there is an invisible (degenerate) triangle, where the texture is "displayed" mirrored as I set the texture coordinate to the origin. Thus the next visible triangle shows the texture from coordinate(0.0, 0.0)
and it never goes over coordinate(x, 127.0)
.There is a blog post explaining this with some examples and pictures.