Archived

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

fireking

taking a closer look at .raw files used as heightmaps

Recommended Posts

ok, ive spent a lot of time questioning .raw files being used as heightmaps, and ive also spent a lot of time trying to figure out why i have a problem with using them ok, first, like in almost any terrain engine, there needs to be a defined size for each map. Whether you define that for all maps, or for each map individually, doesnt matter. The terrain is usually aXa, a being the same number. Lets say, for example, that a = 1024 ok our terrain is 1024x1024.. In picture data, this means 1024 pixels by 1024. When we load this into our terrain engine, this could mean tiles, pixels, quads, sections, blocks, whatever you wanna call it. Now, lets say you make a 1024x2048 imagine. Thats two terrains, on top of each other. If your using photoshop, you can just render some black/white clouds. You cut this image right in the middle. You now have 2 1024x1024 images. Change image mode to grayscale, and save each as .raw. Now, theoretically, those two images, when aligned in the same way drawn, they will connect to each other perfectly. When rendering these heightmaps, you'll find that they dont look like they connect though. This is because it was split right down the middle and dont share a common border.. Now, to solve that problem, you write a function that modifies the heightmap array after loading it, so that each neighbor for each side shares a common border. Its a simple algorithm, and ive accomplished this much. Now lets define how we are rendering these terrains. in addition to the map size that we defined, we also define a step size. This step size save's us some FPS, time, and memory (well kind of). Basically, instead of rendering a height value at every x/y on the heightmap, we skip through it a bit, using step size. A common step size for 1024 is 16 or 32. Hopefully youre still with me. Now, in order to draw this heightmap, we have to loop through each x,y in the heightmap, skipping over values using step_size. example:
for(ix=0;ix < MAP_SIZE;ix+=STEP_SIZE)
{
 for(iy=0;iy < MAP_SIZE;iy+=STEP_SIZE)
 {
  drawstuff();
  ...
 }
}
   
so far so good. But ah, this creates another problem! Now that we have a step size, we're skipping values! uh oh, terrain's probably wont line up now. No need to worry, the average neighbor algorithm still holds true. But lets look at how we render this terrain first, we're using triangle strips, to speed up the process a little bit. Secondly, when we define the second vertex in each x,y point we step on, we have to put z as z+=STEP_SIZE. This changes our loop.
for(iz=0;iz < MAP_SIZE-STEP_SIZE;iz+=STEP_SIZE)
{
 for(ix=0;ix < MAP_SIZE;ix+=STEP_SIZE)
 {
  drawstuff();
  ...
 }
}
   
you might be asking why we added - step_size. Well we added it because you're drawing +step_size on each x/y, we wouldnt wanna draw past the actual terrain data. Ok, we finally are drawing the terrain we want it, in the way we want it. But there's one last problem! Yes, one last problem exists that we need to solve. Imagine your terrain as a square...
===============
|             |
|             |
|             |
|             |
|             |
===============
   
since we're using array's, a 1024x1024 map becomes 0 - 1023 in both directions. as we loop through the terrain, we're drawing each and every point without going out of bounds of the array. That should mean that we're drawing EVERY point in the heightmap, (except those skipped by step_size). Ok, so what's missing? Well if you test out all the theories i described (kind of vaguely, but you get the picture) you'll find that a strip on the last z, and a strip on the last x, in the width/length of STEP_SIZE is missing!
++++++++++++++++***
+              +  *
+              +  *
+              +  *
+              +  *
+              +  *
+              +  *
++++++++++++++++  *
*                 *
*******************

+ = drawn terrain
* = missing strip
   
