3131 */
3232package com .jme3 .anim ;
3333
34- import com .jme3 .export .InputCapsule ;
35- import com .jme3 .export .JmeExporter ;
36- import com .jme3 .export .JmeImporter ;
37- import com .jme3 .export .OutputCapsule ;
38- import com .jme3 .export .Savable ;
39- import com .jme3 .material .*;
34+ import com .jme3 .export .*;
35+ import com .jme3 .material .MatParam ;
36+ import com .jme3 .material .MatParamOverride ;
37+ import com .jme3 .material .Material ;
4038import com .jme3 .renderer .*;
4139import com .jme3 .scene .*;
4240import com .jme3 .scene .control .AbstractControl ;
4745import com .jme3 .util .clone .Cloner ;
4846import java .io .IOException ;
4947import java .nio .FloatBuffer ;
48+ import java .util .ArrayList ;
5049import java .util .logging .Level ;
5150import java .util .logging .Logger ;
5251
5554 * All stock shaders only support morphing these 3 buffers, but note that MorphTargets can have any type of buffers.
5655 * If you want to use other types of buffers you will need a custom MorphControl and a custom shader.
5756 *
57+ * Note that if morphed children are attached to or detached from the sub graph after the MorphControl is added to
58+ * spatial, you must detach and attach the control again for the changes to get reflected.
59+ *
5860 * @author Rémy Bouquet
5961 */
6062public class MorphControl extends AbstractControl implements Savable {
@@ -65,6 +67,7 @@ public class MorphControl extends AbstractControl implements Savable {
6567 private final static float MIN_WEIGHT = 0.005f ;
6668
6769 private static final String TAG_APPROXIMATE = "approximateTangents" ;
70+ private static final String TAG_TARGETS = "targets" ;
6871
6972 private SafeArrayList <Geometry > targets = new SafeArrayList <>(Geometry .class );
7073 private TargetLocator targetLocator = new TargetLocator ();
@@ -79,22 +82,31 @@ public class MorphControl extends AbstractControl implements Savable {
7982 private static final VertexBuffer .Type bufferTypes [] = VertexBuffer .Type .values ();
8083
8184 @ Override
82- protected void controlUpdate (float tpf ) {
83- if (!enabled ) {
84- return ;
85+ public void setSpatial (Spatial spatial ) {
86+ super .setSpatial (spatial );
87+
88+ // Remove matparam override from the old targets
89+ for (Geometry target : targets .getArray ()) {
90+ target .removeMatParamOverride (nullNumberOfBones );
8591 }
92+
8693 // gathering geometries in the sub graph.
87- // This must be done in the update phase as the gathering might add a matparam override
94+ // This must not be done in the render phase as the gathering might add a matparam override
95+ // which then will throw an IllegalStateException if done in the render phase.
8896 targets .clear ();
89- this .spatial .depthFirstTraversal (targetLocator );
97+ if (spatial != null ) {
98+ spatial .depthFirstTraversal (targetLocator );
99+ }
100+ }
101+
102+ @ Override
103+ protected void controlUpdate (float tpf ) {
104+
90105 }
91106
92107 @ Override
93108 protected void controlRender (RenderManager rm , ViewPort vp ) {
94- if (!enabled ) {
95- return ;
96- }
97- for (Geometry geom : targets ) {
109+ for (Geometry geom : targets .getArray ()) {
98110 Mesh mesh = geom .getMesh ();
99111 if (!geom .isDirtyMorph ()) {
100112 continue ;
@@ -428,6 +440,7 @@ public void read(JmeImporter importer) throws IOException {
428440 super .read (importer );
429441 InputCapsule capsule = importer .getCapsule (this );
430442 approximateTangents = capsule .readBoolean (TAG_APPROXIMATE , true );
443+ targets .addAll (capsule .readSavableArrayList (TAG_TARGETS , null ));
431444 }
432445
433446 /**
@@ -442,6 +455,7 @@ public void write(JmeExporter exporter) throws IOException {
442455 super .write (exporter );
443456 OutputCapsule capsule = exporter .getCapsule (this );
444457 capsule .write (approximateTangents , TAG_APPROXIMATE , true );
458+ capsule .writeSavableArrayList (new ArrayList (targets ), TAG_TARGETS , null );
445459 }
446460
447461 private class TargetLocator extends SceneGraphVisitorAdapter {
0 commit comments