Monday 28 May 2012

OpenGL First Steps: Terrain

Good news! I have finally managed to get around to producing something with my noise function that I discussed last week. I have wanted to play around with some graphics programming after doing my final year graphics coursework, so I decided to learn the basics of OpenGL, as well as refresh my memory on C++. This has also been somewhat inspired by Shamus Young's various similar projects which he has posted many updates on.

I'm not planning to be anywhere near as ambitious as these projects, nor do I have any specific goals for what I want to achieve, but I did want to do some procedural terrain generation, hence why I started by creating 2D height-maps procedurally. This was then followed up with large amounts of shouting at the Internet while trying to understand the basics of OpenGL. Most of the resources with regards to OpenGL are pretty undecipherable at first, but I found that looking at some small open source examples (most notably the SDL implementation of the OpenGL gears) and reading through this helped a lot.

This is where I am currently at:

Almost looks like some kind of terrain I guess?
Currently my program can generate a single segment of terrain of arbitrary size, using terrain quads of arbitrary size as well. There are also some very rudimentary controls for controlling the camera. I am planning to expand this to allow the dynamic creation of new terrain sections while moving around the world, textured terrain,  improved lighting and anything else I think of as I go along.
I have already run into various issues though with my terrain generation algorithm. At first, it was generating terrains which look this:

It kind of looks right, but there is something very weird also going on causing these deep chasms and vertical walls. It turns out these issues are only occurring when negative coordinates are used. This was evident as a quarter of the generated terrain looked fine (the centre of this terrain segment was at the world origin, leaving one quarter to be in negative x coordinates, one in negative y coordinates, and one in both negative x and y coordinates.)

The section on the right looks fine, the rest is full of terrible chasms and cliff faces.

I have been able to work around this issue by using absolute values in part of the terrain calculation, however this does mean the terrain is now symmetrical. This is not an ideal solution, but it is unlikely to be noticeable unless looking at the terrain from a birds eye view. This is marked as to fix in the future, but this will have to do for now.

Next up I will probably trying to implement some sort of useful controllable camera, as well as trying to stitch together terrain segments.


So I managed to find out what the problem was. One of the steps of the terrain generation involves interpolating between two values and the original code I was using does not work correctly with negative values.

The code used to have the following section in it:
 int integer_X = (int)x;
 float fraction_X = x - integer_X;
This takes a floating point value x, then determines the fraction based on the value after the decimal point. This is done by casting to an integer, then subtracting the integer value from the original value. This code doesn't work with negative coordinates, because the value returned by casting the int is then greater than the original floating point value, not less than like it is with positive values. This means that you end up interpolating based on the other direction, which is what caused this issue.

This was fixed by using the function floor which returns the a lower value integer, and works with negative values.

The difference this makes can be seen in this small example:
X = 2.300000 int(x)= 2 
X = 2.300000 (int)floor(x)= 2 

Y = -2.300000 int(y)= -2 
Y = -2.300000 (int)floor(y)= -3 

X fraction : 0.300000 
Y fraction : 0.700000
We want the fraction to be 0.7 not 0.3, as this then makes the interpolation value consistent with the way positive values are handled.

No comments:

Post a Comment