Bizzare texture seam problem on LOD terrain.

I’ve written a basic Quadtree LOD engine which renders a 256x256 terrain mesh by dividing it into 16 (4x4) sections where a large texture tile is stretched across each (4x4) section.

Each texture tile is 256x256 pixels.

ignore the LOD part actually, it’s irrelevant to the problem

In order to get the texture coordinates for each triangle, I take the actual (x, z) position on the map and divide the x and z values by a stretching constant (64.0 in this instant, as 4 textures of 256 size fit across either length). This limits the first tile to the range 0.0 - 1.0.

This means I have texture coords across the length of the terrain for each axis like:

(tile 1: 0.0 - 0.999~) (tile 2: 1.0-1.999~) (tile 3: 2.0 - 2.999~) (tile 4: 3.0-3.999~)

With GL_REPEAT the landscape looks like: http://www.arkiruthis.f9.co.uk/lod_1.jpg

With GL_CLAMP the landscape looks like: http://www.arkiruthis.f9.co.uk/lod_2.jpg

(i.e., only the top right tile (1 out of 16) is rendered correctly)

With GL_CLAMP and a check on each set of vertices (e.g. (x%64)/64.0, (z%64)/64.0) I get the edges of the triangle mesh repeating whole sections of the texture itself.
http://www.arkiruthis.f9.co.uk/lod_3.jpg

Any ideas?

[This message has been edited by ceenda (edited 05-21-2002).]

No idea, unfortunately … but some thoughts:
1)GL_CLAMP won’t work for this kind of stuff. Forget about it.
2)The modulo stuff (% operator) is probably doing some weird stuff with floating point. I’ve bitten my desk quite a few times over floating point issues with ‘modern’ compilers. But forget about it anyway … (more about that later)
3)The GL_REPEAT thing looks nice, that should be the way to go.

Question:
Are you using vertex arrays? Even if you don’t, it seems to me that you should reuse grid vertices. Say, tile [0;0] and tile [1;0] meet, you should have two vertices at the junction with tex coords (1.0f/64;0) and (1.0f/64;1.0f/64) respectively. This 0.999999999 … stuff doesn’t make much sense really if you follow the rasterization rules closely.
There would still be some issues, the ‘right thing’ ™ to do would include texture borders, but I think you should first try it without.

Hope I’ve been somewhat useful

You need CLAMP_TO_EDGE, or possibly using texture borders (which aren’t accelerated on most cards).

You also need to make sure you get your s/t coordinates in the right direction; OpenGL treats “0” as the first pixel from the bottom of an image (and also assumes images are stored bottom-to-top).

Are you using vertex lighting ? The artifact in the top shot looks like an interpolation problem to me.

Y.

Please don’t crosspost.
http://www.flipcode.com/cgi-bin/msg.cgi?showThread=00004955&forum=3dtheory&id=-1

Thanks for all the replies.

It seems that the problem in the third method is that the edge triangles ‘backflip’ the texture coordinates (e.g., the larger coordinate becomes the smallest).

Adrian: Sorry, I’ve not been programming for a while and I always guessed that these forums and flipcode were quite remote and that the users were pretty much independant.

Whatever, it looks nice anyhow

Originally posted by Adrian:
Please don’t crosspost.
http://www.flipcode.com/cgi-bin/msg.cgi?showThread=00004955&forum=3dtheory&id=-1

Do you call that crossposting? I call that doubling your chances…

Originally posted by ceenda:

With GL_CLAMP and a check on each set of vertices (e.g. (x%64)/64.0, (z%64)/64.0) I get the edges of the triangle mesh repeating whole sections of the texture itself.
http://www.arkiruthis.f9.co.uk/lod_3.jpg

Any ideas?

[/b]

This doesn’t appear to be an opengl problem. I think your snow field has just avalanched, that is all…

GL_REPEAT is the wrong thing because at the edge of the quad you filter back to the opposite edge on each quad.

GL_CLAMP would avoid this (it’s not perfect but it’s much better) unfortunately for you it clamps between 0-1. Instead of coordinates which go from 1-2 2-3 3-4 you need coordinates which go from 0-1 on each quad for this to work.

Do this by adjusting the vertex coordinates, or use a texture matrix on each quad to translate back to the 0-1 range. I advise adjusting the vertex values.

Dorbie,

GL_CLAMP_TO_EDGE is standard in current OpenGL implementations. It clamps in the center of the outermost texels, which is what you usually want when you clamp. (There also CLAMP_TO_BORDER which might be useful if your card supports borders)

