Sign in to follow this  
xynapse

Rendering terrain the 'right' way ISOMETRIC approach

Recommended Posts

Guys, after a short/long break i finally decided to go through terrain stuff again.

Couldn't ask earlier as i was involved in something that was not related to GFX programming but now i have a clear assignment of what has to be done for the customer.

The main task is to prepare the isometric engine that would utilize the terrain rendering mostly - as they need the terrain to look ultra realistic.

I was asked to 'have a look at the Diablo3 screens' - and it seems they are trying to achieve this type of terrain detail and no less.




So the questions before i start to implement anything are kinda more to 'shed a light' than to 'do me a favor and paste your code here'.

I am not going to say ' i never did that before' - i tried many times with more/less successful effect, but this time i would like to have it done the right way really.

This is why i have split this post into few points, let's start from the beginning : Handing the size / buffers for the terrain.




[heading]TERRAIN SIZE[/heading]

Keeping in mind we are speaking about Isometric view i am thinking of having a 3km x 3km map that can be rendered fast and without 'limits'.

The limit is the size. Let's say they're gonna make 5kmx5km instead of 3kmx3km and this needs to work too. Because of that, the 'technology' that stands behind the scenes

is the key to the success here - and this is why i would like to ask you guys for an advise.




APPROACH.




Editor:

- Map generator creates a RAW heightmap file that is 3072 x 3072.




Engine:

- Parser goes through the file and loads up the height data

What should happen when a height is loaded, shall we go and build one BIG VBO or split the map into pieces - so we can find out which piece to render later on?

Is we should split it: how should we achieve that, any algorithm or any well known approach for isometric?

Do we pack the VBO into VAOs ([i]glGenVertexArrays[/i]/[i]glBindVertexArray[/i]) or we forget about VAOs ( as I've seen somebody was saying it's deprecated 3.1+) - what do you think?




This is very important to be done correctly as later on we shall be rendering the only part that is visible and computation should be done very fast.




- After the VAO/VBOs are made calculate (per frame on CPU side) the actual 'part' of the terrain to be rendered by :

a) using player position

b) using frustum




Is there any other better option here, anything faster or already known to be the only solution here?







Now as we know, this is to be Isometric - i am looking for a fast-implementation - of course i know that handling 10km x 10km instead of 3km x 3km can be more time consuming - but i still believe that

it shouldn't be something that can't be done. Can we all gather around and find the right way to this Isometric terrain rendering approach please? Maybe there's somebody that already made an isometric game and can share his view with us.





Hopefully not only me but others will find this post helpful - it we'll keep it going - i will sum this all up so we can make it a good starting point for beginners.




Thank you for any input into this.










Share this post


Link to post
Share on other sites
If you talk about isometric terrain/engine I guess there are pretty much two approaches:

Traditional (I assume youre Not using this technique), as resources and computing power were rare, terrain and graphics were prebuilt in an isometric view and tile based style. They were nothing more than images which were loaded seuquentially (one might remember the tiles popping up to late during a lag in Diablo 2) as the camera would not change its position, apart from maybe rotation around the character. This is the true isometric style when you talk about isometric.

Today though, as we have the resources, all the assets are real volumetric meshes along with the terrain (I assume you are using this technique). That doesnt mean that the terrain cant be sliced up in patches and get asynchronously loaded in the background ("new" multithreaded technology). I havent really looked into Diablo 3 but I think the camera is fixed there too, so this makes things alot easier when it comes to the resource management. Isometric here means nothing more than how the camera and its look point are positioned and fixed in the 3D world. If you have the appropriate harddrive/CD/whatsoever resources, you can have a kajillion by kajillion terrain and just simply load the patches youll need next and discard the old ones from memory, since youll only render that many at once (fixed view!) and not where your view could change drastically within the next frame. This kind of tile-based implementation is utilized in many if not all MMORPG style games today where you can roam in huge worlds (WoW does it too), except the isometric restriction of course.

You solely need to store the y-values on the harddrive and address the correct value in the file when loading the next patch or you could store it in a heightmap, as you said, and just load that one. Many heightmaps can make up a big terrain too. It really depends on how your engine works or what either your URS/SRS/SDD whatsoever says. You can work with or without heightmaps.

Ultra realistic is only a question about your available resources and implemented shaders.


