@@ -246,6 +246,7 @@ public Object readNode(int nodeIndex) throws IOException {
246246 SkinData skinData = fetchFromCache ("skins" , skinIndex , SkinData .class );
247247 List <Spatial > spatials = skinnedSpatials .get (skinData );
248248 spatials .add (spatial );
249+ skinData .used = true ;
249250 }
250251
251252 spatial .setLocalTransform (readTransforms (nodeData ));
@@ -732,6 +733,17 @@ public void readAnimation(int animationIndex) throws IOException {
732733 logger .log (Level .WARNING , "Morph animation is not supported by JME yet, skipping animation" );
733734 continue ;
734735 }
736+
737+ //if targetNode is a bone, check if it's in a used skin.
738+ BoneWrapper bw = fetchFromCache ("nodes" , targetNode , BoneWrapper .class );
739+ if (bw != null ) {
740+ SkinData skin = fetchFromCache ("skins" , bw .skinIndex , SkinData .class );
741+ if (skin == null || !skin .used ) {
742+ //this skin is not referenced by any mesh, let's not load animation for it.
743+ continue ;
744+ }
745+ }
746+
735747 TrackData trackData = tracks [targetNode ];
736748 if (trackData == null ) {
737749 trackData = new TrackData ();
@@ -790,6 +802,7 @@ public void readAnimation(int animationIndex) throws IOException {
790802 anim .setName (name );
791803 int skinIndex = -1 ;
792804
805+ List <Bone > usedBones = new ArrayList <>();
793806 for (int i = 0 ; i < tracks .length ; i ++) {
794807 TrackData trackData = tracks [i ];
795808 if (trackData == null || trackData .timeArrays .isEmpty ()) {
@@ -810,6 +823,7 @@ public void readAnimation(int animationIndex) throws IOException {
810823 BoneWrapper b = (BoneWrapper ) node ;
811824 //apply the inverseBindMatrix to animation data.
812825 b .update (trackData );
826+ usedBones .add (b .bone );
813827 BoneTrack track = new BoneTrack (b .boneIndex , trackData .times , trackData .translations , trackData .rotations , trackData .scales );
814828 anim .addTrack (track );
815829 if (skinIndex == -1 ) {
@@ -824,6 +838,32 @@ public void readAnimation(int animationIndex) throws IOException {
824838 }
825839 }
826840
841+ // Check each bone to see if their local pose is different from their bind pose.
842+ // If it is, we ensure that the bone has an animation track, else JME way of applying anim transforms will apply the bind pose to those bones,
843+ // instead of the local pose that is supposed to be the default
844+ if (skinIndex != -1 ) {
845+ SkinData skin = fetchFromCache ("skins" , skinIndex , SkinData .class );
846+ Skeleton skeleton = skin .skeletonControl .getSkeleton ();
847+ for (Bone bone : skin .bones ) {
848+ if (!usedBones .contains (bone ) && !equalBindAndLocalTransforms (bone )) {
849+ //create a track
850+ float [] times = new float []{0 , anim .getLength ()};
851+
852+ Vector3f t = bone .getLocalPosition ().subtract (bone .getBindPosition ());
853+ Quaternion r = tmpQuat .set (bone .getBindRotation ()).inverse ().multLocal (bone .getLocalRotation ());
854+ Vector3f s = bone .getLocalScale ().divide (bone .getBindScale ());
855+
856+ Vector3f [] translations = new Vector3f []{t , t };
857+ Quaternion [] rotations = new Quaternion []{r , r };
858+ Vector3f [] scales = new Vector3f []{s , s };
859+
860+ int boneIndex = skeleton .getBoneIndex (bone );
861+ BoneTrack track = new BoneTrack (boneIndex , times , translations , rotations , scales );
862+ anim .addTrack (track );
863+ }
864+ }
865+ }
866+
827867 anim = customContentManager .readExtensionAndExtras ("animations" , animation , anim );
828868
829869 if (skinIndex != -1 ) {
@@ -935,17 +975,25 @@ public void readSkins() throws IOException {
935975 computeBindTransforms (bw , skeleton );
936976 }
937977
938- if (isKeepSkeletonPose (info )) {
939- //Set local transforms.The skeleton may come in a given pose, that is not the rest pose, so let 's apply it.
940- for (int i = 0 ; i < joints .size (); i ++) {
941- applyPose (joints .get (i ).getAsInt ());
978+ // Set local transforms.
979+ // The skeleton may come in a given pose, that is not the rest pose, so let 's apply it.
980+ // We will need it later for animation
981+ for (int i = 0 ; i < joints .size (); i ++) {
982+ applyPose (joints .get (i ).getAsInt ());
983+ }
984+ skeleton .updateWorldVectors ();
985+
986+ //If the user didn't ask to keep the pose we reset the skeleton user control
987+ if (!isKeepSkeletonPose (info )) {
988+ for (Bone bone : bones ) {
989+ bone .setUserControl (false );
942990 }
943- skeleton .updateWorldVectors ();
944991 }
945992
946993 skeleton = customContentManager .readExtensionAndExtras ("skin" , skin , skeleton );
947994
948995 SkinData skinData = new SkinData ();
996+ skinData .bones = bones ;
949997 skinData .skeletonControl = new SkeletonControl (skeleton );
950998 addToCache ("skins" , index , skinData , nodes .size ());
951999 skinnedSpatials .put (skinData , new ArrayList <Spatial >());
@@ -1140,6 +1188,7 @@ private class BoneWrapper {
11401188 int boneIndex ;
11411189 int skinIndex ;
11421190 Transform localTransform ;
1191+ Transform localTransformOffset ;
11431192 Matrix4f modelBindMatrix ;
11441193 boolean isRoot = false ;
11451194 boolean localUpdated = false ;
@@ -1152,6 +1201,7 @@ public BoneWrapper(Bone bone, int boneIndex, int skinIndex, Matrix4f modelBindMa
11521201 this .skinIndex = skinIndex ;
11531202 this .modelBindMatrix = modelBindMatrix ;
11541203 this .localTransform = localTransform ;
1204+ this .localTransformOffset = localTransform .clone ();
11551205 }
11561206
11571207 /**
@@ -1164,15 +1214,15 @@ public void update(TrackData data) {
11641214 if (!localUpdated ) {
11651215 //LocalTransform of the bone are default position to use for animations when there is no track.
11661216 //We need to transform them so that JME can us them in blendAnimTransform.
1167- reverseBlendAnimTransforms (localTransform , bindTransforms );
1217+ reverseBlendAnimTransforms (localTransformOffset , bindTransforms );
11681218 localUpdated = true ;
11691219 }
11701220
11711221 for (int i = 0 ; i < data .getNbKeyFrames (); i ++) {
11721222
1173- Vector3f translation = getTranslation (data , bindTransforms , i );
1174- Quaternion rotation = getRotation (data , bindTransforms , i );
1175- Vector3f scale = getScale (data , bindTransforms , i );
1223+ Vector3f translation = getTranslation (data , i );
1224+ Quaternion rotation = getRotation (data , i );
1225+ Vector3f scale = getScale (data , i );
11761226
11771227 Transform t = new Transform (translation , rotation , scale );
11781228 if (isRoot ) {
@@ -1193,7 +1243,7 @@ public void update(TrackData data) {
11931243 }
11941244 }
11951245
1196- data .ensureTranslationRotations (localTransform );
1246+ data .ensureTranslationRotations (localTransformOffset );
11971247 }
11981248
11991249 private void reverseBlendAnimTransforms (Transform t , Transform bindTransforms ) {
@@ -1208,30 +1258,30 @@ private void reverseBlendAnimTransforms(Transform t, Transform bindTransforms) {
12081258 t .setRotation (tmpQuat );
12091259 }
12101260
1211- private Vector3f getTranslation (TrackData data , Transform bindTransforms , int i ) {
1261+ private Vector3f getTranslation (TrackData data , int i ) {
12121262 Vector3f translation ;
12131263 if (data .translations == null ) {
1214- translation = bindTransforms . getTranslation ();
1264+ translation = bone . getLocalPosition ();
12151265 } else {
12161266 translation = data .translations [i ];
12171267 }
12181268 return translation ;
12191269 }
12201270
1221- private Quaternion getRotation (TrackData data , Transform bindTransforms , int i ) {
1271+ private Quaternion getRotation (TrackData data , int i ) {
12221272 Quaternion rotation ;
12231273 if (data .rotations == null ) {
1224- rotation = bindTransforms . getRotation ();
1274+ rotation = bone . getLocalRotation ();
12251275 } else {
12261276 rotation = data .rotations [i ];
12271277 }
12281278 return rotation ;
12291279 }
12301280
1231- private Vector3f getScale (TrackData data , Transform bindTransforms , int i ) {
1281+ private Vector3f getScale (TrackData data , int i ) {
12321282 Vector3f scale ;
12331283 if (data .scales == null ) {
1234- scale = bindTransforms . getScale ();
1284+ scale = bone . getLocalScale ();
12351285 } else {
12361286 scale = data .scales [i ];
12371287 }
@@ -1243,6 +1293,47 @@ private class SkinData {
12431293 SkeletonControl skeletonControl ;
12441294 AnimControl animControl ;
12451295 Transform armatureTransforms ;
1296+ Bone [] bones ;
1297+ boolean used = false ;
1298+ }
1299+
1300+ private class PartialTransforms {
1301+ Vector3f translation ;
1302+ Quaternion rotation ;
1303+ Vector3f scale ;
1304+ Transform transform ;
1305+
1306+ Transform getTransforms () {
1307+ if (transform == null ) {
1308+ if (translation == null ) {
1309+ translation = new Vector3f ();
1310+ }
1311+ if (rotation == null ) {
1312+ rotation = new Quaternion ();
1313+ }
1314+ if (scale == null ) {
1315+ scale = new Vector3f (1 , 1 , 1 );
1316+ }
1317+ transform = new Transform (translation , rotation , scale );
1318+ }
1319+ return transform ;
1320+ }
1321+
1322+ Transform getTransforms (Transform bindTransforms ) {
1323+ if (transform == null ) {
1324+ if (translation == null ) {
1325+ translation = bindTransforms .getTranslation ();
1326+ }
1327+ if (rotation == null ) {
1328+ rotation = bindTransforms .getRotation ();
1329+ }
1330+ if (scale == null ) {
1331+ scale = bindTransforms .getScale ();
1332+ }
1333+ transform = new Transform (translation , rotation , scale );
1334+ }
1335+ return transform ;
1336+ }
12461337 }
12471338
12481339 public static class SkinBuffers {
0 commit comments