Sign in to follow this  
JTippetts

Texture distortion on heightmapped terrain

Recommended Posts

When you texture a heightmapped terrain by tiling a texture across it, areas where there is a steep slope between adjacent heightmap samples tend to stretch the texture if the heightmap texture coordinates are evenly spaced. Until recently, I lived with it, but lately I've been wondering about ways to eliminate it. I attempted to re-calculate texture coordinates so that the actual length of the edge of a quad determines the spacing of texture coordinates along that edge, rather than the spacing of the samples in the x/z plane. So a quad with a steeper slope 'covers' more texture space than a quad with a shallower slope. On ridges and steep features parallel to the axes, this approach works well, as shown in these images. The first image is non-corrected terrain on a straight ridge, showing the stretching. The second image is corrected. Distorted Corrected However, doing it this way poses problems, since the 'correction' is actually just additional distortion which gets propagated across the remainder of the heightmap, so that on flat areas you can still see how the texture was stretched to accomodate the curve of the feature, as in the following images. The first image here is a mound, with un-corrected texturing, and the second is the same mound corrected. You can see in the second how the 'correction' continues across the map in a very ugly fashion. Distorted Corrected I've tried any number of means for calculating the correction, with no change in the result. Does anybody know of any other means for correcting the distortion that doesn't result in this ugliness, or is it just something you have to deal with with regularly spaced grids? Or am I doing something stupid? The terrain map function that actually calculates the texture coordinates after the grid mesh is constructed is:
void CTerrainMap::calcTextureCoords()
{
    float totals[m_meshmapwidth];
    unsigned int x,z;
    for(x=0; x<m_meshmapwidth; ++x) totals[x]=0.0f;

    for(z=0; z<m_meshmapwidth; ++z)
    {
        float s=0.0f;
        for(x=0; x<m_meshmapwidth; ++x)
        {
            CVec3f prev, cur, delta;
            // Do s
            if(x>0)
            {
                prev=m_vertex.get((int)(x-1), (int)z);
                cur=m_vertex.get((int)(x), (int)z);
                delta=cur-prev;
                float len=delta.length() / m_samplespacing;
                s+=len;
            }
            // Do t
            if(z>0)
            {
                prev=m_vertex.get((int)(x), (int)(z-1));
                cur=m_vertex.get((int)(x), (int)z);
                delta=cur-prev;
                float len=delta.length() / m_samplespacing;
                totals[x]+=len;
            }
            CVec2f tc;
            tc[0]=s*m_texturespacing;
            tc[1]=totals[x]*m_texturespacing;
            m_texcoord.set(x,z,tc);
        }
    }
}


Thanks.

Share this post


Link to post
Share on other sites
What about just treating the terrain as a regular mesh, which has to deal with irregularities in how the texture coordinates change and abandoning the projected texture altogether? That is, have areas with consistent texture coordinate (relative to position) derivatives be continuous areas in a texture, and duplicate vertices at discontinuous areas in the texture?

Share this post


Link to post
Share on other sites
One way i can think of, in the case of tiled terrain textures, is to use tri-planar mapping as did nVidia in their Cascades demo (pdf+movies)
Basically you calculate the texcoords relative to all 3 planes (xz, xy, yz) and you select the correct one, by blending them together, based on the normal.

EDIT : You haven't said anything about the minimum requirements, but tri-planar mapping requires 3 times the texture fetches you usually do in the fp, so this may be a little slow. But again it depends on what shaders and how many different textures you are using for the terrain.

HellRaiZer

Share this post


Link to post
Share on other sites
JTippetts,

If you manage to find an answer to that question, you can sell it to Autodesk and become a RICH man.

The tri-linear method described in that nvidia paper is pretty cool, and will work great if you are using procedural textures or simple repetitious textures like dirt or grass. However, if you are wanting to map actual images then they wont match up at the seems.

Some of the most promising solutions are "LSCSM mapping" as used in Blender and "Pelt Mapping" as used in 3ds Max.

However, since you are likely projecting some kind of a dirt texture, so you have no seems but you just want to avoid distortion, the tri-linear method should do perfectly!

Share this post


Link to post
Share on other sites
I've never really found a good general solution to this problem. Most of the time, any major texture distortion is fixed manually by the artists, who will modify the texture space on really steep surfaces to eliminate artifacts. Seams that appear on the boundaries will typically be covered up by blending over them.

Is there a particular reason why you're trying to eliminate the stretching?

Share this post


Link to post
Share on other sites
1. You can reparamatrize the mapping, for the whole terrain - just run a simulation that will shrink the stretched mapping on steep edges - but it will change the whole mapping of the terrain (as you method...).
In practice however, this will not work, since it creates a dependency on the texturing by the geometry, which is *evil*. No tweaking and can change already textured areas.

2. Triplanar mapping. Make it two-planar, and use it only for steep surfaces - and that works pretty well.
I.e. it can be very easilly fitted into existing splatmapped terrain, just by adding another kind of layer - say, vertical, that has 'cylindrical' texture coordinates and is applied only to vertical terrain.

The (1,3) is the image with that technique:
http://haemimontgames.com/gotre/screenshots/

