旋转相机时,重复纹理会严重扭曲/抖动

时间:2012-01-09 11:10:49

标签: javascript opengl-es rotation textures webgl

我最初在gamedev上问了这个问题,但没有一个答案有助于解决问题,我仍然不知道究竟是什么原因。我没有看到任何关于在常见问题解答中重新发布SE的问题,所以我只能希望这没关系。此外,回想起来,问题可能与图形编程有关,而不仅仅是游戏开发。

编辑1开始

原始帖子的行为仅适用于Windows XP和Windows 7,浏览器Firefox和Chrome。在Ubuntu上,没有这样的失真,而是在相机旋转时纹理“抖动”。当旋转停止时,抖动停止,但纹理可能不在完全正确的位置。

编辑1结束

编辑3开始

该程序已在4台不同的计算机上进行了测试,并且没有按计划在任何计算机上运行。

编辑3结束

我在WebGL中有一个大的体素,我希望用平铺纹理覆盖每个tile在顶点空间中的边长为1。在此测试场景中,摄像机指向负z方向,体素侧面位于x-y,x-z,y-z平面。

较小的体素(即较少的重复)效果很好,但是每张脸大约2000 x和y重复(即体素大小2000 * 2000 * 2000),纹理开始看起来非常难看。当相机垂直于脸部时,无论重复的大小/数量如何,纹理看起来都是正确的,但对于上述尺寸的体素,任何甚至几度的旋转都会引起明显的问题。增加体素尺寸会增加失真。反之亦然:对于小体素,无论相机旋转如何,纹理看起来都是正确的。在我看来,这个尺寸没有硬阈值,但是当体素从每边大约2000个增加时,效果开始从零开始逐渐增加。

有关可视化的信息,请参阅http://imgur.com/a/spQIv。第一个图像是它应该是什么样子,但是当旋转相机时,线条开始像第二个图像一样变形。通过增加体素大小和更多地旋转相机,效果会变得更糟。 http://imgur.com/a/wRndy包含两个影响更严重的其他影像。

纹理(每个纹理一个X)最初为512 * 512像素。屏幕截图没有以任何方式缩放。

我的第一个猜测是浮动不准确,但很难相信,因为该对象只有1000的维度。

我的第二个猜测是某种奇怪的int / float舍入错误,但由于所有内容总是在浮点数中处理,我不知道这是怎么发生的。

我能想到的第三种可能性是,这是不可能的,纹理不应该多次重复。但是,这似乎不太可能是IMO。我的猜测(和希望)是存在某种非常基本的问题。

任何有关可能导致或通常导致此类事情的建议都值得赞赏,因为我似乎很难自己尝试缩小此问题的来源。

我正在使用:

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结束

2 个答案:

答案 0 :(得分:6)

我相信你所看到的可能真的是由于精确造成的。你正确地计算出浮点坐标应该足够了,问题是硬件使用浮点数来查找纹理。纹理内插器单元的精度要低得多(不知道今天怎么样,但在旧版GeForce卡上它曾经低至16位)。

那么......如何超越插补器精度?通过在大型几何体上使用大纹理坐标(多次重复),这正是您正在做的事情。补救?细分您的几何体以使用较小的纹理坐标(您可以按整数步长移动纹理坐标,使它们更接近0)。

这是一个screenshot它看起来有多么极端(我无法在我的GeForce 260上重现错误,但在我的Tegra 2平板电脑上清晰可见,如下图所示)。

答案 1 :(得分:2)

我在iOS下遇到了类似的问题。在重复纹理127次之后,坏事开始发生。

有效的解决方案是:

我使用GL_TRIANGLE_STRIP和一些退化三角形。纹理与顶点对齐,因此在纹理的边缘有一个不可见(退化)三角形,当我将纹理坐标设置为原点时,纹理被“显示”为镜像。因此,下一个可见三角形显示来自坐标(0.0, 0.0)的纹理,它永远不会越过坐标(x, 127.0)

有一个blog post用一些例子和图片来解释这个。