Not logged in, Join Here! or Log In Below:  
 
News Articles Search    
 

 Home / General Programming / Loading large maps .. and instancing Account Manager
 
Archive Notice: This thread is old and no longer active. It is here for reference purposes. This thread was created on an older version of the flipcode forums, before the site closed in 2005. Please keep that in mind as you view this thread, as many of the topics and opinions may be outdated.
 
Vast

May 28, 2005, 10:52 PM

Hello everyone.

I have a general question about loading 3d maps for games. It is obvious (even though i haven't thought about it) that a large... huge world map for a 3d game would not be loaded all at once.

Now, I desided to go with the instancing approach, and upon saving of the map, i "compile" all the object instances as one LARGE mesh (here is my first problem/question). Then, when the game loads, i load the mesh into memory (here is my second _problem_) and then apply octree subdivisions on it, in order to render parts of it (map).

So, first of all, should i really be compiling maps, into large meshes, even at places where for example, i have one prefab, its pasted 4 times, at 4 different places, i compile it as 4 separate, unaware-of-each-other meshes, creating one huge world. Or should i, what should i do? Should i actually store the prefab once, and then reference it by it's index, and a new location for rendering? How would i do that (detailed explanation if possible, please)?

Second part, is still a problem even if the first question is solved, what if there are thousands of prefabs, a frickin ocean of prefabs (big game, no?) then loading them all at once, is plain stupid in my opinion, so what can i do? This isnt just space partitioning issue, and i was hoping someone might share their views in regard to this dillema.

Thank you for all future replies.

Tim

 
Wernaeh

May 29, 2005, 05:27 AM

Hi Vast =)

I think the solution here is to seperate between resources, resource data, and entities.

Resources include bitmaps, prefab meshes, sounds, and the likes. Entities have pointers to resources, and may request resources by a resource name (i.e. a filename within your project directory for example). Note that since you don't know what entity still keeps pointers to any resource, you should never delete resources.

This is a problem though for many resources, since resources may take up lots of memory. However, as I mentioned before, you may seperate resources and their data. For example, a bitmap resource consists of a string name, and
a pointer to the bitmap pixels. Whenever the bitmap resource wasn't used for quite some time, free the data pointer, but keep the actual bitmap object. This should be done internally within the rendering system. Then - either if the bitmap resource is requested again, or if it is simply used for rendering - load up the bitmap data from file again. You might also add a "never unload" flag to indicate important resources, such as menu bitmaps. Finally, since you also kind-of seperated resources, rendering and logics, you may use (and also need to use) a seperate thread to handle resource reloading.

This method results in using just a little memory for each resource loaded - about 100KB for 1000 resources. Additional memory only is required for resources that currently are used.

Futhermore, the approach both allows for easy loading and usage of resources in code and in level data - just load once and then use. You need not worry about resource unloading / reloading anymore.

Meshes also are implemented as a similiar resource. Here, you may free all vertex and poly data whenever the mesh wasn't used for some time. This is also the solution to your "baking" question. Don't bake identical meshes, unless you somehow feel the need to waste memory. Rather, have just a small entity struct that owns a pointer to the static mesh resource within your rendering system. For rendering, the entity only specifies it wants to get this pointer rendered at its location.

With entities you may use the same scheme.

The first idea, though, would be to load up all entities at once, considering that your usual entity doesn't require too much memory, anyways (around 100 bytes are probably realistic here). This is about the way TES: Morrowind handles its huge world.

However, there are few cases where this is not feasible, for example if large data is associated with entities, such as collision meshes.

Yet, simply deleting all entities that are outside some range around the player gives you the same problems as deleting resources: What to do with pointers to these? You might hack around some bit, and perhaps use reference collecting pointers, but things will get ugly. Also consider gameplay critical entities. What if the freighter you should protect is cached out, alongside a lot of enemy pilots?

Consequently, you keep all entities alongside their name in memory, and handle larger entity data the same way as resource data: Only load on demand.

Another strategy to consider is to pack everything that is common about several entities into a static instance. This also is done in TES: Morrowind. There is just a single "Rock_17" class entity that describes how the rock looks, what collision mesh it has, and how it behaves in the game. Then, each instance of Rock_17 just points to the class entity, and only provides its own rotation and location.

Finally, yet another idea I had was to allow for comlete object unloading and reloading by not using pointers. Instead I wrote a replacement system where instead of accessing objects by a pointer, they were accessed by some symbolic name - containing both a file name, and an object identifier. Whenever an object was not found by its name, it was loaded from disk, using the specified file and id. While this system was really great in some aspects - you needn't worry about invalid pointers, or about storing and loading pointers within files - it also had a ugly drawback. Accessing objects via symbolic lookup takes ages.

I hope this helps a bit,

Cheers,
- Wernaeh

 
Vast

