Height from heightmap

Started by
10 comments, last by Codeka 15 years, 3 months ago
I want to texture my terrain by using a "blurry" basic texture and several detail textures, where the visiblity of each detail texture is expressed by a blendmap. The detailmap is stretched over the whole terrain and stores the opactiy for each layer in its color channels (for example red=sand layer, green=gras layer). If the resolution of the terrain vertex grid matches the resolution of the blendmap (so there is a 1:1 relation between the vertices and the blendmap texels), it is clear how I can calculte the texel values of the blendmap: To calculate texel[3][5] (for example) I read the height at vertex[3][5] and based on the layer contraints (for example sand goes from 0 to 20m and gras from 20m to 100m) I determine the opactiy value for the layers. But I want to decouple the blendmap resolution from the vertex grid resolution. For example it should be possible to use a 1024x1024 oder 128x128 blendmap for a 512x512 terrain. Lets say the terrain size is 256x156 and the blendmap size is 1000x1000. How could I determine now the opactiy values for texel[3][5]? What would be the best method to calculate the blendmap when its resolution differs from the terrain vertices grid? Thanks!
Advertisement
newbitmap.width = 1024
newbitmap.height = 1024

texel[3][5] = newbitmap[3 / blendmap.width * newbitmap.width][5 / blendmap.height * newbitmap.height];

to make it faster, precalculate:

scalewid = 1 / blendmap.width * newbitmap.width
scalehgt = 1 / blendmap.height * newbitmap.height

then multiply:

texel[3][5] = newbitmap[3 * mulwid][5 * mulhgt]
texel[2][6] = newbitmap[2 * mulwid][6 * mulhgt]
texel[8][7] = newbitmap[8 * mulwid][7 * mulhgt]

make sense?
Quote:Original post by CPPNick
make sense?


To be honest: No.

What is newbitmap? Why do you set its size to 1024? And I don't understand your index calculation. 3 / blendmap.width * newbitmap.width for my example means:
3 / 1000*1024 = 0. So regardless which index I take it will always map to 0.

Your code cant work because it's not just a matter of recalculating some indices. If I want to create a 1000x1000 blendmap from a 256x256 terrain then there just aren't enough height samples for all blendmap texels so I need to do a (linear) interpolation of the existing heights to get new heights.

To make it easier: If I have a 2x2 terrain and I want to build a 4x4 blendmap, then I can calculate texel[0][0] based on the height of vertex[0][0] but for texel[0][1] and texel[0][2] there is no corresponding vertex so I need to interpolate a new height from vertex[0][0] and vertex[0][1]. Is this correct? I wonder how I could do this the best way.
and you using a pixel shader

map the "blendmap" to the terrain and in the pixel shader just obtain the texel as you usually would from the blend map and use that data, to set the corresponding grass, rock or whatever of the current pixel.
??

My problem is how to CREATE the blendmap. And actually I don't want to use shaders (though it would be possible).
Quote:Original post by schupf
My problem is how to CREATE the blendmap.


An artist? I don't see why you'd need a texture whose pixels are created directly from height values. After all, if that's all you wanted, you can do that in the shaders without the need of a special texture at all.

I would think by making the blendmap by hand, you'd be removing the "sand at x height, grass at y height" limitation.
Quote:Original post by schupf
If the resolution of the terrain vertex grid matches the resolution of the blendmap (so there is a 1:1 relation between the vertices and the blendmap texels), it is clear how I can calculte the texel values of the blendmap: To calculate texel[3][5] (for example) I read the height at vertex[3][5] and based on the layer contraints (for example sand goes from 0 to 20m and gras from 20m to 100m) I determine the opactiy value for the layers.

But I want to decouple the blendmap resolution from the vertex grid resolution. For example it should be possible to use a 1024x1024 oder 128x128 blendmap for a 512x512 terrain.
make sense?


from what I understand, you want the address of a pixel in a bitmap/texture that is larger/smaller than the area that you plan to put it on.. right?

for example:
If the dimensions of a vertex grid is 512 X 512.
we will call this vertex grid:
int vertgrid[512][512];

you want to pick a pixel in that vertex grid, and find out what pixel from a 1024x1024 bitmap would go there. let this new texture be stored in this array:
int newtexture[1024][1024];

