After I have run an application for long time (6-12 hours), I encounter this strange bug, which ends playing some animations. More specifically, when this happens, the default pose is bound for a mesh – as if there were no animations at all.
This happens first to one model, but when time passes, more models are affected until all of the animations end playing. This bug happens randomly, and the animation which stops changes from time to time (is also random). Also, there is no error nor warning message. The animation just stops.
I am using (radakan) OGRE XML importer and bone animation code. I also use software bone animation. My renderer is LWJGL renderer. I have debugged the OGRE XML bone animation code, and it doesn't seem to be the cause of this problem. (I might be mistaken, of course.)
More specifically, the behavior is as if softwareSkinUpdate() is not called inside ogrexml.anim.MeshAnimationController.update(). softwareSkinUpdate() would update vertex buffers for animation, but seems it's not called due the bug. Another possibility is that the vertex buffer is not updated for whatever reason. I am strongly suspecting a native buffer related bug.
I am getting desperate with this! The debugging is difficult, because there is no error or warning, and it happens only when application has run many hours. Can you help with this? Any insight?
You should use the Ogre3D importer included with jME2 SVN, not the one from the radakan project.
You're saying, that softwareSkinUpdate() is no longer called after a long period of time, but is the update() method called? Is the controller active? Frameskip is turned off? Perhaps the animation is changed (setAnimation)?
Wow,…just for curiosity, why are you using one animation for 6-12h? Are you using jME in a showcase?
Yes. I am running the same animation indefinitely. It's a aquarium 3D application, supposed to run on a large wall display.
I investigated the problem, and the cause seems to be a bug in the OGRE XML importer's BoneTrack.setTime() method. The issue is result of IndexOutOfBoundsException. Exception causes the MeshController.update() to terminate midway – the animation is first reset to default pose, but then call to setTime() throws exception.
The exception gives no warning or error. It's because of the exception handling in the Spatial.updateWorldData() method. More of this later in the post…
Exception happens in the following lines in BoneTrack.setTime():
...
for (int i = 0; i < times.length; i++){
if (times[i] <= time){
startFrame = i;
endFrame = i + 1;
}
}
float blend = (time - times[startFrame]) / (times[endFrame] - times[startFrame]); <---- EXCEPTION
...
The reason is obvious, endFrame is out of bounds. Assuming I understand the code completely, I propose the following check after the for loop:
if (endFrame >= times.length){
endFrame = times.length - 1;
}
Why this problem is difficult to trace, is because Spatial.updateWorldData() method catches the exception and does nothing! Here is the block where exception is handled (in Spatial.updateWorldData()):
...
try {
Controller controller = geometricalControllers.get(i);
if (controller != null) {
if (controller.isActive()) {
controller.update(time);
}
}
} catch (IndexOutOfBoundsException e) {
// a controller was removed in Controller.update (note: this
// may skip one controller)
break;
}
...
There is no indication something went wrong, which makes debugging extremely difficult! What I suggest, there should be a warning in the catch block, or this piece of code could be rewritten (of which latter is IMHO better idea). At least something should be done to the catch block...
I had actually encountered this issue before, found out that the exception was being dropped in that particular method. But I couldn't identify the problem in the loop…
Now I see where it happens. If you inspect the code you see that there's no way endFrame can go beyond the size of the array because it is checked before
}else if (time > times[times.length-1]){ // <--- here
target.setAnimTransforms(translations[translations.length-1],
rotations[rotations.length-1]);
However this if tests if time > times[times.length -1] while the loop checks times <= time.
In other words, if the current time and the last frame time are exactly the same, you will have a crash. The likeliness of this happening is very rare so that's why you only encounter the issue after a few hours of playing the animation.
So, I think the proper fix is to change the first two if statements from > to >= and that should fix these issues.
There is no indication something went wrong, which makes debugging extremely difficult! What I suggest, there should be a warning in the catch block, or this piece of code could be rewritten (of which latter is IMHO better idea). At least something should be done to the catch block...
It should be rewritten, it's really a hack if you look at it. In the case where you try to remove a controller inside that loop, it should at least catch the exception where the exception can actually happen, rather than go around the Controller.update as well.
That is a very good explanation why it happens randomly! I'll try the solution to change > to >= . I'd think that will fix the problem.
OK! Confirmed. It fixed the problem! :D
Now the bug should be fixed in the trunk…