kapa76 / jmonkeyengine

Automatically exported from code.google.com/p/jmonkeyengine
0 stars 0 forks source link

SkeletonControl does not track changes to materials or spatials #592

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1.Load the Oto model
2.set a new material to the model (must be a HardwareSkining complient 
material). for example just clone the model's material and assign it to the 
model.
3.get the SkeletonControl from the model and call 
control.setHardwareSkinningPreferred(hwSkinningEnable);
4.get the animcontrol, create a channel and set the "Walk" animation on it

What is the expected output? What do you see instead?
I expect hardware skinning to work and see my model animated.
Instead the model is not animated.

The reason is that the NUM_BONES define is not assigned to the material so 
Hardware Skinning is disabled.
The problem is that the Skeleton control gathers the materials on which to set 
the parameter only on control.setSpatial().
If the material is changed afterwards on the model it's not in the list of 
material of the SkeletonControl.
On a side note this could lead to memory leak as the SkeletonControl holds a 
reference to the old unused material.

A workaround is after setting the new material is to call 
skeletonControl.setSpatial(model). The targets will be properly gathered again.

We'd need a way to somehow notify the skeleton control that a material has been 
changed on one of its target.

here is a test case of the issue http://pastebin.com/trEXCykU

Original issue reported on code.google.com by remy.bou...@gmail.com on 22 Apr 2013 at 9:29

GoogleCodeExporter commented 9 years ago
A similar issue occurs when trying to add or remove "skins" from the model, or 
the geometries. The list of mesh "targets" is also not updated.

Option 1: Do not store target materials and meshes on the SkeletonControl 
object, but generate them at runtime every frame. This is the easiest but also 
most expensive option. On the plus side you only have to do this on 
controlRender(), so this computation only occurs for models visible on the 
screen.

Option 2: Add a new refresh flag that can be used to track changes to materials 
and attach/detach of spatials. In SkeletonControl.controlUpdate() you check for 
these flags and update the material/mesh target list accordingly. 
Spatial.updateGeoemtricState() will simply set them to 0 when it goes through 
the scene graph.

Original comment by ShadowIs...@gmail.com on 24 Apr 2013 at 1:42

GoogleCodeExporter commented 9 years ago
I tried both ways.
A new refresh flag was working but idk how it would have worked if materials 
were changed on sub target nodes and so on. 

I ended up doing it as option 1 suggested, and in practice it doesn't have a 
noticeable impact on performance (I tired with 100 animated Otos). I guess it 
could have a more noticeable impact if the sub graph is complex, but that's not 
very likely to happen.

Also to avoid instantiating new arrays and lists on each frames, I changed the 
way target meshes and materials were stored. I now use a safeArrayList for 
target meshes and a HashSet for materials. This avoid instantiation and array 
copies on each frames.

An a side note, now that target meshes and materials are gathered on each 
frame, there is no need to serialize them so i removed them from the read/write 
method.

@ShadowIsLord please review/comment this change 
http://code.google.com/p/jmonkeyengine/source/detail?r=10577

Original comment by remy.bou...@gmail.com on 27 Apr 2013 at 2:36

GoogleCodeExporter commented 9 years ago
I made another change to do the update on render instead of on update as you 
suggested.
https://code.google.com/p/jmonkeyengine/source/detail?r=10578

Original comment by remy.bou...@gmail.com on 27 Apr 2013 at 2:44