Sign in to follow this  
solenoidz

Level data organization

Recommended Posts

Hi all... I was wondering how I should keep my mesh data in a level-like format. First I need to mention that I need to stream the level data. The world is supposed to be huge. First option (that I already have) Export all my triangles for a world chunk and store them in a bin file. That means for example that if I have 200 street lights along the roads a store every street-light mesh triangle, and so for the other meshes no matter if they repeat across the level. I then stream up all the triangles, for every street-light mesh(for example) I build an unique vertex buffer,fill it with loaded triangles which are already in wolrd-space and render them as they are with identity transformation. Hope that makes sense. Second option : The level is made up of unique meshes that repeats eventually across the level. Street-lights, same buildings here and there, fence elements, benches and stuff. Then I export every unique mesh in a separate file and for the level I export the index(name or something) for a mesh and it's transformation matrix. Then load up this info, load up every mesh that is in this world-chunk and their matrix and render them according to their transform. As I see it, every method has pros and cons. First one has repeating data all over and huge file size, since I store every individual street-light(for ex.) as a separate mesh with their triangles. Also I build separate vertex buffer for every street-light, but in the end I render the entire level with no transform calls, since every triangle is in world space already. That has huge file-size, loads slower, eats up more "vertex buffer memory", but for a level with very few repeating things it should be OK? Terrain mesh is unique, road-geometry is unique(it has unique curves and bends), all the street-light could be made as one mesh(grouped) and so on.. On the other hand - the second method loads only one street-light, loads all it's transforms across the level, and then switches matrices. Small file-size, fast load, but not suitable for non repeating stuff. Should I go for some kind of blend between the two methods ? Any guids on the subject would be appreciated.

Share this post


Link to post
Share on other sites
Well, your first step is undoubtly separating the unique geometry from the repeating meshes.
For the rest, streaming isn't much of a problem if you keep your granularity and latencies under control. You may have to break by temporal/local coherence and resource usage. Make sure you don't spend time on a feature you actually won't use. I don't count how many hours I spent tweaking my out-of-core systems and guess what? Nowaday's video cards alone have more memory than I need for the whole program...

You must have a special path for world's (mostly unique) geometry, because that's the trend which has been demostrated over the years with the assets.

So, in your case the 200 street lights should really be imported as entities, or external meshes. Whatever you pre-transform them or instance them one by one with proper transform matrices is somewhat the runtime shall be concerned with, not the format you choose to store data. Since the "object repeats 200 times" information is valuable, you don't really want to trash it if not for some good reason which is to be evaluated case by case from someone else.

A building which is repeated at the opposite sides of a city isn't a good candidate for this approach; it can still be instanced that way for the lack of a good reason in not doing so... but if your content is "real world" I am confident there will be little to no difference.

Share this post


Link to post
Share on other sites
I will try a blend between the two and see how it goes. I really don't want to loadup all the possible meshes in the game at the start of the game, and then walking around the level, stream objects id's and their matrices, and transform them around the camera.

Share this post


Link to post
Share on other sites
Here's how at least one popular MMORPG did it:

The "world" consists of 1 or more regions. No culling is performed against the world, everything is assumed to be present in it.
A "region" consists of 1 or more zones. The coordinates of a region are determined by using the smallest bounding box that will contain all zones. The minimum bounding box (x, y, z) of all zones becomes the top-left corner of the region bounding box and the maximum (x, y, z) of all zones becomes the bottom-right corner of the region bounding box. Coordinate values typically range from 0 to positive infinity and will likely be multiples of 8192 (0x2000). No culling is performed against a region, a simple index indicates which region is currently being viewed.
A "zone" can be either terrain, city, dungeon or sky city. Terrain zones consist of 8x8 equal-sized patches. Dungeon, city, and sky city zones are portal-based and consist of 1 or more arbitrary sized bounding boxes.
The coordinates of terrain zones range from 0 to 65535 (0x0000 to 0xFFFF) but are offset by a multiple of 8192 as defined in the zones.dat file. An entire terrain zone is 256x256 grid squares large, uses 1 256x256 heightmap, and is textured with 64 256x256 textures.
Terrain patches consist of 32x32 grid squares and are textured with a different 256x256 texture. Patch coordinates are 0 to 8192 (0x0000 to 0x2000)
Grid squares consist of two right triangles whose AB sides are 256 by 256 float units long. They consist of 4 vertices and are indexed primitives. Grid coordinates are 0 to 255 (0x00 to 0xFF).
Each distinct zone has a comma-seperated value (CSV) file describing a list (by filename) of unique static meshes that can be found in that zone, one per line. Additionally, each distinct zone has a larger CSV file that describes the "instance" positions of every static mesh, providing at a minimum the following on each line:

mesh index (from first CSV file), x, y, z, uniform scale, y-axis rotation

At region load time, the two CSV files for every zone that comprises this region are scanned and a list of unique static mesh filenames is generated along with a vector of world positioned instances for each unique mesh. This vector of instances can be cross-linked with the patch data so that Region r, zone z, patch p may immediately pull up a list of which unique meshes it uses and where they are instanced on patch p.
Static geometry is therefore associated with terrain patches. First the AABB's of zones and then patches are interesected with the view frustum to create a list of visible patches. If a patch is not visible, none of its static geometry is visible either. Thus there is no need to interesect static geometry against the frustum because if it's owning patch is not culled it will be rendered otherwise it will not.
A circle around the player is created that is roughly twice the distance from the camera's z-near to z-far. In a seperate thread, all terrain zones and patches that interesect this circle have first their geometry and then their textures loaded/created. All static geometry that is present on these patches is also loaded at this time if an instance of it was not already found to be loaded. The textures for the static geometry are also loaded.
Alternatively two circles can be created, one at a distance of twice the magnitude of the z-far plane and one a little closer in. The larger circle will force geometry loads with white textures and the smaller circle (though still further out than the z-plane) will force texture loads for previously loaded terrain/static mesh geometry.
Note that all background loaded geometry/textures go into LRU queues that release least recently used entities to satisfy some maximum vertex/texture overhead.

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