I’m not sure if this applies to your problem but bear in mind that if you’re going to use LINEAR filtering and/or mipmapping(which I assume you will) you will get texture seems on terrain tile borders even with CLAMP or CLAMP to edge which btw is the way to go.To solve this problem you need use a trick which jwatte mentioned as well(although the gl border mechanism isn’t needed and shouldn’t be used).
For more info on this check out the links at vterrain.org(a very usefull page on terrain rendering) in the large textures section.Also you might want to take a look at the mailing list archives of the same site for a thread I started on the same topic a while ago.I don’t remeber the exact title but do a search for tile,borders,seams or something like that and you’ll find it.Hope that helped(although I have the feeling you allready knew most of this)

PS: shot 1 looks like the problem I’m reffering to.If you fixed the problem with the other screenshots(which should look like the first) take a good look at a tile border to check for seams.

[This message has been edited by zen (edited 05-23-2002).]

Thanks for all the replies.

I tried looking for GL_CLAMP_TO_EDGE on the OpenGL Extensions registry… but couldn’t find any info at all. In the end I did a google search and found a piece of sourcecode with:

#define GL_CLAMP_TO_EDGE 0x812F

so I added that to the headers and substituted GL_CLAMP_TO_EDGE instead of GL_REPEAT. However, it seems that the NVidia OpenGL drivers don’t seem to implement this properly on GeForce2 and you just get EXACTLY the same effect as GL_REPEAT.

zen: Heh, my old quadtree engine is still linked at vterrain (OpenGL LOD). It’s a very good website.

I don’t want to use borders as I sense this will incur a massive hit on the performance.

A mate of mine (not a programmer) said “Why not just make the textures 257x257?” … would this make the program run slower? I always thought that if textures weren’t 2^n then the cards couldn’t do optimisation when processing them.

I think that I’ll render each tile and send a token to each:

x_sector = (x / 64);
z_sector = (z / 64);

which will give an index like

(0,0)(1,0)(2,0)(3,0)
(0,1)(1,1)(2,1)(3,1)
(0,2)(1,2)(2,2)(3,2)
(0,3)(1,3)(2,3)(3,3)

and I can subtract the texture coordinates thus:

x_f = ((x - (x_sector * 64)) / 64.0f)
z_f = ((z - (z_sector * 64)) / 64.0f)

[This message has been edited by ceenda (edited 05-23-2002).]

[This message has been edited by ceenda (edited 05-23-2002).]

I had a similar problem some time ago.

I solved it in this way:

Imagine a Texture of the size 16*16. In this case the bottom, left pixel isn’t (0.0 | 0.0). ( 0.5/16 | 0.5/16 ) are the coordinates where you get the real color of the bottom left pixel.

Another thing you should know is, that you can only use 15*15 pixel of this texture. The reason for this is that the borders of two joining textures has to have the same color. So you must scale the texture by scale=(16-1)/16;

Now your texture coords for the bottom, left of a section should be ( 0.5/texturesize | 0.5/texturesize ).
And the top right coords shoud be ( (texturesize-0.5)/texturesize | (texturesize-0.5f)/texturesize ).

hope this helps

[This message has been edited by Mexx (edited 05-23-2002).]

jwatte, I consider that a detail, I was trying to solve the larger problem which to my surprise nobody had even mentioned yet despite the traffic on this thread. On the more subtle issue of edge filtering the designed way to resolve these issues is to use texture borders, which are generally not recommended on a lot of hardware.

The issues that exist with MIP maps mean the decision to go with clamp to edge is not clear cut.

There’s so much crap in this thread, he’ll be lucky to solve his relatively simple problem.

Clamp to edge will not resolve his issues, using texture coordinates between 0-1 on each quad will, for the most part.

Following up my post with a correction that won’t implement a fix for him won’t help him find a solution faster. The way he applies coordinates now REQUIRES a repeat wrap filter, so it is his coordinates which most change before any clamp filter will work, as I stated in my earlier post.

[This message has been edited by dorbie (edited 05-23-2002).]

Try rendering the scene without textures. My guess is that you will still see the dark lines.

I have seen the same problem without textures and on both Nvidia and S3 cards.

My guess is that it is just an artifact of the shading and/or lighting algorithms.

Also bear in mind that,in order to use the overlapping tiles approach(you can find a link to some info on it in the vterrain ‘large textures’ page)you don’t have to(and shouldn’t) use the gl border mechanism.Your textures are still 2^n+1x2^n+1 and the border is included in the texture itself.Take a look at that thread I mentioned for more info.