Searching: tool suggestions for polygon reduction and OutOfMemory tracking

Started by kbjansen, June 19, 2012, 03:40:41 PM

Previous topic - Next topic

kbjansen

Hooohaaa!

the most nerving problem while programming for mobile devices is the OutOfMemory Exception.
In most cases the OOM is caused by long living objects. The further the development progresses the more objects you
need and the more often you are running into a OOM.

1.
Does anyone have experience with a kind of Memory Leaks tracking tool?
I want to find out which objects are blocking the Memory.
I would try this: http://macgyverdev.blogspot.de/2011/11/android-track-down-memory-leaks.html


The latest OOM - that drives me insane - is thrown after restarting the gameActivity wherein , among others, a simple keyframe animation
is created. Uncommenting that code lets the OOM disappear, so i think i have something forgotten to clean up.
This is how I do:


private Animation drive = null;
private Object3D temp = null, playerCar = null;
[...]
/* jPct specific ViewPort setup. It's called in MyRenderer.onSurfaceChanged(...)*/
private void setupViewPort(){
[...]
//loading 3D cars
case 1:{
//playerCar = beetle
if(playerCar == null){
playerCar = loadZippedSerializedModel(getResources().openRawResource(R.raw.beetleidle));
playerCar.rotateY((float)Math.PI/2);
playerCar.rotateMesh();
playerCar.clearRotation();
playerCar.getMesh().compress();
//*
drive = new Animation(3);
drive.createSubSequence("IDLE");
drive.addKeyFrame(playerCar.getMesh());

drive.createSubSequence("LEFT");
temp = loadZippedSerializedModel(getResources().openRawResource(R.raw.beetleleft));
temp.rotateY((float)Math.PI/2);
temp.rotateMesh();
temp.clearRotation();
temp.calcBoundingBox();
temp.calcNormals();
temp.getMesh().compress();
drive.addKeyFrame(temp.getMesh());
if(temp!=null)temp.clearObject(); temp = null;

drive.createSubSequence("RIGHT");
temp = loadZippedSerializedModel(getResources().openRawResource(R.raw.beetleright));
temp.rotateY((float)Math.PI/2);
temp.rotateMesh();
temp.clearRotation();
temp.calcBoundingBox();
temp.calcNormals();
temp.getMesh().compress();
drive.addKeyFrame(temp.getMesh());
if(temp!=null)temp.clearObject(); temp = null;

playerCar.setAnimationSequence(drive);

playerCar.strip();
playerCar.build();
// playerCar is added to world later, after connecting with jBullet Rigidbody
// /*drive.remove(0); drive = null;*/
                                                }

}
                           
/** Loads a single, zipped and serialized Object from InputStream. It' s called in setupViewPort()*/
private Object3D loadZippedSerializedModel(InputStream inputRessource) {
ZipInputStream zis = new ZipInputStream(inputRessource);
try {zis.getNextEntry();} catch (IOException e) {/*throw new RuntimeException(e);*/}

Config.oldStyle3DSLoader=true;
Config.useRotationPivotFrom3DS = true;

Object3D model = null;
model = Loader.loadSerializedObject(zis);

//clear resources
try {
zis.close();
zis = null;
} catch (IOException e) {/*e.printStackTrace();*/}
Loader.clearCache();
MemoryHelper.compact();
System.gc();
return model;
}


/* Resets all Objects to null in reverse order of creation. It's called in Activity.onDestroy()*/
private void destroyAllObjects(){
[...]
Loader.clearCache();
playerCar.clearAnimation(); playerCar.clearObject(); playerCar = null;
if(drive != null)drive.remove(0); drive = null;
if(temp != null)temp.clearObject(); temp = null;
[...]
System.gc();
MemoryHelper.compact();
}




What I managed beside the cleaning of all objects on Destroying the Activity:

  • minimizing the keyframe animation to 3 frames (so beside the object3D there are two more Meshes loaded)
  • every keyframe is part of a single animation sequence (so one frame per sequence)

To reduce the memory usage I want to compute the 3ds-objects down - I hope this helps.

2.
Does anyone know a good polygon reduction tool?
I already tried POLYGON CRUNCHER (http://www.mootools.com/plugins/us/polygoncruncher/) but after optimizing (from 9073 vertices  to 6112 and from 14652 faces to 8738)
the jpctSerializing process get stuck so the serialized 3ds file is not created.
I guess there was something destroyed while polygon reducing that was important for jpctSerializer.
Anyone knows a better tool?

(EDIT: fixed this by doing another import of the reduced 3ds-file to 3ds-Max and export it as 3ds-file again)


ByTheWay!?: What's recommended: quadrangular or triangular Polygons?
I've read somewhere that all quads are recompute into triangles for the android's hardware, so putting objects as quadrangular Polygon Mesh would reduce performance (can't find where I read this anymore) - so is that true?

EgonOlsen

Are you removing references to instances of World and FrameBuffer too? If so, remember to call dispose() on both before they go out of scope. Maybe that helps. Is there a particular reason why you remove the objects anyway? You could keep the references (for example in a static variable in the Activity) and recycle them once the Activity starts again. I'm doing this in my RPG experiments and it works pretty well (at least on Android 4.0.x).

To answer the question about quads vs. triangles: Triangles all the way! jPCT will convert quads into triangles anyway, but you have better control if you use triangles in the first place.

kbjansen

Yes I'm disposing the World and the FrameBuffer in the destroy-Method like you mentioned.
Your idea of making objects static instead of killing them is interesting - i give it a try and will report the results.

And do you mean with recycle to reset the objects preferences (for example set an object3d back to startposition...) or doing the destroying and nulling that i do in destroyallobjects, or what else do you mean?

Thanks for your answer related to 'quads vs triangles'!


Another thing related to polygon reduction:

I'd reduced some 3ds models inclusive its separate keyframe meshes (keyframe meshes = same vehicle object but front wheels rotated).
When I separately load and 'draw' them with the jpct-AE Engine all objects are displayed correctly.

But when I load the 3ds keyframe meshes as keyframe into a Animation (do it like seen above) and animate these frames at runtime
then i will get a strange output:
- looks like the texture of the corresponding keyframe animation was putting over the mesh of the default original object itself
- so the keyframe texture is loaded but the keyframe mesh is not
- looks kind of cracked

without polygon reduction the keyframe meshes are displayed correctly
what could be lost while reducing polygons?
or is there any preference i should call on 'Animation'.

I 'm going to post some pictures, so you can see what i'm talking about
... too spiritless to do it right now o_o
cya

EgonOlsen

With "recycle" i actually meant to copy the references into the new (or restarted) Activity. My Android examples do this in a crude and simple way and my RPG game does it too. The result is, that the game simply continues where i left once all references are being copied into the new Activity.

About reducing the polygon count of keyframes...it's very unlikely that this will work, because the polygon reduction is based on the mesh's geometry...and that changes between keyframes, so the reduction tool will combine different polygons for each frame and as a result, interpolating between them will result in a mess. The only thing that might work is to create new keyframes out of an already reduced master mesh.

kbjansen

Quote from: EgonOlsen on June 20, 2012, 08:04:34 PM
With "recycle" i actually meant to copy the references into the new (or restarted) Activity. My Android examples do this in a crude and simple way and my RPG game does it too. The result is, that the game simply continues where i left once all references are being copied into the new Activity.
... how do you copy the objects? Via Intent? I've already thought about handing over all jpct objects at the beginning of the developement.
At that time I failed to transport the mGLView because I didn't know how to transport custom or uncommon objects via Intent. So I leave this branch to save time.
Your result of copying the references seems to be equal with my "onResume"- result after minimizing and reopen the app.
When restarting the game and the activity, I want to reset all jpct objects position, score, time and so on. So no need to destroy them, thats right.
But I have to reset and unconnect the jBullet-Simulation. So it might work if I copy the refs like you said and 'just' destroy the jBullet things. Thats an idea...

reducing polys:
Ok I understand the problem, thanks! Your idea with the reduced master mesh seems to be plausible and make sense.
So back to original mesh :S ... I hope the polygon cruncher plugin for 3ds doesn't clump all submeshes of the object while reducing.
If so, there is no way to rotate the wheels after reduction... i test this and will report


kbjansen

Report:

Referring to Problem 1: Messed up keyframe animation after polygon reduction:

Try:
a) Take default object without keyframes and do polygon reduction
b) duplicate this "master" mesh 'n' times (n = amount of keyframes) and rotate/ translate subcomponents of the mesh to get the desired keyframes (e.g. rotating the front wheels to the left and right)
c) create one mesh out of all subcomponents, doing that once per mesh duplicate
d) Export each frame as separate 3ds-file, Serializing, zipping and load to the jpct-AE World

result:
- the object shapes of the mesh and it's different keyframes are loaded correctly, but the subcomponents that alter between the keyframes are textured in a wrong cracky way while animating (so the chassis and back wheels are textured correctly, but the front wheels doesn't )
- although the textures are connected to the shape of each single subobject correctly, because if i load each one in a separate Object3D then everything seems to be fine
-> animation.setInterpolationMethod(Animation.KEYFRAMESONLY) doesn't helped

Is there a way to switch off interpolation between master object and its keyframes (or its duplicates)?

Reffering to Problem 2: Out of Memory when restarting/ close Activity after Animation allocation

Try:
a) make nearly every class member static and disable some object-destruction and 'nulling'
effect: OOM disappears for a while, but objects are not reseted correctly (some objects are still there others are gone -> very strange)
b) make some more changes referring to code structure and several statements
result: OOM is back :-\

----> now I gonna try to track the source of error with the help of the Eclipse Memory Analyzer Tool,
so stay tuned!

ps: every hint of 'how to get rid of OOM errors' would be nice and  helpful!

EDIT:
quickly found a possible reason for the appearing of the OOM error - the texture that contains all GUI elements might be too big
I think I open a new thread, because this could be basic topic with a short answer (linked here)