javascriptopengl-esrotationtextureswebgl

Repeated textures are severely distorted/shaking when rotating camera


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:

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:

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


Solution

  • 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).