Archived

This topic is now archived and is closed to further replies.

Preventing stretched textures on terrain

This topic is 5108 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The way I''ve been texturing terrain for the longest time has also been in the most basic way. I have been simply setting texture coordinates based on the 2D grid of the terrain mesh. As such, there occurs a problem where on a steap slope the texture is stretched over a larger physical 3D area. Let''s take a cross section of the terrain for a 2D example. Imagine that neighbouring vertices are at the same height. The true distance between them will be 1 unit. Basing texture coordinates on the 2D position of the vertices, this situation provides an ideal circumstance. However, if one vertex is 4 units higher than the other, the true distance between them is now approximately 4.1 units. Using the same texture coodinates, the texture must be stretched across a greater area, resulting in an obvious irregularity in how the surface looks. Is there any way to get around this? A way to generate texture coordinates that will ensure that a texture is never stretched across a greater area than at any other point on the terrain?

Share this post


Link to post
Share on other sites
not really, mainly because you would have a very complicated texture image. The texture image would be distorted in various areas in order to compensate for how much stretching that has to be done. The more a specific area needs to be stretched, the more "pixels per float" there needs to be in that spot.

The only feasible way i see this ever working, is if your terrain is procedurally textured, instead of using a static texture map that is stretched over the terrain, you would actually be tiling a specific texture over the terrain. This would have it''s benefits in your situation, since you''d be able to calculate if you need to tile more based on height (which is where stretching occurs).

the most elegant solution, of course, is using meshes for terrains. But this is arguable.

Share this post


Link to post
Share on other sites
I was thinking about the procedural idea. . . I could toss a 3D noise texture into a fragment program and manipulate it in various ways for creating a rock texture or whatever else is necessary. However, that would then make my engine dependant on fragment programs, which I would like to avoid until they become more widespread (at acceptable speeds). My terrain is already fully dependant on ARB_vertex_program. . . Also, alot of textures may be very difficult to achieve via procedural methods. . .

EDIT: Oops! You weren't quite talking about the same procedural stuff as I was! :D

I am already procedurally colouring the terrain and have no problem with the results. My problem specifically deals with detail textures.

[edited by - Ostsol on December 12, 2003 8:44:38 PM]

Share this post


Link to post
Share on other sites
Hi Ostsol. What you are talking about is definitely possible. It is essentially the same problem people face when texturing any object that isn't flat. If you are linearly projecting the texture from above, then any non-flat regions of your terrain get the wrong amount of texture on them. If the slope becomes very steep, they get very little texture and things look awful.

There are paint programs that will warp an object to a flat plane, and allow you to paint on that, but they are usually not for terrains. They automatically generate the warp required to map the texture correctly onto the model.

For your purposes with a detail texture, it should be much simpler. Is your terrain a regular grid? If so, let's say you are generating texture coordinates for one row of vertices.

1. Find the euclidian distance from one point to the next, and sum that over the entire row.

2. Make another pass over the vertices, and set the tex coord to be: (distance from last point / summed distance) * multiple

The multiple is how many times you want the detail texture to repeat.

Do the same thing in the other dimension as well.

I haven't implemented it, but it should work fine.

shadow



[edited by - shadow_bobble on December 12, 2003 9:28:38 PM]

Share this post


Link to post
Share on other sites
Texture splatting is a method of handling multiple layers of detail textures and the blending between them. Unfortunately, it does not appear to handle the issue I explained. Here''s a screenshot of the issue from one of GameTutorials'' heightmap tutorials:

http://members.shaw.ca/dwkjo/screenshots/stretch.png

shadow_bobble, I''ve thought of your suggestion, but wasn''t sure if it''d really work. . . I''ll try and implement it, though. . .

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
i dont know if this is possiable, but could you do that via mip map levels, i mean instead of starting on level1 all your terrain starts on the 2nd mip map level and when the poly is tilted enough to need more resiultion you move upto mip map level 1(could this be done via shaders?)


---------------------------------------------------
luminus =)
chown -R us /*base*

Share this post


Link to post
Share on other sites
Here''s a screenshot:

http://members.shaw.ca/dwkjo/screenshots/skew.png

Here''s the code for my texcoord generation:

float fX = (float) x;
float fY = (float) y;
float fHeight = afTotal[x + y * nSize];

if (x > 0)
fX = (aVertices[(x - 1) + y * nSize].texcoord[0] * 64.0f) + sqrtf (1 + fabsf (fHeight - afTotal[(x - 1) + y * nSize]));

if (y > 0)
fY = (aVertices[x + (y - 1) * nSize].texcoord[1] * 64.0f) + sqrtf (1 + fabsf (fHeight - afTotal[x + (y - 1) * nSize]));

aVertices[x + y * nSize].texcoord[0] = fX / 64.0f;
aVertices[x + y * nSize].texcoord[1] = fY / 64.0f;


This is run through a couple of for loops, incrememing x and y, which represent the columns and rows of the terrain grid, of course. afTotal is an array of floats containing the heights for each point on the grid. nSize is the size of the terrain.

Share this post


Link to post
Share on other sites
For a heightmap with vertices that have shared texture coordinates there really is no way to avoid the texture stretching. A solution would require splitting the hightmap up into smaller patches in a manner that each patch was comprised of only vertices that could support shared texture coords. This would allow you to alter the texture coordinates for the steep areas to get rid of the stretching.

Of course, I could be wrong, but AFAIK theres no easy way around the problem.

-=[ Megahertz ]=-

Share this post


Link to post
Share on other sites
Hi again Ostsol. Well I looked into this more and it seems my original idea was a little too simple. My mistake. Sorry. :-)

I spoke to a friend who did some university research on UV mapping last summer. He came up with a method that works quite well, but the math involved is complex. It involves eigensystems/PCA. Are you familiar with that? If you want to give it a shot, let me know and i''ll send you the details. But just so you know, it''s not something that will be easy to implement unless you''re using matlab. :-)

shadow

Share this post


Link to post
Share on other sites
There is no good way to fix it. Even the most advanced games (Asheron''s Call 2 for example) pretty much ignore it and let the stretching happen. Yann L mentioned something a while ago about adjusting uv coordinates with his bezier patch terrain that let him fix it but I don''t know if he went into any details.

Share this post


Link to post
Share on other sites
Hi Ostsol.

Here is one method that will give you reasonably good results, but its only practical for low vertex counts for obvious reasons.

build an adjacency matrix for the vertices(edges).

Below is a matlab function that takes that matrix, and minimizes the error in the distances between vertices. It returns the texture coordinates. You will need an understanding of some graph algorithms (dijkstra) and eigensystems to understand what is happening.

I didn't write this code (my friend did), but I understand it if you have questions.

function texcoords=MDStexgen(edges)

N=size(edges,1);

diss=zeros(N);
for(j=1:N)
[d p]=dijkstra(edges,j);
diss(:,j)=d;
end

diss(find(isinf(diss)))=1;


J=eye(N)-(1/N)*ones(N,1)*ones(1,N);
B=-0.5*J*(diss.*diss)*J;
[v,e]=eigs(B,2);
texcoords=v*sqrt(e);



[edited by - shadow_bobble on December 14, 2003 12:11:01 AM]

Share this post


Link to post
Share on other sites
I know how to manually compensating for UV stretching in a 3D editor, by stretching the UVs on slopes. This means compressing the UVs on level areas to get enough space for the stretched areas.

Maybe you could use the vertex normal as an offset for the UV coordinates?

Share this post


Link to post
Share on other sites