Author Topic: Loading Bones on Android  (Read 11982 times)

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11769
    • View Profile
    • http://www.jpct.net
Re: Loading Bones on Android
« Reply #15 on: September 03, 2011, 08:24:32 pm »
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.

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1970
    • View Profile
    • http://www.aptalkarga.com
Re: Loading Bones on Android
« Reply #16 on: September 03, 2011, 08:29:46 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

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: Loading Bones on Android
« Reply #17 on: September 03, 2011, 08:36:54 pm »
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.
« Last Edit: September 03, 2011, 08:43:53 pm by AGP »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11769
    • View Profile
    • http://www.jpct.net
Re: Loading Bones on Android
« Reply #18 on: September 03, 2011, 11:47:58 pm »
Exception in the log? This is a little strange, because any animation will cause a touch()-call anyway....

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: Loading Bones on Android
« Reply #19 on: September 04, 2011, 04:38:10 am »
Some form of hierarchical organization of which we're not aware in AnimatedGroup, perhaps?

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1970
    • View Profile
    • http://www.aptalkarga.com
Re: Loading Bones on Android
« Reply #20 on: September 04, 2011, 02:40:05 pm »
AGP post the stack trace please

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11769
    • View Profile
    • http://www.jpct.net
Re: Loading Bones on Android
« Reply #21 on: September 04, 2011, 07:57:28 pm »
@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?

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1970
    • View Profile
    • http://www.aptalkarga.com
Re: Loading Bones on Android
« Reply #22 on: September 04, 2011, 08:12:47 pm »
i dont know the exact count but it must be something around that value.

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?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11769
    • View Profile
    • http://www.jpct.net
Re: Loading Bones on Android
« Reply #23 on: September 04, 2011, 08:37:53 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:

Code: [Select]
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.
« Last Edit: September 04, 2011, 08:42:52 pm by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: Loading Bones on Android
« Reply #24 on: September 04, 2011, 08:55:04 pm »
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.

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1970
    • View Profile
    • http://www.aptalkarga.com
Re: Loading Bones on Android
« Reply #25 on: September 04, 2011, 10:06:58 pm »
@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
Code: [Select]
return objects[index];so when does that exception happen?

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: Loading Bones on Android
« Reply #26 on: September 04, 2011, 10:18:18 pm »
21-26 (on his test) is more like 20%, although I realize you're writing about your test. The exception is thrown on

Code: [Select]
animatedGroup.get(1).touch();

even when it's preceded by a test of if (animatedGroup.getSize() > 0).

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1970
    • View Profile
    • http://www.aptalkarga.com
Re: Loading Bones on Android
« Reply #27 on: September 04, 2011, 10:21:41 pm »
Code: [Select]
animatedGroup.getSize() > 0
this only ensures that

Code: [Select]
animatedGroup.get(0)
won't fail ;) appereantly your group is a single object group. so you need to call

Code: [Select]
animatedGroup.get(0)

Offline AGP

  • quad
  • ******
  • Posts: 1524
    • View Profile
Re: Loading Bones on Android
« Reply #28 on: September 04, 2011, 10:29:57 pm »
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.

Offline raft

  • Moderator
  • quad
  • *****
  • Posts: 1970
    • View Profile
    • http://www.aptalkarga.com
Re: Loading Bones on Android
« Reply #29 on: September 04, 2011, 10:33:09 pm »
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