If we modify our rendering loop to draw these missing strips, they return 0, because well, they are out of bounds of the array! But that should not be true. To back up my theory of this missing strip, i decided to render a textured quad, the same size as the terrain, with the same texture of the terrain, right above the heightmap. My results show that the quad is indeed the exact size of the texture as it should be, and the heightmap is missing -16 (or -STEP_SIZE) on its right and bottom edge. Ive even changed the iz < MAP_SIZE-STEP_SIZE part, which still is a valid concept, because drawing that area generates bogus values (if your height function returns 0 on bogus areas, then this will render steep slopes on both the right and bottom edge of the heightmap). Ok, so my question is, what the hell is going on here? I believe it has something to do with the equation for retreiving heights from the heightmap... HeightValue=HeightMapArray[(MAP_SIZE*Y)+Z] ive tried several combinations of x < MAP_SIZE or x < =MAP_SIZE (just guessing), staring with 0, starting with 1, and i really cant seem to figure out why it wont work correctly. If we're talking about points on the heightmap, i would think we were talking about points 1-1024, and if we're talking about places inside the terrain, we should be using 0-1023 well, im afraid this simple theory cant fully explain the phenomenon here, which from now on, im going to call, missing mystery strips If you can help me out, id greatly appreciate it! sorry this is such a long post, i figured i should take a lot of time to explain all the things i've went through to reach this point. [edited by - fireking on October 22, 2003 11:32:54 PM] [edited by - fireking on October 22, 2003 11:33:37 PM] [edited by - fireking on October 22, 2003 11:35:16 PM]

Share this post


Link to post
Share on other sites
*shrugs* All I did was create heightmaps that were 1 greater than what I needed. Instead of 256x256, I did 257x257. That way the edges always match up perfectly. Of course, I generate my heightmaps procedurally. . .

Share this post


Link to post
Share on other sites
the edges match perfectly, thats not the problem, the problem is that it will not draw the very last value on right/bottom edges of the .raw file...

i mean, of course i can draw them, and i can even make them line up while rendering using glTranslatef(), but what im saying is, its not drawing everything it should be cuz the terrain should be 1024x1024, and i verified what it would look like by drawing a quad the same size. even if i moved each terrain next to each other, biggity blam, the entire texture isnt being rendered, cuz of that damned missing strip.. I dont want to modify texture coords, cuz thats not the point.. If we did that, we're escaping the fact that the entire terrain is not being rendered!

what im wondering, is .raw files kind of glitched being used as height maps or what? but im still waiting for an answer to the first post as well, not just an answer to this post..

[edited by - fireking on October 22, 2003 12:16:07 AM]

Share this post


Link to post
Share on other sites
The format that the heightmap is stored in shouldn't really make a difference. The thing is that a 1024x1024 heightmap (where each pixel represents a vertex) will produce a grid containing 1023x1023 squares. The result of that will of course be a missing strip of squares on two edges. That is another reason why all my heightmaps one greater than they would otherwise need to be. A 1025x1025 heightmap will always connect perfectly with others.

Taking your example of a 1024x2048 heightmap, one could simply take 1024x1025 of it for the first segment. The second segment would start at the 1025th row, sharing those pixels with the first segment and go on to the end. Take this bit of l33t ASCII art, for example:

********@$$$$$$$
********@$$$$$$$
********@$$$$$$$
********@$$$$$$$
********@$$$$$$$
********@$$$$$$$
********@$$$$$$$
********@$$$$$$$

That represents a 16x8 heightmap. Splitting it as I suggested, the * represents the pixels that are solely owned by the first (left) segment and the $ represent the pixels solely owned by the second (right) segment). The @ are those pixels shared by the two. The result is a 9x8 heightmap and an 8x8 heightmap. Using each pixel as a vertex, the resulting terrain will fit together seamlessly because they share vertices. Also, the resulting terrain will consist of a 8x7 square grid and a 7x7 square grid:

********$$$$$$$
********$$$$$$$
********$$$$$$$
********$$$$$$$
********$$$$$$$
********$$$$$$$
********$$$$$$$

. . . where * is a square owned by the first segment and $ is a square owned by the second.

[edited by - Ostsol on October 23, 2003 9:09:08 AM]

Share this post


Link to post
Share on other sites
There's nothing wrong with .raw files fireking. Your image should be 2^n + 1 like Ostsol said.

lets say map size is 1025x1025 and step size is 8. That means the loop you describe would look like:

for(x = 0; x < 1024; x+=8)
for(z = 0; z < 1024; z+=8)
draw()

in the last iteration of the both outer/inner loop, the values will be x = 1016, z = 1016. If you're adding step size to this inside the rendering code, you get 1024 (the last valid part of your heightmap), and none of your heightmap "misses" getting rendered.

by the way, if that is how you're drawing your terrain, you might want to consider display lists. They will be much faster for strips like that.

