Sign in to follow this  
Daniel E

efficient mesh management?

Recommended Posts

Hi, So i have my Mesh Objects of (semi-pseudo code):
class MeshObject {

    LPD3DXMESH mesh;

}

MeshObject meshes[10];


and my function to load a mesh to it
void loadMesh() {

        LPD3DXMESH mesh;
	LoadMeshFromFile(&mesh, "test.x");

        for(int i=0; i<10; i++)
	     meshes[i]->mesh = mesh;


}


So i wonder if adding the same mesh to each object will increase the meshes in memory? Should i use LPD3DXMESH *mesh; in my object class instead? Also will directx load the same file each time? I mean my function is telling it to, but does it really do it?

Share this post


Link to post
Share on other sites
LPD3DXMESH is already a pointer LP is the give away. So you're already store it as a pointer. So assinging it to each mesh object as you did is only making a reference to the mesh. It is only loaded and stored 1 time. Since you called Load 1 time, and are only copying references, not the mesh data.

This means though, that if you call meshes[0]->mesh->doSomething(), that it will effect all the other meshes, since they are the same mesh.

Share this post


Link to post
Share on other sites
that looks very good and useful

i have thought about keeping my meshes in a vector before

but what do i have to include to make it work?

my compiler stops at the first line.

i have already included <vector>

Share this post


Link to post
Share on other sites
I'm sorry, i thought my original post was off track so i removed the code, here it is again, you'll need

#include <vector>
#include <map>
#include <string>
#include <boost/shared_ptr.hpp>


I wrote this very quickly, so it's untested, may not compile, and may be entirely useless/flawed.


std::map<std::string, boost::shared_ptr<Mesh> > meshes;
std::vector<boost::shared_ptr<Mesh> > meshInstances;

boost::shared_ptr<Mesh> LoadMesh(const std::string &path)
{
std::map<std::string, boost::shared_ptr<Mesh> >::iterator it;

it = meshes.find(path);

if (it == meshes.end()
{
//mesh not loaded yet
it = meshes.insert(std::pair<std::string, boost::shared_ptr<Mesh> >(path, boost::shared_ptr<Mesh>(new Mesh())));

D3dXLoadMesh(it->second.get());
}

return it->second;
}

void PopualteMeshInstances()
{
for (int i = 0; i < 10; ++i)
{
meshInstances.push_back(LoadMesh("yo.mesh"));
}
}


You'll probably want your mesh instance to look more like this:

struct MeshInstance
{
Matrix ModelTransform;
boost::shared_ptr<MeshObject> Mesh;
};

std::vector<MeshInstance> meshInstances;

That way you can store a model transform with each instance.

Share this post


Link to post
Share on other sites
Quote:
Original post by bzroom
LPD3DXMESH is already a pointer LP is the give away. So you're already store it as a pointer. So assinging it to each mesh object as you did is only making a reference to the mesh. It is only loaded and stored 1 time. Since you called Load 1 time, and are only copying references, not the mesh data.

This means though, that if you call meshes[0]->mesh->doSomething(), that it will effect all the other meshes, since they are the same mesh.



I'm sorry, my example wasn't considering that i'm actually calling the function multiple times and pass a file name to it.

In that case, will my MeshObject array actually hold pointers to one mesh and not 10 meshes (if the file name doesnt change)?


it would actually look like this



int i=0;

for(i=0; i<10; i++)
loadMesh("test.x");

i=0;

void loadMesh(char* filename) {

LPD3DXMESH mesh;
LoadMeshFromFile(&mesh, filename);
meshes[i++]->mesh = mesh;


}



Share this post


Link to post
Share on other sites
Each time you call: LoadMeshFromFile, it will load the mesh, regardless of wether it has been already loaded or not.

Yes that will load 10 duplicate copies of the mesh, and you should use a system as described in my previous post to only load each mesh once.

Share this post


Link to post
Share on other sites
Ok this works absolutely gorgeous, except that i had to remove all the "boost" usage.

(i'm working on a school project and can't use non standard libraries).

Will the performance at run time decrease without using boost when i get the meshes from the list for rendering?

Share this post


Link to post
Share on other sites
No, boost is just a way to intelligently handle the life of the objects pointed to by pointers. while it will work, copying the pointers around as you are, it is VERY unsafe.

Imagine you added a destructor to the MeshObject which told directx to free the mesh that it was pointing to. If all 10 MeshObjects are pointing to the same mesh, and one of them gets destroyed, telling d3d to free the mesh, then they all lose their mesh.

Worse still, they all still think the mesh is still there, since they have a pointer to it. But truthfully it's been deleted out from under them. This is called a dangling reference. and you're very very close to a whole party of them :)

