Friday, June 5, 2015

c# - Efficient Method of Rendering Massive Terrain in XNA


I'm creating an XNA game that requires a huge space for players. Currently, the test heightmap I'm using is 4096x4096, and is saved as a 4-bit BMP.


What I'm trying to do is take that huge heightmap file and render it in the game. The problem I'm running into is the fact that it's inefficient to load the entire terrain into memory at once, as it will use majority of available memory.


Another problem I've run into is that I cannot render the terrain all in one primitive because of a hard-limit set within XNA.


With that said, I've come across a number of solutions, all of which I have listed below:



  • Rendering based on the current user's location - basically drawing a square around the user no matter their orientation within the world. This isn't exactly what I wanted either, because you're still rendering space that the user does not see.

  • Rendering based on the user's orientation and position - I found a formula to retrieve a triangle that is supposed to have what pixels of the heightmap are supposed to be rendered, but this proved to be very difficult.

  • Splitting the terrain into multiple chunks and rendering which ones are closest to the user - Still not very efficient as you're still rendering chunks that people won't see. And it's work-intensive because then I have to split my heightmap into several pieces, and scalability becomes a large problem.



After trying those solutions, I'm fresh out of ideas for what to do. I've received some answers where people are telling me to do these complex algorithms, but I simply have no idea even how to approach doing them.


So basically I'm asking for a simple, straightforward way of rendering humongous terrains in XNA with utmost efficiency.


I'm rather new to game development in general, but I am willing to research if it seems promising.


Update 1: After researching the geoclipmapping method, I started to code with that. I have all the math done, and the game runs. However, it is extremely inefficient - which is probably bad coding on my part. It runs at 2FPS and uses an entire core of my CPU. I'm going to try and improve the code, but I think I'll need more help, so here is a Pastebin of the code for the Terrain manager class. I'll post back with more results later if I ever get it to be more efficient.



Answer



The chunks approach is typically what is used. Rarely is it efficient to test every triangle out of hundreds of thousands to see if you should be rendering it. Instead most terrain rendering algorithms employ a spatial data structure to dynamically render the visible parts of the terrain.


An easy to implement data structure is called a quadtree. In short, to use a quadtree you would find the player's viewing frustum, intersect it against the top level of the quadtree, and for any chunks that are partially viewable (ie, the frustum planes intersect the chunk) you subdivide and test all the children chunks, omitting ones outside the frustum. This will give a pretty close approximation to the actual visible geometry with only a few levels of recursion.


More advanced terrain renderers use an algorithm to tune not only the viewable geometry but the detail of that geometry as well. Geomipmapping (and its relative geoclipmapping) is relatively popular at the moment for doing that but isn't a trivial thing to implement.


edit: Here is a decent description of both geoclipmapping and the frustum culling.


I also have some doubt as to whether 4 bits for the heightmap is actually enough to produce a nice looking terrain unless you're doing a lot of smoothing on the result.



No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...