Some more info would be helpful tough. What hardware are you on? What kind of resources do you have? Forward or deferred rendering? etc..

Hope that helps...
DC

Share this post


Link to post
Share on other sites
DC, thanks for pointing few things out - but to specify and keep this post on the right track here's what exactly i am targeting.

The engine should run on modern PCs, i am now coding with 2x GForce 9800GTX - which isn't that new, but keeps the frame rates at high values.

Forward rendering / deferred rendering - i would like to go through this later on - instead of throwing all into one post.




The thing i [u]need[/u] to achieve is :

- An isometric camera ( that can be rotated around player in 3d) - this is a 3d project, it has nothing to do with a 2d tiled engine.

- An 'unlimited' kind of terrain engine that is optimized for rendering purposes - this is very important, as the terrain does the main 'effect' role here -

i am aware it's mainly up to the GFX team to polish it's final look, but besides the look it has to compute fast and work fast.

And this is why i asked about well known approaches.

From what i have found - an Quadtree Frustum culled terrain should do the job - if so,

- how does a 'pseudocode' implementation look like,

- what stands behind the theory and how fast it can be,

- how do you handle the VBOs / terrain splitting for quadtree purposes?




That's all in regards to the first phase - which is "Handling Terrain" - in regards to rendering methods - i will come back as soon as we get this first stuff resolved.













Share this post


Link to post
Share on other sites
Just a small nitpick: if it's 3D, with a fully rotatable camera, then it's not isometric. Diablo 3 is not isometric. Isometric has a pretty [url="http://en.wikipedia.org/wiki/Isometric_projection"]fixed meaning[/url], and even taking into account the stretching of that meaning that video games have done (ie, any orthographic projection, ie axonometric, tends to be called isometric), a fully 3D camera still is not isometric. It's just a 3D third-person view. That being said...

If the camera is constrained to a fixed angle looking down at the map, and no horizon is visible, then you can make some assumptions. I have found good results in the past with using a spatial hash-map of nodes, where each node is a chunk or tile of terrain, drawn as a single mesh buffer. The map is organized as a hash-map; ie, each terrain tile has a pair of world coordinates that are used as a hash key, and the tile is placed into a map keyed on that hash. This makes the hash-map indexable via world coordinates, but since it is structured as a hash rather than a 2D array, the world is effectively infinite. Coordinates can be arbitrarily large and even infinite, and chunks of terrain can be streamed in from disk as needed with minimal overhead in the map management. Something like this:

[code]
struct KeyType
{
int world_x;
int world_y;

bool operator <(const KeyType &rhs)
{
return (x < rhs.x && y<rhs.y)
}
};

std::map(KeyType, TileMeshBuffer) terrain_map;

[/code]

To draw the terrain, the visible view can be calculated by reverse-projecting the corners of the screen to determine the frustum edges. These edges are tested against the extents of the hash-map to determine the coordinates of a box super-imposed on the hash-map the encloses the visible area. By calculating the coordinates of these line intersections with the top and bottom bound planes of the world (the maximum and minimum Y coordinate extents) you can calculate a box that contains all of the terrain tiles that need to be drawn, without the overhead of the recursive frustum tests of a quad-tree, which can be quite slow with very large worlds. This sort of frustum calculation essentially runs in constant time regardless of the size of the world. Once you have calculated the visible box, you can run some type of rasterizing or iterating algorithm to draw the enclosed terrain tiles.

After that, it's a very simple matter of just feeding the terrain tile mesh buffer to the rasterizer using the correct transforms. No LOD is necessary, since a terrain tile is never viewed from far away, and since the range of the visible area is naturally constrained by the camera angle.

Share this post


Link to post
Share on other sites
As I said before, for the camera, youll only need some simple math (you might want to look into [url="http://en.wikipedia.org/wiki/Axonometric_projection"]this[/url] or [url="http://en.wikipedia.org/wiki/Isometric_projection"]this[/url] respectively).

I dont know what you have in mind. But usually, in isometric projected games, youre never able to see into the distance (far away terrain/objects) so all that frustum culling, quadtree implementation can be left away since youre only going to render one to a few patches at once which are handled dynamically, there never will be more patches that need to be culled. This makes things very fast and you can put more detail onto and into the terrain. How fast the terrain rendering will be depends mainly on the grid sizing (vertex distance) you are planning to use and further down the road how many entities (environment, players, mobs, whatsoever) are placed on it.

