Optimizing memory usage by duplicated or unused Object3D

Started by iagofg, December 12, 2011, 02:04:31 AM

Previous topic - Next topic

iagofg

Hello,

I'm wish to know which is the best way to dispose the unused Object3D that is no more necesary on the scene.

Also, I wish to know how should I proceed to minimize the memory usage when I have several instances of one Object3D in the scene, with different animation positions, translations and rotations.

Thank you!!

K24A3

To remove an Object3D I believe you need to remove it from the world then null all references to the Object3D so the garbage collector frees it.

world.removeObject(myObject);
myObject = null;

Cloning objects wont work with objects that have different animations (every object will have the same animation timings because they use the same mesh), but you can remove triangle information from the animations by calling Animation.strip().

EgonOlsen

It's correct that animated objects can't share meshes, but they can share the same animation instance though.

iagofg

So making:

world.removeObject(myRef);
myRef = null; // for all the references

Sure is enought to dispose everything, including all the underlaying compiled data? I suspected that there is something else to do to free all the resources. I've asked the question the first time because my app didn't not low the memory usage doing so... sure it can be the complexity of my app that hides some lost non-nulled references, but I looked for them everywhere and I didn't found more. Maybe I make some benchmarks with IRenderHook to confirm or discard :)

On the other topic (sharing data between duplicated objects)... relating cloning meshes sure that this: Object3D myRef2 = new Object3D(myRef, true); do not work to share the same mesh?

For animated object I suppose that is necesary 1 mesh per object so you can get different animated statuses per each Object3D? is it? do you refer this when you say animated objects can't share meshes? so if animated objects share meshes all of them will get the same animation status when rendering? maybe know this is usessful if i want more than 1 object animated identically at the same time?

Finally: I'm reading the doc searching for other posibility... maybe sound a little mad, but can I add more than one time the same Object3D to the world?? I'm thinking in optimizing with IRenderHook; it can solve my problem in some scene :)

EgonOlsen

#4
QuoteSure is enought to dispose everything, including all the underlaying compiled data? I suspected that there is something else to do to free all the resources. I've asked the question the first time because my app didn't not low the memory usage doing so... sure it can be the complexity of my app that hides some lost non-nulled references, but I looked for them everywhere and I didn't found more.
It should be sufficient. GPU will be freed once the compiled data gets garbage collected. If you are using VBOs, you'll get a log message in that case. This won't happen of course, if you are still keeping some reference to that Object3D somewhere.

Quote
On the other topic (sharing data between duplicated objects)... relating cloning meshes sure that this: Object3D myRef2 = new Object3D(myRef, true); do not work to share the same mesh?
Yes, that will make the new object use the same mesh...but i don't understand the actual question...?

Quote
For animated object I suppose that is necesary 1 mesh per object so you can get different animated statuses per each Object3D? is it? do you refer this when you say animated objects can't share meshes? so if animated objects share meshes all of them will get the same animation status when rendering? maybe know this is usessful if i want more than 1 object animated identically at the same time?
If they share the mesh, they share the animation...so calling animate() on one of them is sufficient. However, you have to make sure that this object will actually be rendered or otherwise, the mesh update doesn't happen on the other objects until you call touch() on one of them. 


Quote
Finally: I'm reading the doc searching for other posibility... maybe sound a little mad, but can I add more than one time the same Object3D to the world?? I'm thinking in optimizing with IRenderHook; it can solve my problem in some scene
No. One Object3D can't belong to a world multiple times nor can it belong to multiple worlds.

iagofg

Quote

QuoteOn the other topic (sharing data between duplicated objects)... relating cloning meshes sure that this: Object3D myRef2 = new Object3D(myRef, true); do not work to share the same mesh?

Yes, that won't make the new object use the same mesh...but i don't understand the actual question...?

Sorry, the actual question was:

Using myRef2 = new Object3D(myRef1, true) Does myRef2 share the mesh data so all the data is not duplicated in memory?
Does it share compiled data as well?
If not, How to make it happen? (How to get duplicated Object3D using the same mesh data without storing two times in memory?)

EgonOlsen

