3DS Animated Model Error

Started by ToddMcF2002, April 10, 2007, 03:18:47 PM

Previous topic - Next topic

ToddMcF2002

Can't seem to get this working.  Every time I add a mesh for an animation frame I get an error such as:

Object 'object_1_jPCT20' created using 570 polygons and 558 vertices.
[ Tue Apr 10 08:38:30 EDT 2007 ] - ERROR: Bounding box missing in this mesh!

The model does appear in the world.  He's lying on his back but I know how to fix that.  When I call

_monster.setAnimationSequence(anim);

I get:

[ Tue Apr 10 08:38:30 EDT 2007 ] - ERROR: This Animation is empty!


Which is expected given the other errors on each Mesh.

BTW I didn't create the model - its from the book "Killer Java Game Programming" and it was created with Poser
I can't seem to find a basic animated 3DS file anywhere for testing.  Could someone upload one??? 

Here is the underlying code.


private void testLoad3DS2(){
try{
Loader.setVertexOptimization(false);

Object3D[] animArray=Loader.load3DS("models/3ds/skel_stand.3ds", 100f);
_monster=animArray[0];
_monster.build();

_monster.rotateX((float)-Math.PI/2);
              _monster.rotateMesh();
              _monster.setRotationMatrix(new Matrix());
     
              _monster.createTriangleStrips(2);
              _monster.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
              _monster.setCollisionOptimization(Object3D.COLLISION_DETECTION_OPTIMIZED);

_monster.setTexture("select");
_monster.setVisibility(true);

_monster.translate(new SimpleVector(0, -50, 0));

theWorld.addObject(_monster);



Animation anim=new Animation(5);
Object3D [] o = null;

anim.createSubSequence("stand");
o = Loader.load3DS("models/3ds/skel_stand.3ds", 100f);
anim.addKeyFrame(o[0].getMesh().cloneMesh(false));

anim.createSubSequence("walk");
o = Loader.load3DS("models/3ds/skel_walk1.3ds", 100f);
anim.addKeyFrame(o[0].getMesh().cloneMesh(false));
o = Loader.load3DS("models/3ds/skel_walk2.3ds", 100f);
anim.addKeyFrame(o[0].getMesh().cloneMesh(false));

anim.createSubSequence("punch");
o = Loader.load3DS("models/3ds/skel_punch1.3ds", 100f);
anim.addKeyFrame(o[0].getMesh().cloneMesh(false));
o = Loader.load3DS("models/3ds/skel_punch2.3ds", 100f);
anim.addKeyFrame(o[0].getMesh().cloneMesh(false));

System.out.println("MoveTest::testLoad3DS2() setting sequence...");
_monster.setAnimationSequence(anim);

}catch(Exception e){
System.err.println("MoveTest::testLoad3DS2() " + e.getMessage());
e.printStackTrace();
}
   }




    private void checkAnimate3DS(){
    // CALLED IN GAME LOOP...

try{
long ltime = System.currentTimeMillis();
    if((ltime - _last3DSms) > 60){
_last3DSms = ltime;

if(_anim3DS > 1)
_anim3DS=0;
else
_anim3DS+=0.05f;
_monster.animate(_anim3DS, 2); // walk sequence...
}

}catch(Exception e){
System.err.println("MoveTest::checkAnimate3DS() " + e.getMessage());
e.printStackTrace();
}
   }



EgonOlsen

Just do a call to build(); on each of the objects from which you are using the mesh as keyframe.

ToddMcF2002

That got rid of the errors, but now I think I'm still doing something wrong.

[ Tue Apr 10 13:38:21 EDT 2007 ] - ERROR: The sizes of the Animation's Meshes (611) and the object's Mesh (553) don't match!

EgonOlsen

They have to have the same number of vertices to be animated. So they either don't or the loader merges them. To prevent the latter, do a Loader.setVertexOptimization(false); before loading them. If the error persists, the mesh sizes don't match and have to be corrected in the modeller.

ToddMcF2002

Yup that was at the top of the routine.  Oh well.  Thanks for the help though.