May 29, 2005, 11:19 AM

Hey Wernaeh!

Thanks for your reply, and
Yes, this does help. So what you suggest is for me to delete the actual data if it isnt used for certain time, but when u need it again, you just load it again from files? That sounds awfully inefficient to me =S

What about constructing an octree? Don't I need a complete mesh to do that? But if I load all of my entities based on the need for them, i really dont have a complete, final mesh, which in turn stops me from constructing an octree, to speed up my rendering =/

I also plan to use rendering techniques like bump mapping, and specular highlights, but that would be really slow if i just cull out whole objects instead of using an octree.

But i guess your way, is better then my way =) lol,

Thanks for your help.

Regards,
Tim

 
Wernaeh

May 29, 2005, 12:04 PM

Hi again ;)
Pleased to have helped.

>>
So what you suggest is for me to delete the actual data if it isnt used for certain time, but when u need it again, you just load it again from files? That sounds awfully inefficient to me =S
>
What about constructing an octree? Don't I need a complete mesh to do that? But if I load all of my entities based on the need for them, i really dont have a complete, final mesh, which in turn stops me from constructing an octree, to speed up my rendering =/

 
Vast

May 29, 2005, 01:03 PM

Hey Wernaeh!

I wrote a big post, but my internet went down, and i dont want to retype it, so to summarize ill just say thanks for the great advice =)

Regards,
Tim

 
Wernaeh

May 29, 2005, 02:17 PM

You're always welcome ;)

 
tokjunior

May 29, 2005, 02:52 PM

Hm. If you're smacking the smaller meshes together into a large one you're not really instancing anymore, are you?
Don't bother "compiling" the maps, just store each instance ID in the map, and use an AABB for each instance to generate a KD-tree. When rendering, cull nodes, and once you find one that's in view, just use the ID stored in the node to render it.

 
RAZORUNREAL

May 29, 2005, 07:09 PM

In case it's of interest, I'm working on a png loader that loads interlaced png's progressively, so that rather than freezing for a moment the textures will just be low detail. Might not be worth it though, you'd have to download the texture to the graphics card every frame. But yea, thats a possibility you could think about.

 
Vast

May 29, 2005, 07:13 PM

That sounds very interesting. Since you post it here, i believe your technique could be applied to other media?

That sounds very interesting. Is there a link that you could share with us?

Thanks,
Tim

 
RAZORUNREAL

May 29, 2005, 08:15 PM

Can't give you a link, I don't know of anyone else thats done it and I'm only half done myself (if that).

I think it's pretty limited actually, you can only load png's with ever increasing detail because they have an interlacing scheme. So you don't have to load any more data, it's just given in an order that lets you make a low detail picture before your done. Gifs have interlacing too, but it's not as good. You could possibly progressively load models I suppose, just it'd be hard to come up with face indices. Models are mostly pretty small anyway, so I wouldn't bother.

I only mentioned it because I find textures to be the most memory hungry thing.

 
Lennox

May 29, 2005, 09:40 PM

I used this method in GIS visualization from full earth down to street level with major cities. It works reasonably well if you can put up with the deferred loading scheme. To start of, there is the concept of a material and an image. I load all the materials into memory without loading the associated image. These materials are also stored in a queue (currently a list for quick insert/removal).

I render the scene as I typically would with all the images loaded. When a material associated with an image is called to render itself to the scene, the material udpates its usage information (sets its current use time), and moves itself to the front of the material queue.

Now that everything is working nicely, we should have our scene rendering, but only with colored materials (no textures). Whenever a material needs a texture, that material adds a request to our worker thread to load the image data so that it can create the material. Once the data is loaded, the material gets created in the main thread.

Every frame, you iterate once through your material list and clean out any texture id's for materials that haven't been used in the last 10 seconds or so (this can vary). Depending on your scene complexity, you can store thousands of relatively high resolution textures without having to really modify any of your code.

The end result is you can store all your textures in memory. I don't think this might be ideal for the FPS, but maybe its helpful in your case. The pitfall of course is that if you move too quickly to a new area, everything can come in as shaded rather than textured. This method can also be used for geometry and terrain.

Here are some considerations to keep in mind if you choose this method:
1. You have to keep your image sizes relatively small so it doesn't impact performance. I suggest capping your material size to 512x512 for the highest resolution (but really you should try to use 256x256 or less).
2. You should be keeping a cache of texture id's so that you can reuse them instead of creating brand new ones.
3. Only 1 request is made at any given time. You should only clean out 1 material per frame if cleaning has a high overhead.
4. Watch out for the clean step if you have millions of materials. Doing a linear search on this list can actually chew up alot of time, but that should be easy to work around.

 
This thread contains 11 messages.
 
 
Hosting by Solid Eight Studios, maker of PhotoTangler Collage Maker.