Assuming this is right (on the desktop app to save the bones file):
private void saveToBones(String outFileName) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(outFileName);
BonesIO.saveGroup(animatedGroup, outStream);
outStream.close();
}
catch (FileNotFoundException e) {System.err.println("File Not Found Problem: "+e.getMessage());}
catch (IOException e) {System.err.println("IO Problem: "+e.getMessage());}
}
createAnimatedGroup() should look like:
protected AnimatedGroup createAnimatedGroup() throws Exception {
AnimatedGroup animatedGroup = BonesIO.loadGroup(getResources().openRawResource(R.raw.andersonbones));
Texture texture = new Texture(getResources().openRawResource(R.raw.andersondiffuse));
TextureManager.getInstance().addTexture("texture", texture);
for (Animated3D o : animatedGroup) {
o.setTexture("texture");
o.build();
o.discardMeshData();
}
return animatedGroup;
}
Right? But this isn't working on my phone. I also tried
AnimatedGroup animatedGroup = BonesIO.loadGroup(new FileInputStream(objectFileName));
on the desktop, but it crashes. I should point out that the .bones file looks about right at 2241 KB. I appreciate any insights.
post logs and stack trace please
Actually, I got it to a point in which it no longer crashes. But try as I might I can't get the camera to see it.
I've tried NOT calling discardMeshData() and specifically setting each Animated3D instance to setVisibility(true). Nothing works, but it looks a lot like it should. I even called calcNormals() just to be sure and that didn't make it visible either.
But, by the way,
AnimatedGroup animatedGroup = BonesIO.loadGroup(new FileInputStream(objectFileName));
is now working. But the same file still doesn't load on my phone. And the same camera is on both versions (camera should see the same thing but it shows nothing on phone version).
Now, I've also played with the near and far plane. To sum up:
-I'm seeing the "world" (the FrameBuffer's background color is being drawn) but not the model
-It's not crashing
-The file works and is visible on the PC version
-The camera is in the exact same position as the one on the PC version
-Config.maxPolysVisible > number of polys on the model
-near and far planes are very small and very large respectively
I have nothing left to try as far as I can tell (even the normals don't seem to be the problem). Help?
Quote from: AGP on August 29, 2011, 08:59:11 PM
-Config.maxPolysVisible > number of polys on the model
This isn't related to your problem, but i though i should mention it: This is wasteful. For the Android version, you don't have to reserve that much space, because it doesn't really stand for polygons anymore (but the naming stayed the same for compatibility reasons) but for compiled object parts. An object with 32,000 polygons can very well get away with 4 entries in that structure instead of 32,000.
I'll adjust the docs for this setting.
Cool, thanks. But I suggest renaming maxPolysVisible. Since I already knew it, I didn't look it up on the AE-specific docs. If it's going to do something potentially counter-productive you should totally just rename it. jpct-AE is too young for you to have grave concerns about backward-compatibility anyway.
Do you have any clue as to what might be causing my problem? I assume if it were memory-related it would be crashing, so it really makes no sense to me.
Have you tried to replace your model with some placeholder (for example from Primitives) to see if that actually appears?
Yes, even an OBJ version of the same model works.
Hey, now I'm getting (for the first time!) a "version mismatch" message: "Current version: 3, stream version: 2". That's a jpct message, what does it mean?
No, that was just when I tried replacing my model with Raft's ninja (I guess it was saved with an older version of the exporter).
OK, I narrowed it down to the fact that it crashes just before the following loop ("all's well" is printed before any problem occurs). But again, the file is working (the desktop version of the program loads it nicely). "o is null!" never gets printed.
Logger.log("\n\n************************************************************************All's well.\n\n\n");
for (Animated3D o : animatedGroup) {
if (o == null)
Logger.log("****************************************o is null!!!!");
o.setTexture("texture");
o.build();
o.discardMeshData();
}
Someone help me, please.
I solved it. I'm not remotely sure as to what changed between yesterday it not crashing to it crashing today. But crashing is far more useful becuase it lets you debug it!
you use a Bones file which was serialized by version 2 but you try to open it with version 3.
btw, this is not a log message. this is an exception and you possibly catch print and ignore it.
Quote from: AGP on August 30, 2011, 06:11:04 PM
Hey, now I'm getting (for the first time!) a "version mismatch" message: "Current version: 3, stream version: 2". That's a jpct message, what does it mean?
No, that was just when I tried replacing my model with Raft's ninja (I guess it was saved with an older version of the exporter).
On one of my posts I replaced my model with yours. I noticed it was your model that caused that message and edited that post. At one point an exception was being thrown, and then I changed a few things (not very scientific, I know, but I was trying this for the first time and kind of in a hurry to see it working), one of which the model. I had fixed some things but, in replacing my model with yours, had introduced that message. But anyway, I got it working. But my 9300-poly model (+-4500 vertices) is only rendering at a measly 11 fps on a Galaxy S 2, so the test isn't very good.
i'm afraid 9300 polys is a bit high for such devices
On Egon's request, I just did a very valid test: didn't call animateSkin or animatePose. Otherwise, it's the same program and the same model. It shot up to 60 frames/second. The same model in Unity runs perfectly, so there is, no doubt (now that we know that it's not the graphics pipeline) a lot of room for optimization for Bones.
Try what happens if you omit the animation calls but add a Object3D.touch() instead. That will trigger the vertex data upload for each frame...just to see if that is a bottle neck or not.
Quote from: AGP on September 03, 2011, 08:07:32 PM
The same model in Unity runs perfectly, so there is, no doubt (now that we know that it's not the graphics pipeline) a lot of room for optimization for Bones.
well, unfortunately i dont see much room for optimization except hardware skinning with shaders. and i dont have any plan to implement hardware skinning at least for now
animatedGroup.getRoot().touch() didn't seem to slow it down (but the root is supposed to be a dummy, so I'm not sure if this was a valid test). animatedGroup.get(1).touch() crashes, for some reason ("application stopped unexpectedly").
Update 1: Oh, the reason is probably that I did call discardMeshData(). Do you want me to not destroy the data and call touch() on 1?
Update 2: No, that wasn't it. Even without discardMeshData() get(1).touch() still crashes.
Exception in the log? This is a little strange, because any animation will cause a touch()-call anyway....
Some form of hierarchical organization of which we're not aware in AnimatedGroup, perhaps?
AGP post the stack trace please
@raft: How many vertices does the ninja model actually have? The object compiler says something about 2712 vertices for the model and around 300 for the sword. Does that sound reasonable? And if it does, why should animating AGP's model be so much slower than animating 3 ninjas?
i dont know the exact count but it must be something around that value.
Quote from: EgonOlsen on September 04, 2011, 07:57:28 PM
why should animating AGP's model be so much slower than animating 3 ninjas?
that's a good question. to tell the truth i don't know ::)
@AGP are you using Ninja demo as a base or written your application from scratch? how is the performance if you replace ninja model in ninja demo with your own?
Quote from: raft on September 03, 2011, 08:29:46 PM
well, unfortunately i dont see much room for optimization except hardware skinning with shaders. and i dont have any plan to implement hardware skinning at least for now
Well...this is Android. Even with 2.3, the VM is still crappy to a degree, so you can always do some micro. It did this to the formerly more readable applySkeletonPose()-method in Animated3D:
public void applySkeletonPose() {
SimpleVector[] destMesh = this.destMesh;
SimpleVector[] destNormals = this.destNormals;
// if pose animation is applied, destination vertices are already initialized based on source and offseted, so use them
SimpleVector[] sourceMesh = !destMeshDirty ? destMesh : this.sourceMesh;
//SimpleVector[] sourceNormals = !destMeshDirty ? destNormals : this.sourceNormals;
SimpleVector[] sourceNormals = this.sourceNormals;
SimpleVector vertexTemp = this.vertexTemp;
SimpleVector vertexSum = this.vertexSum;
SimpleVector normalTemp = this.normalTemp;
SimpleVector normalSum = this.normalSum;
// Cycle through each vertex
int end=sourceMesh.length;
float[][] skinweights=skin.weights;
short[][] skinjointIndices=skin.jointIndices;
for (int i = 0; i < end; i++) {
// zero out our sum var
vertexSum.x=0f;
vertexSum.y=0f;
vertexSum.z=0f;
normalSum.x=0f;
normalSum.y=0f;
normalSum.z=0f;
// pull in joint data
final float[] weights = skinweights[i];
final short[] jointIndices = skinjointIndices[i];
SimpleVector sourceMeshi=sourceMesh[i];
SimpleVector sourceNormalsi=sourceNormals[i];
Matrix[] currentPosepalette=currentPose.palette;
for (int j = 0; j < Skeleton.MAX_JOINTS_PER_VERTEX; j++) {
final float weightsj=weights[j];
if (weightsj == 0) {
continue;
}
Matrix mat=currentPosepalette[jointIndices[j]];
// -- vertices --
vertexTemp.x=sourceMeshi.x;
vertexTemp.y=sourceMeshi.y;
vertexTemp.z=sourceMeshi.z;
// Multiply our vertex by the matrix pallete entry
vertexTemp.matMul(mat);
// Sum, weighted.
vertexTemp.x*=weightsj;
vertexTemp.y*=weightsj;
vertexTemp.z*=weightsj;
vertexSum.x+=vertexTemp.x;
vertexSum.y+=vertexTemp.y;
vertexSum.z+=vertexTemp.z;
// -- normals --
normalTemp.x=sourceNormalsi.x;
normalTemp.y=sourceNormalsi.y;
normalTemp.z=sourceNormalsi.z;
// Multiply our vertex by the matrix pallete entry
normalTemp.rotate(mat);
// Sum, weighted.
normalTemp.x*=weightsj;
normalTemp.y*=weightsj;
normalTemp.z*=weightsj;
normalSum.x+=normalTemp.x;
normalSum.y+=normalTemp.y;
normalSum.z+=normalTemp.z;
}
// Store sum into _meshData
destMesh[i].set(vertexSum);
destNormals[i].set(normalSum);
} // for vertices
destMeshDirty = true;
}
For testing purposes, i changed your demo apk to apply the same animation 10times to the ninja in each frame. With my uglification of the method, the frame rate went up from 21 fps to 26 fps on my Nexus S. But then again, the method looks like crap now (reminds me of jPCT-AE's inner loops somehow... ;) ). Keep in mind that Android doesn't like method calls as i can't inline simple methods and it doesn't like array access either, i.e. instead of doing a sourceMesh[ i ] for each j, do it once before entering the j-loop.
Very cool suggestions. 5fps on a Nexus S should be even more on a Galaxy S II, so that's a great start right there.
It's an ArrayIndexOutofBoundsException, oddly enough. I can't copy the trace from LogCat, but it makes a reference to line 78 in AnimatedGroup.
@Egon, you are the master of micro optimizations :) On my N1, animating 8 Ninjas barely increased from 20 fps to 21 fps, I dont know why. But I'll still keep the modification. %5 percent is good enough. I've uploaded the new zip.
@AGP, line 78 in AnimatedGroup is
return objects[index];
so when does that exception happen?
21-26 (on his test) is more like 20%, although I realize you're writing about your test. The exception is thrown on
animatedGroup.get(1).touch();
even when it's preceded by a test of if (animatedGroup.getSize() > 0).
animatedGroup.getSize() > 0
this only ensures that
animatedGroup.get(0)
won't fail ;) appereantly your group is a single object group. so you need to call
animatedGroup.get(0)
OK, but isn't get(0) the same as getRoot() and isn't the root supposed to be a dummy? And if not, well, I've already shown that getRoot().touch() doesn't slow it down.
no, get(0) does not return root. root is not one of Animated3D's. all Animated3D's are attached to root as a child, and it's used to translate/rotate the group easily
Quote from: raft on September 04, 2011, 10:06:58 PM
On my N1, animating 8 Ninjas barely increased from 20 fps to 21 fps, I dont know why. But I'll still keep the modification. %5 percent is good enough.
My test case rendered only one ninja, but applied the animation 10 times to it in a frame...to stress the animation part more than the rendering itself.
Oh, good to know: animatedGroup.get(0).touch() still renders at 60 fps.
Quote from: EgonOlsen on September 04, 2011, 10:34:52 PM
My test case rendered only one ninja, but applied the animation 10 times to it in a frame...to stress the animation part more than the rendering itself.
i see. so we get something around 5% overall
@AGP have you tried replacing Ninja model with your model?
I did the opposite test and got that version mismatch message. Would the reverse work?
with latest version, both tests should work. i especially recommend replacing ninja with your model first
Cool, I'll report back in a second.
OK, 12-13 fps with your ninja demo (exactly the same as mine when I don't call animatePose()). So I'm already experiencing a boost of 20% (didn't really get your conclusion of 5 and now have confirmed 20 in practice). That's a little better but not enough.
can you please post fps of:
* ninja demo with 3 ninjas
* ninja demo with your model
12-13 fps with my model, 59-60 fps with 3 ninjas.
really strange ::) the only explanation i can think of is, your model skinned too heavily. ie: each vertex is influenced by a lot of joints. but still IMHO it shouldnt differ that much.
send me your model and i'll have a look. i'll PM my email
Five ninjas and it's still at 60 fps. I didn't bother test with more, but clearly it can take more ninjas.
i've inspected your model. it seems as it's more complex then you said
a few numbers:
ninja your model
vertices 781+61 28720
joints 28 66
according to these numbers slow down is expected. if your model is really 9300 polygons all vertices should be distinct. even so, there are some extra vertices ::)
@Egon I don't know why object compiler reports 2712+312 vertices for ninja. i get these numbers from VertexController.getSourceMesh()
Because i took these numbers from the desktop version, which doesn't compile to indexed geometry by default, i.e. it results in triangles*3 vertices. Animation processing will still happen on the 781 vertices you mentioned. The compiled pipeline will map between the two formats at runtime. My bad...i should have noticed this earlier. jPCT-AE compiles to indexed geometry by default, at least for animated objects.
Except that it's not more complex then I said (the number of polys here refers to squares rather than tris):
(http://www.agpgames.com/del.jpg)
Multiply by two to get the exact number of tris (but the burger isn't skinned so you'd have to subtract its polys and vertices to get a relevant number).
And again, Unity does it at 60 fps. Since it's not jPCT, I see no reason why bones in a Java VM should be any slower than in a native machine.
Oh, you may be counting the morphs' vertices in addition to the original pose's.
the number comes from IVertexController.getSourceMesh(). it's still strange that 9300 polygons have 27000+ vertices. lots of them should be shared but apparently not in your case.
i don't know what Unity exactly does. maybe it uses hardware skinning?
Look at the screenshot: it's 4800 vertices.
Like I said, IVertexController is probably adding all the morphs together.
jPCT reports me 27000+ vertices. Egon what do you think?
If that's the size of the vertex array in the controller, it's the size that this thing has in memory. No idea what the loader loads though. You can verify this by using Mesh.getUniqueVertexCount(). It should more or less report the same number.
Alright, but I think it's fairly safe to trust 3ds Max's count, don't you? It could be a wrong count by jpct (like, say, counting the sum of all of the morphs), or it could be something weird either by the exporter or by the importer (or, come to think of it, by the second importer and exporter to .bones format).
AGP whay don't you look at mesh.xml file?
I've no idea what a morph is in this context...jPCT displays the number that someone (in this case the loader of that model) has given to it for a mesh. It's a simple array containing the vertex data. If it reports a size of X, that's the size it has...the question is: Why?
An example of a morph would be a copy of the same model with closed eyes. This particular model has several morphs. jpct's normal behavior should probably be to create a new frame for vertex animation (and not add all the different meshes into a single one), but then again I'm not sure how the animation blending is handled.
jPCT doesn't do anything like that. It's not aware of morphs or frames or whatever. Whatever is in the engine is there, because the importer/loader considered it to belong there. If that is wrong, the importer or the file is flawed. The engine itself can't do anything about this.
I know, I meant the loader. But what's different in this case from, say, importing an animated MD2 is that not all of the morphs will have been put in the animation "track" (the morphs are there and OgreMax probably exports even the ones that aren't being used in the animation, but I wouldn't know where they would go).
AGP can you send me your mesh.xml file?
I can only do it a few hours from now, but sure.
@AGP looking at your mesh.xml, there are 9440 polygons and 28320 (=9440x3) vertices. so none of the vertices is shared among polygons. i don't know what causes this. possibly a problem in your model or in exporter. try playing with options of both
neither jPCT nor Bones has any flaw here. they both process what input is given
OK, but the extra vertices are definitely for the morphs. The model, I assure you, is perfect and has, as I've shown 4800 vertices. I'll ask the developer of OgreMax about this and report what he says.
"Remove Duplicate Vertices" (another one for the wiki!) did the trick. I'm up to 35 fps with both skeletal and pose animation (although it should be mentioned I must have exported pose wrong because I don't see the morphs happening so maybe it'll yet slow down but probably not).
Hi All
I am trying to compile the android apllication with no success it seems I need to compile bones into the app is this correct.
Is there a readme/tutorial that explains how to set up the project on android
Bones is just an ordinary library from Android's point of view. Just put bones.jar in your build bath.
for genaral jPCT and Android information have a look at:
http://www.jpct.net/wiki/index.php/Main_Page#jPCT-AE_-_a_port_of_jPCT_to_Android
I tried to add the bones jar but am getting
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.IllegalArgumentException: already added: Lraft/jpct/bones/Animated3D$VertexController;
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:123)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.dex.file.DexFile.add(DexFile.java:143)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main.processClass(Main.java:372)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main.processFileBytes(Main.java:346)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main.access$400(Main.java:59)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:294)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:244)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:130)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:108)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main.processOne(Main.java:313)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main.processAllFiles(Main.java:233)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.dx.command.dexer.Main.run(Main.java:185)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at sun.reflect.GeneratedMethodAccessor14.invoke(Unknown Source)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at java.lang.reflect.Method.invoke(Unknown Source)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.ide.eclipse.adt.internal.build.DexWrapper.run(DexWrapper.java:179)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.ide.eclipse.adt.internal.build.BuildHelper.executeDx(BuildHelper.java:585)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at com.android.ide.eclipse.adt.internal.build.builders.PostCompilerBuilder.build(PostCompilerBuilder.java:490)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:629)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:172)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:203)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:255)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:258)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:311)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:343)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:144)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:242)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx at org.eclipse.core.internal.jobs.Worker.run(Worker.java:54)
[2011-09-09 02:10:12 - NinjaDemoActivity] Dx 1 error; aborting
[2011-09-09 02:10:12 - NinjaDemoActivity] Conversion to Dalvik format failed with error 1
NinjaDemo project depends on Bones project. so it already has all the necessary bones classes. if you add bones.jar to project, there becomes two copies bones classes. try either removing project dependency or removing bones.jar
When you say depends on what do you mean
Whjat do I need to do to get ninjademo to compile for android
are you using Eclipse?
yes but when I try to build ninja without the bones.jar it is missing files
what do you mean by build? run the project or?
I dont know how but its working now
thanks