Example:
[url="http://www.celedyr.net/blogpics/2006/heroesv1.jpg"]HOMM V[/url] (although you CAN move the camera down, but you can ignore that aspect)
[url="http://harlevin.net/wp-content/uploads/2011/01/diablo3.jpg"]Diablo III[/url]
[url="http://3.bp.blogspot.com/-QFm9cndGe3I/TgJijHyMr4I/AAAAAAAAC0Q/b78kWiqSNUg/s1600/Warcraft+III+Gameplay.jpg"]Warcraft III[/url] (like any other RTS camera)

No view into the distance, no culling needed, no tree needed!

Share this post


Link to post
Share on other sites
Excuse me saying 'Diablo' type all the time, what i really meant is a Camera that is looking on the player constantly from a defined height - but player can rotate it around without seeing the horizon.


DC - you got the right point, it should look exactly as per :

[url="http://www.celedyr.net/blogpics/2006/heroesv1.jpg"]http://www.celedyr.net/blogpics/2006/heroesv1.jpg[/url]




So if there is no culling made, how do i know which part of the terrain mesh to render?

Share this post


Link to post
Share on other sites
You have the player/camera position, so you know what to load and render :). In a very simple manner, you can choose a patch size greater than the frustum of the camera and if youre getting close to the end of the patch you start to load the next patch in the background so it will be ready when the frustum reaches the next patch. Not really elegant and youll run into some difficulties when you reach a corner where 3 more patches connect, but something along those lines ;).

Share this post


Link to post
Share on other sites
So what you're saying is:




- Get the player position

- bind the index buffer

- update the index buffer to point to the vertexes 'around' the player within a static 'distance' ( distance a bit bigger than the frustum so we won't see terrain ending at the borders )

- draw the vbo using previously updated index buffer







Should do the job quickly?



Share this post


Link to post
Share on other sites
There are many possible ways to achieve what youre trying but I suggest you to not manipulate any buffer since doing that (locking) "every" frame for the main patch is very slow.

First off, youll never have to manipulate the index buffer since the mesh build-up will never change.

So a first example could be:

Have only one index buffer.
Prepare several (only a few!) vertex buffers (depending on the patch size) with the x/y/z/texture values of the terrain around the player and discard/load new vertex buffers in the background. Either by drive stored y-floats or a heightmap.

Or:
Hardware instancing several terrain patches, then youll only need one IB and one VB and you just update their location with the stream data. This requires you to use heightmaps though so you can fetch the vertex y-pos from the heightmap in the shader (SM3 required). This might require some more texture memory depending on your grid resolution and texturing technique. Modifying/editing the terrain is cheaper with this method IMO.

A more brute force approach could be:
Create several meshes (ID3DXMesh in DirectX9 for example) and fill them will all the needed parameters and discard/load new each patch when needed. This is easier to handle and implement but will require more resources and overhead, but does not necessarily mean to be slower in your case. It does not require heightmaps except if you want to (same as the first example).


Which one you choose (or make up yourself) depends on your needs.

Share this post


Link to post
Share on other sites
DC, hold on a sec - i don't think you got that my terrain is to be a heightmap - there is nothing about 2d tiling in there, so as what i need to achieve is an RTS-Like rendering for the terrain, where "TERRAIN" is a normal RAW heightmap.




Just to clarify as i see we're not understanding each other correctly, the question is:


How to handle the terrain rendering for a RTS-LIKE game type.





- [b]How do i [/b]

[b]-- know which part of 10km X 10km terrain to render knowing the camera position and player position[/b]

-- Any culling for the terrain?

-- Any quadtree/octree algorithm for this?




And this is exactly what i am asking for, please do not think i'm talking about 2d/3d tiled game ;)




Share this post


Link to post
Share on other sites
you can have a heightmap and still break it up into tiles. a tile isn't necessarily what you think it is. in this case, splitting a heightmap into chunks is a logical thing to do. if you use a quadtree, then the leaf nodes will be the tiles. if you use a hash map like JTippetts talked about, then each tile will just be an entry in the map. Either way, a tile is just some NxN piece of terrain, not a 2D tile like you're thinking of.

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