Skip to main content
GameDev.net gamedev.net
🔒 Locked

Materialsystem: Avoid loading of textures and shaders twice

Started by mokaschitta Nov 12, 2009 at 5:10 AM 9 replies 2.1k views
Original Post
mokaschitta
mokaschitta
Hi, I am currently working on a small modelformat and I am at the point of implementing a simple material system. Anyways, I could need some input on how to properly do this. Lets say each material only links to one texture for simplicity. How can I avoid that I load the texture twice if I have to different models using the same materials? I thought about having a materialManager class or something which loads all the materials of the requested models at once so you would basically have one class that knows about all the materials in the scene and avoids loading stuff twice for instance. Is there a common way to do this? (my first idea was to simply load the materials from the modelLoader class but that way its not global and does not know which materials are used in other models) And also, doesnt it make sense to draw all the faces of the same material in a scene at once? or do you usually only sort faces by material per model? thanks! [Edited by - mokaschitta on November 12, 2009 5:30:43 AM]
haegarr
haegarr
Loading textures (from disk) is usually done by a mechanism called resource management (i.e. that the same mechanism works for other resources like meshes, sound, scripts, ..., too).

It is implemented that the resource management holds a map for each type of resource. When the renderer requires a resource, it asks the management for the belonging kind of resource by providing a key. The management looks up whether the resource is already loaded from disk. If not, it loads it and stores it into the map. The resource is marked as used once more (to avoid its accidentally unload) and returned.


Each kind of switching the context costs time. Be it switching of textures, materials, shaders, and so on. Switching the one kind is more expensive than switching the other kind. External constraints (like transparency) may prescribe a partial order of rendering. So the best sorting depends on the set-up of your render pipeline.
Gorax
Gorax
What you could do is create a texture/shader loader class that uses a hash map to link filenames to textures/shaders. The material system would basically combine the use of textures and/or shaders, so it'd require the loaders anyway. It sounds a little complicated, but if you can already load the textures/shaders, the rest of it should be fairly simple to implement.

[EDIT]
What haegarr said.
mokaschitta
mokaschitta
okay, that sounds great. I work on a small deferred renderer, were most material properties will be stored in specular/albedo... textures which modify the phong term in the lighting shader. So basically for the beginning I will only have one global lighting shader, and some variations for transparency or special things.
Anyways I would still have different shaders for effects like bumpmapping and so on so I still would like to implement some kind of sorting per material (propably per mesh, because then I would only have to sort them once).

Sorting everything in the scene per material (unless its transparent) does not really make sense since I would have to sort it every frame wouldnt i? Did anybody try that?
thanks!

Stani R
Stani R
Quote:
Original post by mokaschitta
Sorting everything in the scene per material (unless its transparent) does not really make sense since I would have to sort it every frame wouldnt i? Did anybody try that?
thanks!

You don't want to sort transparent objects by material, you want to sort them back to front or they will not show what's behind them. The rest you can sort by material. If you are building a separate list for the objects to be drawn each frame, you can sort on insert. If you keep the list between frames and it is sorted to begin with you don't need to sort by material every frame, only when new objects are inserted. This depends on how you submit geometry to the renderer.

It's a tradeoff between CPU and GPU processing. If you don't sort, you will have more state changes to do so GPU will be busier. If you do sort, you are obviously taking up CPU time. The benefits of sorting should outweigh the costs, but I'm not saying that from experience.
mokaschitta
mokaschitta
Okay thanks guys, that helped me understand what I have to do next, and I found this nice tutorial:
Here

I will propably not sort anything by material for now and add that later when everything else works :)
mokaschitta
mokaschitta
Hey, I just thought about the sorting question a little more and came to the conclusion that I propably want to use opengls occlusion query for occlusion culling which would require sorting Objects front to back (the transparent ones not of course)
Can I still also sort all objects in the scene by material? or do I have to decide between one of the both (so maybe sort objects in the scene from front to back for occluion culling and only sort the faces in each model by material?)

thanks
dclyde
dclyde
They don't necessarily have to be exclusive (although that is the simplest route to go).

In some cases games will sort front to back and render their objects using an extremely cheap shader for occlusion culling without using the rendered result. They will then use that information to conduct all remaining rendering passes (except shadows which can occur from different perspectives).

During the subsequent rendering passes they sort by material/shader or what have you. There is a level of cost associated with all context switches, exactly what you sort on may depend on how your content is setup. Sorting by material in your case sounds like an effecient method, but in some pipelines materials are essentially unique per mesh.

I use "in some cases" because as with everything else it varies. For instance in your case you are doing a deffered lighting pipeline so your initial shader may already be "cheap" and you may not have additional rendering passes after the first one. Because of this the two pass approach may end up being more costly than in cases where multiple passes are already being taken.

As an alternative to the two pass approach there is a frame delayed approach to using occlusion culling. Implementations may vary, I saw one where the previous frames data was used, but not entirely trusted (the camera or objects may have moved) any new items were just assumed to be visible, any old items went through a simpler bounding box test. I am probably getting this wrong, I was only vaguely familiar with the implementation.

As a last note, your "sort the models front to back, then sort the materials within them" comment brought up a potential issue. In general it is best to have the items in your renderer be at the mesh->material level, not at the model->meshes[]->materials[] level. This allows individual meshes within a model to be transparent (and submitted for rendering seperately) it also prevents some issues with really large transparent models not cooperating properly with much smaller transparent models due to sorting at a much coarser level.
// Full Sail graduate with a passion for games// This post in no way indicates my being awake when writing it
mokaschitta
mokaschitta
Thank you very much, that helped me alot. I think I start to see in which direction I have to go now :)
megatron242
megatron242
There's an important issue you might consider. In case you want your framework to be usable also in multithreading scenraio. Rememeber that OpenGL requires that you can load resources only on the active thread. So you might want have a mechanism which allows deferring the loading, so it can be done in the correct thread.

Again, this is only relevant if you plan to use multithreading...
Atrix256
Atrix256
A quick blurb cause im surprised no one else has mentioned it...

Refcounted resources are pretty nice.

Here's what i do for resource loading / making sure no more than a single copy is loaded once.

I make a resource manager class which has a "load" function that takes a filename and returns a pointer to a loaded resource (or null if failure)

Inside of that load function, it checks the list of already loaded resources, and if there is a match, it increments a "usage counter" on that resource and then returns it.

I also make a "free" function where you pass it a resource and it decriments the refcounter. If the refcounter hits 0, that means it's safe to unload because nothing else is relying on it. If the refcounter is > 0, then do nothing after decrimenting because other things are using it.

this lets your other game objects call load and free for resources as they require / no longer require them which really simplifies code. The resource manager behind the scenes makes this efficient.

HTH!

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.