You can implement your own reference counted object that the MeshObjects can share, so that when the destructor is called, it only frees the mesh after there are no more references to it. But why go through all that trouble when boost::shared_ptr is there for you?

There may be some std variant, or you may be able to convince your teacher to let you use shared_ptr, since it's pretty much standard at this point.

Share this post


Link to post
Share on other sites
Ok thanks for shedding light on "boost".

This library doesn't come with windows or? i tried to include it but the compiler says he can't find it.


So here's my implementation so far:

I was a little lazy and use one list to save each mesh one time and just give my mesh objects pointers to the meshes in the list.



LPD3DXMESH* mesh;

void ObjectManager::addObject(char *file, MeshObject* object)

std::map<std::string, LPD3DXMESH>::iterator it;

it = MeshList.find(file);

if (it == MeshList.end())
{
mesh = new LPD3DXMESH;
LoadMeshFromFile(mesh, file);
MeshList.insert(std::pair<std::string, LPD3DXMESH>(file, (*mesh)));
object->mesh = treemesh;
}
else
{
object->mesh = &(it->second);
}

scene->AttachChild(object);

}





In the rendering i go through my object graph and the objects seem to store only one adress for each mesh (right now i'm using two meshes and only two addresses are shown in my render loop).

Is this implementation suitable or does it miss some benefits of your code? The performance increased by about 100 fps with this new implementation btw. The objects render correctly too.

Share this post


Link to post
Share on other sites
This code is technically correct, but it still suffers from the issue that i menitioned before regarding ownership. Who owns each mesh that is loaded? How/When do they get cleaned up?

Just to clarify i was only speaking of boost::shared_ptr, not boost itself. Boost is a suplimental code library written by very competant people. Lots of the things contained in the library have been considered for adding to the standard library.

It's not a part of windows or restricted to windows even. It's a seperate library that you can build for lots of platforms. It should be pretty easy to find a ton of info about it through google.

Actually your code is a bit off, you're storing pointers to pointers for no reason.




void ObjectManager::addObject(char *file, MeshObject* object)
{
std::map<std::string, LPD3DXMESH>::iterator it;

it = MeshList.find(file);

if (it == MeshList.end())
{
LPD3DXMESH newMesh;
LoadMeshFromFile(&newMesh, file);
MeshList.insert(std::pair<std::string, LPD3DXMESH>(file, newMesh));
object->mesh = newMesh;
}
else
{
object->mesh = it->second;
}

scene->AttachChild(object);
}





.. is likely more appropriate.

Remember, LPD3DXMesh is already a pointer.

Share this post


Link to post
Share on other sites
ah yes, thanks, this works better.

i gotta tattoo that on my forehead - "LPD3DXMesh is already a pointer"


now i just need to modify my scene structure so i can actually delete my little objects again :)

Share this post


Link to post
Share on other sites
I'm willing to bet your project has memory leaks galore, judging by the last sniplet. When you delete things you're going to want it to cascade down into the object structure.

If you write unsafe code (unclear ownership), that pretty much means "shiz gonna be f'd." Which is where the shared_ptr comes in and all his brother objects.

When you run your program, and have some kind of cycle going on, where objects are being deleted and added. Assuming that nothing has crashed yet, open the task manager and look at the memory consumption of your process. It should eventually peak out. If it continues to rise and rise and rise and rise.. There are issues. It may only rise when you reload a level.. but if you reload the level 100 times it might have risen a lot. This is an issue, an extreme one if you're machine has limited memory to begin with.

I'm saying good luck, i'm just also assuming that you're going to have issue..

My suggestion is that you study the boost shared_ptr and wikipedia pages on the subject and implement your own smart ptr. Test it properly, and then use it thoroughly.

Looks like you could at least use auto_ptr, but it doesnt give you shareing ability, it'd be like using boost::scoped_ptr. But boost::shared_ptr and boost::weak_ptr is where it's at i'm tellin ya :)

Share this post


Link to post
Share on other sites
yes, you're right, suddenly memory usage goes up and up...

i have no idea where this is coming from now haha

yes i'm a newbie at c++ and direct x and i'll probably ditch my concepts a dozen of times in the future.

edit: found the problem, some array wasnt deleted.

Oh yea, that boost::shared_ptr sounds promising. i'll look deeper into it and try to boost up my code :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Daniel E
yes, you're right, suddenly memory usage goes up and up...

i have no idea where this is coming from now haha

yes i'm a newbie at c++ and direct x and i'll probably ditch my concepts a dozen of times in the future.

edit: found the problem, some array wasnt deleted.

Oh yea, that boost::shared_ptr sounds promising. i'll look deeper into it and try to boost up my code :)


Boost can seem a little intimidating at first (it's pretty enormous as a whole), but trust me, once you get your hands on shared_ptr, you'll wonder how you ever lived without it.

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