I don't suppose anyone has any simple animated test 3DS files???

I really don't want to buy one just to test the loader.
   

ToddMcF2002

Alright so I found a free 3DS and got it working.  Here is the download for anyone else interested.

http://www.turbosquid.com/FullPreview/Index.cfm/ID/312341

A few things.  There are 650 frames of animation.  That translates to about 19MG as a 3DS export.  Say goodbye to your heap!

I started messing around with selecting the short walk sequence (frames 0-30) in 3DS max and exporting that.  900KB.
I then used the handy "Select Objects" button to thin out the selection to every other frame and then finally every 3rd frame.
Selecting every 3rd frame gave me my target 300KB and the animation was surprising smooth - equivalent to my MD2 animations I downloaded somewhere.

So in case this will help anybody:

I could not find any definitive forum posts validating this for certain - you can use a single 3DS file for your animations just like an MD2.  Works exactly the same.  You could surely export it frame by frame but you don't need to.  Is there some advantage or something?  I like the single file thing because it is consistent with the MD2 approach. 

To export the single 3DS file: 
1.  Tools->Snapshot...
     select 0 - 30 and 30 copies (for the model above that is). 
2.  Edit->Select By->Name
     Select the items you want in the export file - for me it was "monster01", "monster04"..."monster28".  Every 3rd
     frame resulting in a 10 frame animation sequence.  Hit the Select Button before leaving!
3.  File->Export Selected

Here is the working code:


   private void testLoad3DS(){
try{
Loader.setVertexOptimization(false);

TextureManager tm = TextureManager.getInstance();
Texture t = new Texture("models/3ds/monster.jpg");
tm.addTexture("monster2", t);

Object3D[] animArray=Loader.load3DS("models/3ds/animate/monster_c.3DS", 1f);
monster2=animArray[0];
monster2.build();

monster2.setTexture("monster2");

monster2.rotateX((float)-Math.PI/2);
              monster2.setRotationMatrix(new Matrix());

monster2.translate(new SimpleVector(0, -30, 0));
     
              monster2.createTriangleStrips(2);
              monster2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
              monster2.setCollisionOptimization(Object3D.COLLISION_DETECTION_OPTIMIZED);

theWorld.addObject(monster2);

System.out.println("MoveTest::testLoad3DS() array size is: " + animArray.length);


Animation anim=new Animation(animArray.length);
int iseq = anim.createSubSequence("walk");
for (int i=0; i<animArray.length; i++) {
animArray[i].build();
Object3D o = animArray[i];
o.rotateX((float)-Math.PI/2);
anim.addKeyFrame(o.getMesh().cloneMesh(false));
}
System.out.println("MoveTest::testLoad3DS() setting animation sequence...");
monster2.setAnimationSequence(anim);
System.out.println("MoveTest::testLoad3DS() sequence id is: " + iseq);


}catch(Exception e){
System.err.println("MoveTest::testLoad3DS() " + e.getMessage());
e.printStackTrace();
}
   }



And then the game loop calls this (I know I need to use a better timer - its just a test!)


private void checkAnimate3DS(){
   

try{
long ltime = System.currentTimeMillis();
    if((ltime - _last3DSms) > 60){
_last3DSms = ltime;

if(_anim3DS > 1)
_anim3DS=0;
else
_anim3DS+=0.05f;
monster2.animate(_anim3DS, 1);
}

}catch(Exception e){
System.err.println("MoveTest::checkAnimate3DS() " + e.getMessage());
e.printStackTrace();
}
   }



EgonOlsen

Regarding the memory usage for larger animations, you may consider to add a call to strip() on the Mesh to remove triangle information from it. This is ok for meshes that are used as keyframes only.

ToddMcF2002

OK.

One thing I'm confused about though - If I strip() I have to do cloneMesh() or I get a null pointer.

If I'm cloning, isnt that using memory that offsets the benefit of strip()?

I also noticed that without cloneMesh() there is an extra frame (or a pause) at the end of the frame sequence.


EgonOlsen