Sorry, my answer was wrong..."won't" should actually read "will". So yes, this will make the new Object3D use the same Mesh, but only in main memory. On the GPU, they will still be different. To change this, add a newObj.shareCompiledData(oldObj);. More info: http://www.jpct.net/wiki/index.php/Reducing_memory_usage


K24A3

Is there a faster or more memory efficient way of loading the same 3D file into multiple Object3D's with each Object3D having an independent animation?

At the moment I'm using Load3DS for every object 3D. How can I load the 3D file just once and then copy the mesh to the other Object3D's?
Does mesh.cloneMesh() actually copy the mesh or does it use the same mesh?

Here's the current code:

for(int n=0;n<MAX_CLONES;n++)
{
obj = Object3D.mergeAll(Loader.load3DS(myContext.getResources().openRawResource(R.raw.obj3s), 2f));
obj2 = Object3D.mergeAll(Loader.load3DS(myContext.getResources().openRawResource(R.raw.obj3l), 2f));
obj3 = Object3D.mergeAll(Loader.load3DS(myContext.getResources().openRawResource(R.raw.obj3r), 2f));
obj.setTexture("obj3tex");
obj.setSpecularLighting(true);
obj.calcCenter();
obj2.calcCenter();
obj3.calcCenter();
obj.calcNormals();
obj2.calcNormals();
obj3.calcNormals();
obj.calcBoundingBox();
obj2.calcBoundingBox();
obj3.calcBoundingBox();
obj2.strip();
obj3.strip();

Animation anim = new Animation(3);
               anim.createSubSequence("anim1");
               anim.addKeyFrame(obj2.getMesh());
               anim.addKeyFrame(obj.getMesh());
               anim.addKeyFrame(obj3.getMesh());
               anim.setClampingMode(Animation.USE_CLAMPING);
               obj.setAnimationSequence(anim);
               //obj.compile();
world.addObject(obj);

               // Save object reference
               myObjects3[n] = obj;

anim = null;
obj  = null;
obj2 = null;
obj3 = null;

}

EgonOlsen

They are using the same mesh by default. If you don't want this, do


Object3D niu=old.cloneObject();
niu.setMesh(niu.getMesh().cloneMesh(true));


or, which i prefer:


Object3D niu=new Object3D(old, false);

K24A3

That made quite a difference, I managed to decrease the load time from 6 seconds to 4.
Cheers.


K24A3

Wow serialized objects make a big difference in load time, loading just three serialized 100KB objects shaved off another 500ms. The RAM usage appears to have dropped a bit as well (yet to confirm).

I can't seem to get Eclipse to auto serialize the folder unless I go into the Project Properties and click Apply again. Clicking Refresh and changing the folder contents does nothing.

The mesh bounding box is also different (offset is wrong) now that I need to call Scale() and translateMesh().
EDIT: I found a solution, removing translateMesh() and scaling the bounding box values manually gives me the correct values.

iagofg

Yeah... xDDD I used serialialized loading since weeks :) is faster... and uses less memory because no importation process must be executed.

But above those advantages I believe the serialized format has one severe problem: it is very very big: by example for one of the animations I work:


  • source data: 60 .objs, animated: around 1'5 mb (.obj maybe are one of the bigger formats, very very redundant).
  • import with a java application and exported to serialized form. I discard redundant geometry with strip, and I apply some other optimizations (I do not remember now, but I readed everything weeks ago).
  • the result is that the serialized data: animated 60 frame object: around 4 mb.

I suspect that the matter is that serialized data include not only the geometry data, also include all the other properties so the objects do not need to be initialized again. Very very fast, but very very big. Probably there exists a better solution which picks advantages from both alternatives, ;) but for the moment I guess the serialized form is the best available, as long as you can zip the data inside jars or apks, so the size lowers.

Anyway :) maybe something is possible in this way

K24A3

Yeah I noticed the file size difference. 100KB vs 357KB, but if it only increases the APK, it's not a problem for me since my objects are mostly low poly anyway. The APK format is actually a ZIP file so it shouldn't make much difference, zipping that 357KB serialized file shrunk it to 130KB (compared to 78KB using the 7zip format :p).