vertgrid[3][5] --> pixel (3,5) in the vert grid
you can't do the following, because they are different sizes:
vertgrid[3][5] = newtexture[3][5]; // =(

so here is how you find the address of the pixel in newtexture:

newX = 3 / 512 * 1024;
// (3 / 512) = 0.005859375
// 0.005859375 * 1024 = 6

newY = 5 / 512 * 1024;
// (3 / 512) = 0.009765625
// 0.005859375 * 1024 = 10

so this means that pixel that goes in vertgrid[3][5] will be taken from newtexture[6][10].

this is simply the math to find the address of a pixel in a larger bitmap that corresponds to the pixel in the smaller bitmap...as for "creating a blendmap"
you might wanna google that one...
Quote:Original post by CPPNick
from what I understand, you want the address of a pixel in a bitmap/texture that is larger/smaller than the area that you plan to put it on.. right?

No. Look at my second post.

I wouldn't get any benefit from just mapping the indices from the blendmap to corresponding indices in the vertex grid (I could just use the same resolution as the vertex grid).

I want to sample a heightmap BETWEEN the existing height samples. Imagine this 3x3 heightmap:
|----|----|| \  | \  ||  \ |  \ |   -----------| \  | \  ||  \ |  \ |   -----------

It has 9 vertices, 4 cells and 8 triangles. I can sample this heightmap at indices with integer indices like [0][0] (which gives the height at the top left vertex) or [1][2] (which gives the height of the vertex in the second row and last row). But I need to sample this field EVERYWHERE inside the grid, not just at the sample points. For example I need to sample the height grid at samplepoint [0.7][0.2]. This samplepoint is in the top right triangle of the top left cell, but obviously no height is stored for it.

Meanwhile I think I have found a solution (though I dont know if it is a good one;):
First I pick the triangle in which the sample point lies. For example [0.7][0.2] would give me the top right triangle of the top left cell:
A----B| \p | |  \ |  X----C

A,B,C are 3D vertices in the vertex grid, and p is the sample point (currently X does not exist).
Then I linearly interpolate the heights of A and B alonge the edge AB (lets call the result h1). Then I calculate a vector v from B to C: v=C-B and add it to A to get a new point X. X lies in the plane of the triangle. Now I interpolate between X and C (which yields h2) and finally interpolate between h1 and h2 to get the height at p.
Does this work? Any better ideas?
unless I am misunderstanding your question, the idea I gave still applies.

V1----V2----V3
| | |
|.(x,y) |
V4----V5----V6
| | |
| | .(x2,y2)
V7----V8----V9

assumes V1 is (0,0) in your bitmap
XFromBitmap = ((x - V1.x) / (V2.x - V1.x)) * bitmap_width
YFromBitmap = ((y - V1.y) / (V4.y - V1.y)) * bitmap_height
pixel(x,y) = (XFromBitmap, YFromBitmap)

assumes V5 is (0,0) in your bitmap
XFromBitmap = ((x2 - V5.x) / (V6.x - V5.x)) * bitmapwidth
YFromBitmap = ((y2 - V5.y) / (V8.y - V5.y)) * bitmapheight
pixel(x,y) = (XFromBitmap, YFromBitmap)

if this needs to be done in three dimensions, you will need to consider the points (x,y) and (x2,y2) vectors from the top left vertex in your mesh, and use the "Dot Product" to find how the points relate to segments V1-V2, V1-V4, and V5-V6, V5-V8. acos = inverse cosine in C++
good luck =)
Quote:Original post by CPPNick
unless I am misunderstanding your question, the idea I gave still applies.


I think the problem he's having is not calculating the corresponding pixel in the blendmap, it's calculating the height of the heightmap at non-vertex points. So the height at (5.0, 8.0) is easy because there's a vertex there - just take the y value from the vertex. The part he's struggling with is sampling the height at (5.4, 8.2) (say).

What you need to google on is "bilinear interpolation".

Still, I think you're doing yourself a disservice by trying to calculate this blendmap algorithmically. It'd be far more flexible if you simply allowed an artist to do it. Like I said, if all you're doing is basing your material on the height of the heightmap, you can do that entirely within the vertex/pixel shaders without the need for a blendmap at all.

This topic is closed to new replies.

Advertisement