You are getting a null pointer...when and were exactly? If this happens while trying to animate an object using stripped meshes, i consider it to be a bug. Keep in mind that you have to call strip() right before adding the mesh to the animation, not before doing a build() or something.

ToddMcF2002

I'm afraid you are losing me.  How can I strip() a cloned mesh before a build?  It won't have a bounding box and I'll be back were I was initially.

Here is the working code - maybe I'm just missing something. 


private void testLoad3DS(){
try{
Loader.setVertexOptimization(false);

TextureManager tm = TextureManager.getInstance();
Texture t = new Texture("models/3ds/monster.jpg");
tm.addTexture("monster2", t);

Object3D[] animArray=Loader.load3DS("models/3ds/animate/monster_c.3DS", 1f);
monster2=animArray[0];
monster2.build();

monster2.setTexture("monster2");

monster2.rotateX((float)-Math.PI/2);
              monster2.setRotationMatrix(new Matrix());

monster2.translate(new SimpleVector(0, -30, 0));
     
              monster2.createTriangleStrips(2);
              monster2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
              monster2.setCollisionOptimization(Object3D.COLLISION_DETECTION_OPTIMIZED);

theWorld.addObject(monster2);


//0-30  walk
//0-120 walk
//150-190 run
//150-210 run
//250-333 attack-01
//320-400 attack-02
//390-418 death-01
//478-500 growl
//500-550 death-02
//565-650 death-03

System.out.println("MoveTest::testLoad3DS() array size is: " + animArray.length);


Animation anim=new Animation(animArray.length);
int iseq = anim.createSubSequence("walk");
for (int i=0; i<animArray.length; i++) {
Object3D o = animArray[i];
o.build();
o.rotateX((float)-Math.PI/2);
Mesh m = o.getMesh().cloneMesh(true);
m.strip();

anim.addKeyFrame(m);
}
System.out.println("MoveTest::testLoad3DS() setting animation sequence...");
monster2.setAnimationSequence(anim);
System.out.println("MoveTest::testLoad3DS() sequence id is: " + iseq);


}catch(Exception e){
System.err.println("MoveTest::testLoad3DS() " + e.getMessage());
e.printStackTrace();
}
   }



EgonOlsen

Looks fine. Without the cloneMesh(), you are using the same Mesh for the model in the world and as the first animation mesh, which won't work with strip(). The way you are doing it now is fine.

ToddMcF2002

I was able to create and animate a character model with a sword in 3DSMax and get him in the game.  The sword is a seperate mesh and works just like the MD2s.  The only thing I noticed is that my sword seems to get distorted - the hilt is too wide on one sword and the blade too long on a different attempt.  I'm starting to think its not the engine causing the problem though.

One thing is for sure - I have a renewed appreciation for how much work character modeling entails.  I'm a heck of alot better at Java  :P
 

EgonOlsen

Quote from: ToddMcF2002 on April 16, 2007, 08:30:03 PM
The only thing I noticed is that my sword seems to get distorted - the hilt is too wide on one sword and the blade too long on a different attempt.  I'm starting to think its not the engine causing the problem though.
Most likely not. I'm willing to bet that the problem lies within the model itself...

mystara

Quote
I could not find any definitive forum posts validating this for certain - you can use a single 3DS file for your animations just like an MD2.  Works exactly the same.  You could surely export it frame by frame but you don't need to.  Is there some advantage or something?  I like the single file thing because it is consistent with the MD2 approach. 

To export the single 3DS file: 
1.  Tools->Snapshot...
     select 0 - 30 and 30 copies (for the model above that is). 
2.  Edit->Select By->Name
     Select the items you want in the export file - for me it was "monster01", "monster04"..."monster28".  Every 3rd
     frame resulting in a 10 frame animation sequence.  Hit the Select Button before leaving!
3.  File->Export Selected

I've found this guide very useful.
But does anyone know if there is a way to repeat the same process in blender?

i.e. given an animated model, how to export all frames of the model as a set of objects inside a single 3ds file.

Cheers!