3. The same as (2), but do not use twoplanar mapping, just single VERY tiled texture. VERY tiled. It can work the same as (2), if you don't have truely vertical geometry, which is exactly the case of heightmapped terrains anyway... :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Zipster
Is there a particular reason why you're trying to eliminate the stretching?


Mostly OCD, really. Every time I see a stretched cliff, my inner psychotic 'fixer' screams at me to do something about it. [grin] All of my terrains are randomly generated, so special-case fixing of the terrain texturing doesn't seem like the best solution, since I really need a general-case one.

Thanks for the posts, everyone. I've been playing quite a bit with procedurally generated terrain textures, so I might play around with the tri-planar mapping as was suggested. I can see how it could be pretty handy.

Share this post


Link to post
Share on other sites
The triplanar projection certainly will work, but is it needed? In my experience if you are using procedural textures (perlin-noise-based for instance), there is such a high resolution for the final texture output that the stretching is hardly noticeable if you avoid really sheer cliffs..

Share this post


Link to post
Share on other sites
You could move towards a 3D texture mapping / storage.

There's a bit of research lately taking advantage of the fact we have enough storage to access 3D textures.

for example, 'Solid Texture Synthesis'
http://www.johanneskopf.de/publications/solid/index.php

~Main

Share this post


Link to post
Share on other sites
Quote:
Original post by Matt Aufderheide
The triplanar projection certainly will work, but is it needed? In my experience if you are using procedural textures (perlin-noise-based for instance), there is such a high resolution for the final texture output that the stretching is hardly noticeable if you avoid really sheer cliffs..


At the moment, I'm using basic bitmap images. I have experimented with procedural terrain texture synthesis, but support for using such is not implemented in the engine.

I have thought about experimenting with non-square textures which are 2 or 4 times as large in one dimension as in the other. I could place a 'tall' texture on one layer and a 'wide' texture on another, then blend between the two layers based on the normal at a given vertex. This way, steep cliffs that face mostly one direction would sample from the texture that encodes more texels in the [0,1] range in that direction. This might fix a lot of the stretching. I'll have to try it and see how it goes. I doubt for a 'checkerboard' texture as in the examples above it would do anything, but for similar appearing dirt or stone textures, it would probably be fine.

Share this post


Link to post
Share on other sites
From a crude first attempt, blending the two layers seems to work okay. With a little more fiddling with the final blend into the base terrain to hide the fact that the long and wide layers are compressed relative to the base, plus some tweaks to the calculation of the weighting factors, I think I can achieve some acceptable results. Pity it takes up 2 terrain layers, though.

The blended terrain

Share this post


Link to post
Share on other sites
You can definitely improve on that result if, instead of interpolating between multiple planar textures, you interpolate between a planar mapping in the XY plane (assuming Z is up) and a cylindrical mapping where the cylinder is about the Z axis. This way you do not get any blending distortions on the sides of steep vertical objects, if you have a "hump" coming out of the ground then the only place blending would occur would be at the tip and base of the hump.

Share this post


Link to post
Share on other sites
I hope this thread is not too old to reply to, but could you explain what you mean by cylindrical mapping?

I too am trying to solve this texture distortion for terrain heightmaps and haven't yet found any good ideas beyond this thread.

JTippett, have you had any further success in reducing the distortions?

Share this post


Link to post
Share on other sites
Quote:
Original post by Nairou
I hope this thread is not too old to reply to, but could you explain what you mean by cylindrical mapping?


Map the texture as if it is on a cylinder wrapped around the terrain. This will provide zero distortion, but will have the problem that all cliffs will be the same.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nairou
I hope this thread is not too old to reply to, but could you explain what you mean by cylindrical mapping?


Map the texture as if it is on a cylinder wrapped around the terrain. This will provide zero distortion, but will have the problem that all cliffs will be the same.

Share this post


Link to post
Share on other sites
Cylindrical mapping would only work if there's just one "mountain" and it's in the very center of the terrain. Basically, the cylindrical mapping assumes that steep slopes always face exactly toward or away from the center. It would not work in the general case where cliffs can be anywhere on the map and have any facing.

Consider the case of a mountain in the northwest (top left) quadrant of the terrain. Its eastern slope could be along the north-south centerline of the terrain, which means the cylindrical mapping would give you a constant U coordinate for the entire slope - resulting in worse texture stretching than with common planar mapping. You would also have serious texel density variations depending on the distance from the center.

Share this post


Link to post
Share on other sites
Quote:
Original post by JTippetts
Quote:
Original post by Zipster
Is there a particular reason why you're trying to eliminate the stretching?


Mostly OCD, really. Every time I see a stretched cliff, my inner psychotic 'fixer' screams at me to do something about it. [grin] All of my terrains are randomly generated, so special-case fixing of the terrain texturing doesn't seem like the best solution, since I really need a general-case one.

Thanks for the posts, everyone. I've been playing quite a bit with procedurally generated terrain textures, so I might play around with the tri-planar mapping as was suggested. I can see how it could be pretty handy.


If it is procedural, you might be able to use a slope-dependant texture space. By this I mean using an approach similar to CLOD, where you generate lower-resolution textures in smoother areas - not necessarily easy to do, but it should look perfect.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this