Loading Bones on Android

Started by AGP, August 29, 2011, 10:02:52 AM

Previous topic - Next topic

EgonOlsen

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.

raft

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

AGP

#17
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.

EgonOlsen

Exception in the log? This is a little strange, because any animation will cause a touch()-call anyway....

AGP

Some form of hierarchical organization of which we're not aware in AnimatedGroup, perhaps?

raft


EgonOlsen

@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?

raft

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?

EgonOlsen

#23
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.

AGP

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.

raft

@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?

AGP

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).

raft

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)

AGP

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.

raft

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