[edited by - shadow_bobble on October 23, 2003 12:10:13 PM]

Share this post


Link to post
Share on other sites
well there are two things i dont like about ostol''s advice. Number one he says i should change the size of my maps. I don''t want to do that, absolutely not. The idea of the project is to get the program to render the terrain as it is.

i have no problem making terrain''s connect, that last strip just never gets drawn. what if i changed map size within program, but kept file map size the same... for instance, .raw file is 1024 by 1024, and the program loads it into an array thats 1025x1025..

thats a hacked way of doing it, but would it work? please note that the 1025 area wouldl be blank, allowing me to access that last strip... remember that my solution is not to edit the images, i want to render the images and heightmaps, not edit them. so if this idea doesnt work (ie: requires new area to have height values) then ill have to find another solution.

Share this post


Link to post
Share on other sites
It''s too bad you don''t like his advice because he''s absolutely correct. It''s quite standard in published terrain techniques to use 2^n+1 x 2^n+1 terrains. There are tons of heightmaps online that follow these specs. If you want to have a product that works at the end of the day, I would suggest a little elbow grease instead of filling it with "hacks".

Share this post


Link to post
Share on other sites
quote:
Original post by fireking
well there are two things i dont like about ostol's advice. Number one he says i should change the size of my maps. I don't want to do that, absolutely not. The idea of the project is to get the program to render the terrain as it is.

i have no problem making terrain's connect, that last strip just never gets drawn. what if i changed map size within program, but kept file map size the same... for instance, .raw file is 1024 by 1024, and the program loads it into an array thats 1025x1025..

thats a hacked way of doing it, but would it work? please note that the 1025 area wouldl be blank, allowing me to access that last strip... remember that my solution is not to edit the images, i want to render the images and heightmaps, not edit them. so if this idea doesnt work (ie: requires new area to have height values) then ill have to find another solution.

Yeah, you could do that, too. Just fill the 1025th row/column with the first row/column from the next heightmap.

[edited by - Ostsol on October 23, 2003 3:52:22 PM]

Share this post


Link to post
Share on other sites
when using the 1d array system, do you have to go from 1-1024 for points x and z, or do you have to go from 0 - 1023 for points x and z, using the equation

index = (z*width)+x

basically im asking, what range is x and z based on, in this equation...

Share this post


Link to post
Share on other sites
fireking, a good engine also needs good data. In theory, it should handle bad data gracefully (not core-dump, for instance), but it doesn''t have to fix bad data. It seems like it would be easier to fix your data once, than try to do fixes real-time everytime it runs. Just my thoughts, do other people agree?

Share this post


Link to post
Share on other sites
well, the whole idea is that everything is supposed to be based off of even numbers, plus, i made this huge world map, and it would take tons and tons and tons of work to make each map (256 of them) have shared borders with its neighbors

so i wrote a neighbor function, but it still doesnt render the last strip

i finally decided on just letting it not render the last strip, then when the next heightmap is connected to it, its lined up at 1024-step_size, matching edges with the averageneighbor function. it works, but the texture is still 1 step_size bigger on two edges, so i modified texture coordinates so that the texture is shrunken just a bit to fit the 1008x1008 terrain (originally 1024x1024 now - step_Size which is 16)

it works pretty good, and since each block is scaled by 100, the fact that the last strip missing and being ignored doesnt really matter, cuz the terrains connect to each other anyways.

the only thing i have to worry about, which i hope doesnt happen, is situations where that last strip contains a terrain transition that is important to the game world. im pretty sure i wont come across any areas like that.

terrain programming was fun though! im not done yet, i think i wanna do procedural textures now, so that i dont have these crappy looking textures stretched over the surface making the gamer''s puke.

my next adventure, after this, will be making and rendering simple dungeon maps. You know, the good ole tile based dnd type stuff, just in 3d. I believe it will be much easier than the terrain, but i dont want to jinx my self

thanks for all the help though guys, i keep telling my self to get the open gl programming book, but i just cant break down and do it, cuz i bought that programming role playing games in direct x book, hoping that id find it fairly easy, but direct x makes me puke... i like open gl and im just gonna ignore the fact that i purchased that book for now (putting off reading it) and work on open gl.

Share this post


Link to post
Share on other sites