|
@@ -15,10 +15,7 @@ import com.jme3.util.mikktspace.MikktspaceTangentGenerator;
|
|
|
|
|
|
import java.io.*;
|
|
import java.io.*;
|
|
import java.nio.Buffer;
|
|
import java.nio.Buffer;
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.HashMap;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
|
|
+import java.util.*;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Level;
|
|
import java.util.logging.Logger;
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
@@ -56,8 +53,9 @@ public class GltfLoader implements AssetLoader {
|
|
private Matrix4fArrayPopulator matrix4fArrayPopulator = new Matrix4fArrayPopulator();
|
|
private Matrix4fArrayPopulator matrix4fArrayPopulator = new Matrix4fArrayPopulator();
|
|
private static Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>();
|
|
private static Map<String, MaterialAdapter> defaultMaterialAdapters = new HashMap<>();
|
|
private boolean useNormalsFlag = false;
|
|
private boolean useNormalsFlag = false;
|
|
|
|
+ private Transform tmpTransforms = new Transform();
|
|
|
|
|
|
- Map<Skeleton, List<Spatial>> skinnedSpatials = new HashMap<>();
|
|
|
|
|
|
+ Map<SkinData, List<Spatial>> skinnedSpatials = new HashMap<>();
|
|
|
|
|
|
static {
|
|
static {
|
|
defaultMaterialAdapters.put("pbrMetallicRoughness", new PBRMaterialAdapter());
|
|
defaultMaterialAdapters.put("pbrMetallicRoughness", new PBRMaterialAdapter());
|
|
@@ -146,6 +144,13 @@ public class GltfLoader implements AssetLoader {
|
|
root.attachChild(sceneNode);
|
|
root.attachChild(sceneNode);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ //update skeletons
|
|
|
|
+ for (int i = 0; i < skins.size(); i++) {
|
|
|
|
+ SkinData sd = fetchFromCache("skins", i, SkinData.class);
|
|
|
|
+ sd.skeletonControl.getSkeleton().resetAndUpdate();
|
|
|
|
+ sd.skeletonControl.getSkeleton().setBindingPose();
|
|
|
|
+ }
|
|
|
|
+
|
|
//Loading animations
|
|
//Loading animations
|
|
if (animations != null) {
|
|
if (animations != null) {
|
|
for (int i = 0; i < animations.size(); i++) {
|
|
for (int i = 0; i < animations.size(); i++) {
|
|
@@ -165,7 +170,7 @@ public class GltfLoader implements AssetLoader {
|
|
private Object readNode(int nodeIndex) throws IOException {
|
|
private Object readNode(int nodeIndex) throws IOException {
|
|
Object obj = fetchFromCache("nodes", nodeIndex, Object.class);
|
|
Object obj = fetchFromCache("nodes", nodeIndex, Object.class);
|
|
if (obj != null) {
|
|
if (obj != null) {
|
|
- if (obj instanceof Bone) {
|
|
|
|
|
|
+ if (obj instanceof BoneWrapper) {
|
|
//the node can be a previously loaded bone let's return it
|
|
//the node can be a previously loaded bone let's return it
|
|
return obj;
|
|
return obj;
|
|
} else {
|
|
} else {
|
|
@@ -207,11 +212,13 @@ public class GltfLoader implements AssetLoader {
|
|
|
|
|
|
Integer skinIndex = getAsInteger(nodeData, "skin");
|
|
Integer skinIndex = getAsInteger(nodeData, "skin");
|
|
if (skinIndex != null) {
|
|
if (skinIndex != null) {
|
|
- Skeleton skeleton = fetchFromCache("skins", skinIndex, Skeleton.class);
|
|
|
|
- List<Spatial> spatials = skinnedSpatials.get(skeleton);
|
|
|
|
|
|
+ SkinData skinData = fetchFromCache("skins", skinIndex, SkinData.class);
|
|
|
|
+ List<Spatial> spatials = skinnedSpatials.get(skinData);
|
|
spatials.add(spatial);
|
|
spatials.add(spatial);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ spatial.setLocalTransform(readTransforms(nodeData));
|
|
|
|
+
|
|
if (children != null) {
|
|
if (children != null) {
|
|
for (JsonElement child : children) {
|
|
for (JsonElement child : children) {
|
|
readChild(spatial, child);
|
|
readChild(spatial, child);
|
|
@@ -221,7 +228,6 @@ public class GltfLoader implements AssetLoader {
|
|
if (spatial.getName() == null) {
|
|
if (spatial.getName() == null) {
|
|
spatial.setName(getAsString(nodeData.getAsJsonObject(), "name"));
|
|
spatial.setName(getAsString(nodeData.getAsJsonObject(), "name"));
|
|
}
|
|
}
|
|
- spatial.setLocalTransform(readTransforms(nodeData));
|
|
|
|
|
|
|
|
addToCache("nodes", nodeIndex, spatial, nodes.size());
|
|
addToCache("nodes", nodeIndex, spatial, nodes.size());
|
|
return spatial;
|
|
return spatial;
|
|
@@ -232,14 +238,34 @@ public class GltfLoader implements AssetLoader {
|
|
Object loaded = readNode(child.getAsInt());
|
|
Object loaded = readNode(child.getAsInt());
|
|
if (loaded instanceof Spatial) {
|
|
if (loaded instanceof Spatial) {
|
|
((Node) parent).attachChild((Spatial) loaded);
|
|
((Node) parent).attachChild((Spatial) loaded);
|
|
- } else if (loaded instanceof Bone) {
|
|
|
|
- //fetch the skeleton and add a skeletonControl to the node.
|
|
|
|
- // Skeleton skeleton = fetchFromCache("skeletons", index, Skeleton.class);
|
|
|
|
- // SkeletonControl control = new SkeletonControl(skeleton);
|
|
|
|
- // parent.addControl(control);
|
|
|
|
|
|
+ } else if (loaded instanceof BoneWrapper) {
|
|
|
|
+ //parent is the Armature Node, we have to apply its transforms to all the Bones' bind pose
|
|
|
|
+ BoneWrapper bw = (BoneWrapper) loaded;
|
|
|
|
+ //TODO this part is still not woking properly.
|
|
|
|
+ applyTransformsToArmature(bw, parent.getLocalTransform());
|
|
|
|
+
|
|
|
|
+ //now we can remove the parent node as it's not meant as a real node.
|
|
|
|
+ parent.removeFromParent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private void applyTransformsToArmature(BoneWrapper boneWrapper, Transform transforms) {
|
|
|
|
+ //Transforms are mean in model space, so we need some tricky transformation
|
|
|
|
+ //We have this inverseBindMatrix provided in the gltf for each bone that transforms a vector from mesh's model space to bone's local space.
|
|
|
|
+ //So it's inverse, transforms from bone's local space to mesh model space.
|
|
|
|
+ // we need to transform the bone's bind transforms in this mesh model space, transform them with the transform given in this method,
|
|
|
|
+ // then recompute their local space value according to parents model space
|
|
|
|
+ Bone bone = boneWrapper.bone;
|
|
|
|
+ tmpTransforms.setTranslation(bone.getBindPosition());
|
|
|
|
+ tmpTransforms.setRotation(bone.getBindRotation());
|
|
|
|
+ tmpTransforms.setScale(bone.getBindScale());
|
|
|
|
+
|
|
|
|
+ tmpTransforms.combineWithParent(transforms);
|
|
|
|
+
|
|
|
|
+ bone.setBindTransforms(tmpTransforms.getTranslation(), tmpTransforms.getRotation(), tmpTransforms.getScale());
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
private Transform readTransforms(JsonObject nodeData) {
|
|
private Transform readTransforms(JsonObject nodeData) {
|
|
Transform transform = new Transform();
|
|
Transform transform = new Transform();
|
|
JsonArray matrix = nodeData.getAsJsonArray("matrix");
|
|
JsonArray matrix = nodeData.getAsJsonArray("matrix");
|
|
@@ -592,7 +618,7 @@ public class GltfLoader implements AssetLoader {
|
|
} else {
|
|
} else {
|
|
//check if we are loading the same time array
|
|
//check if we are loading the same time array
|
|
if (animData.times != times) {
|
|
if (animData.times != times) {
|
|
- throw new AssetLoadException("Channel has different input accessors for samplers");
|
|
|
|
|
|
+ // throw new AssetLoadException("Channel has different input accessors for samplers");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (animData.length == null) {
|
|
if (animData.length == null) {
|
|
@@ -619,6 +645,7 @@ public class GltfLoader implements AssetLoader {
|
|
List<Spatial> spatials = new ArrayList<>();
|
|
List<Spatial> spatials = new ArrayList<>();
|
|
Animation anim = new Animation();
|
|
Animation anim = new Animation();
|
|
anim.setName(name);
|
|
anim.setName(name);
|
|
|
|
+ int skinIndex = -1;
|
|
|
|
|
|
for (int i = 0; i < animatedNodes.length; i++) {
|
|
for (int i = 0; i < animatedNodes.length; i++) {
|
|
AnimData animData = animatedNodes[i];
|
|
AnimData animData = animatedNodes[i];
|
|
@@ -635,28 +662,58 @@ public class GltfLoader implements AssetLoader {
|
|
SpatialTrack track = new SpatialTrack(animData.times, animData.translations, animData.rotations, animData.scales);
|
|
SpatialTrack track = new SpatialTrack(animData.times, animData.translations, animData.rotations, animData.scales);
|
|
track.setTrackSpatial(s);
|
|
track.setTrackSpatial(s);
|
|
anim.addTrack(track);
|
|
anim.addTrack(track);
|
|
- } else {
|
|
|
|
- //At some point we'll have bone animation
|
|
|
|
- //TODO support for bone animation.
|
|
|
|
- System.err.println("animated");
|
|
|
|
- System.err.println(node);
|
|
|
|
|
|
+ } else if (node instanceof BoneWrapper) {
|
|
|
|
+ BoneWrapper b = (BoneWrapper) node;
|
|
|
|
+ //apply the inverseBindMatrix to animation data.
|
|
|
|
+ b.update(animData);
|
|
|
|
+ BoneTrack track = new BoneTrack(b.boneIndex, animData.times, animData.translations, animData.rotations, animData.scales);
|
|
|
|
+ anim.addTrack(track);
|
|
|
|
+ if (skinIndex == -1) {
|
|
|
|
+ skinIndex = b.skinIndex;
|
|
|
|
+ } else {
|
|
|
|
+ //Check if all bones affected by this animation are from the same skin, otherwise raise an error.
|
|
|
|
+ if (skinIndex != b.skinIndex) {
|
|
|
|
+ throw new AssetLoadException("Animation " + animationIndex + " (" + name + ") applies to bones that are not from the same skin: skin " + skinIndex + ", bone " + b.bone.getName() + " from skin " + b.skinIndex);
|
|
|
|
+ }
|
|
|
|
+ //else everything is fine.
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (skinIndex != -1) {
|
|
|
|
+ //we have a bone animation.
|
|
|
|
+ SkinData skin = fetchFromCache("skins", skinIndex, SkinData.class);
|
|
|
|
+ if (skin.animControl == null) {
|
|
|
|
+ skin.animControl = new AnimControl(skin.skeletonControl.getSkeleton());
|
|
}
|
|
}
|
|
|
|
+ skin.animControl.addAnim(anim);
|
|
|
|
+ //the controls will be added to the right spatial in setupControls()
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
if (!spatials.isEmpty()) {
|
|
if (!spatials.isEmpty()) {
|
|
- Spatial spatial = null;
|
|
|
|
- if (spatials.size() == 1) {
|
|
|
|
- spatial = spatials.get(0);
|
|
|
|
|
|
+ //Note that it's pretty unlikely to have an animation that is both a spatial animation and a bone animation...But you never know. The specs doesn't forbids it
|
|
|
|
+ if (skinIndex != -1) {
|
|
|
|
+ //there are some spatial tracks in this bone animation... or the other way around. Let's add the spatials in the skinnedSpatials.
|
|
|
|
+ SkinData skin = fetchFromCache("skins", skinIndex, SkinData.class);
|
|
|
|
+ List<Spatial> spat = skinnedSpatials.get(skin);
|
|
|
|
+ spat.addAll(spatials);
|
|
|
|
+ //the animControl will be added in the setupControls();
|
|
} else {
|
|
} else {
|
|
- spatial = findCommonAncestor(spatials);
|
|
|
|
- }
|
|
|
|
|
|
+ Spatial spatial = null;
|
|
|
|
+ if (spatials.size() == 1) {
|
|
|
|
+ spatial = spatials.get(0);
|
|
|
|
+ } else {
|
|
|
|
+ spatial = findCommonAncestor(spatials);
|
|
|
|
+ }
|
|
|
|
|
|
- AnimControl control = spatial.getControl(AnimControl.class);
|
|
|
|
- if (control == null) {
|
|
|
|
- control = new AnimControl();
|
|
|
|
- spatial.addControl(control);
|
|
|
|
|
|
+ AnimControl control = spatial.getControl(AnimControl.class);
|
|
|
|
+ if (control == null) {
|
|
|
|
+ control = new AnimControl();
|
|
|
|
+ spatial.addControl(control);
|
|
|
|
+ }
|
|
|
|
+ control.addAnim(anim);
|
|
}
|
|
}
|
|
- control.addAnim(anim);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -703,74 +760,113 @@ public class GltfLoader implements AssetLoader {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- System.err.println(inverseBindMatrices);
|
|
|
|
-
|
|
|
|
- rootIndex = joints.get(0).getAsInt();
|
|
|
|
-
|
|
|
|
|
|
+ boolean addRootIndex = true;
|
|
Bone[] bones = new Bone[joints.size()];
|
|
Bone[] bones = new Bone[joints.size()];
|
|
for (int i = 0; i < joints.size(); i++) {
|
|
for (int i = 0; i < joints.size(); i++) {
|
|
- bones[i] = readNodeAsBone(joints.get(i).getAsInt(), inverseBindMatrices[i]);
|
|
|
|
|
|
+ int boneIndex = joints.get(i).getAsInt();
|
|
|
|
+ if (boneIndex == rootIndex) {
|
|
|
|
+ addRootIndex = false;
|
|
|
|
+ }
|
|
|
|
+ bones[i] = readNodeAsBone(boneIndex, inverseBindMatrices[i], i, index);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (addRootIndex) {
|
|
|
|
+ //sometimes the root bone is not part of the joint array. in that case we add it at the end of the bone list.
|
|
|
|
+ //The bone won't deform the mesh, but that's pretty common with the root bone.
|
|
|
|
+ Bone[] newBones = new Bone[bones.length + 1];
|
|
|
|
+ System.arraycopy(bones, 0, newBones, 0, bones.length);
|
|
|
|
+ //TODO actually a regular node or a geometry can be attached to a bone, we have to handle this and attach it ti the AttachementNode.
|
|
|
|
+ newBones[bones.length] = readNodeAsBone(rootIndex, new Matrix4f(), bones.length, index);
|
|
|
|
+ findChildren(rootIndex);
|
|
|
|
+ bones = newBones;
|
|
|
|
+ }
|
|
|
|
+
|
|
for (int i = 0; i < joints.size(); i++) {
|
|
for (int i = 0; i < joints.size(); i++) {
|
|
findChildren(joints.get(i).getAsInt());
|
|
findChildren(joints.get(i).getAsInt());
|
|
}
|
|
}
|
|
|
|
|
|
Skeleton skeleton = new Skeleton(bones);
|
|
Skeleton skeleton = new Skeleton(bones);
|
|
- addToCache("skins", index, skeleton, nodes.size());
|
|
|
|
- skinnedSpatials.put(skeleton, new ArrayList<Spatial>());
|
|
|
|
|
|
|
|
- System.err.println(skeleton);
|
|
|
|
|
|
+ SkinData skinData = new SkinData();
|
|
|
|
+ skinData.skeletonControl = new SkeletonControl(skeleton);
|
|
|
|
+ addToCache("skins", index, skinData, nodes.size());
|
|
|
|
+ skinnedSpatials.put(skinData, new ArrayList<Spatial>());
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- private Bone readNodeAsBone(int nodeIndex, Matrix4f inverseBindMatrix) throws IOException {
|
|
|
|
|
|
+ private Bone readNodeAsBone(int nodeIndex, Matrix4f inverseBindMatrix, int boneIndex, int skinIndex) throws IOException {
|
|
|
|
|
|
- Bone bone = fetchFromCache("nodes", nodeIndex, Bone.class);
|
|
|
|
- if (bone != null) {
|
|
|
|
- return bone;
|
|
|
|
|
|
+ BoneWrapper boneWrapper = fetchFromCache("nodes", nodeIndex, BoneWrapper.class);
|
|
|
|
+ if (boneWrapper != null) {
|
|
|
|
+ return boneWrapper.bone;
|
|
}
|
|
}
|
|
JsonObject nodeData = nodes.get(nodeIndex).getAsJsonObject();
|
|
JsonObject nodeData = nodes.get(nodeIndex).getAsJsonObject();
|
|
- JsonArray children = nodeData.getAsJsonArray("children");
|
|
|
|
String name = getAsString(nodeData, "name");
|
|
String name = getAsString(nodeData, "name");
|
|
if (name == null) {
|
|
if (name == null) {
|
|
name = "Bone_" + nodeIndex;
|
|
name = "Bone_" + nodeIndex;
|
|
}
|
|
}
|
|
- bone = new Bone(name);
|
|
|
|
|
|
+ Bone bone = new Bone(name);
|
|
Transform boneTransforms = readTransforms(nodeData);
|
|
Transform boneTransforms = readTransforms(nodeData);
|
|
- Transform inverseBind = new Transform();
|
|
|
|
- inverseBind.fromTransformMatrix(inverseBindMatrix);
|
|
|
|
- // boneTransforms.combineWithParent(inverseBind);
|
|
|
|
bone.setBindTransforms(boneTransforms.getTranslation(), boneTransforms.getRotation(), boneTransforms.getScale());
|
|
bone.setBindTransforms(boneTransforms.getTranslation(), boneTransforms.getRotation(), boneTransforms.getScale());
|
|
|
|
|
|
|
|
+ addToCache("nodes", nodeIndex, new BoneWrapper(bone, boneIndex, skinIndex, inverseBindMatrix), nodes.size());
|
|
|
|
+//
|
|
|
|
+// System.err.println(bone.getName() + " " + inverseBindMatrix);
|
|
|
|
+// tmpTransforms.fromTransformMatrix(inverseBindMatrix);
|
|
|
|
+// System.err.println("t: " + tmpTransforms.getTranslation());
|
|
|
|
+// System.err.println("r: " + tmpTransforms.getRotation());
|
|
|
|
+// Quaternion q = tmpTransforms.getRotation();
|
|
|
|
+// float[] axis = new float[3];
|
|
|
|
+// q.toAngles(axis);
|
|
|
|
+// for (int i = 0; i < axis.length; i++) {
|
|
|
|
+// System.err.print(axis[i] + ", ");
|
|
|
|
+// }
|
|
|
|
+// System.err.println("");
|
|
|
|
+// System.err.println("s: " + tmpTransforms.getScale());
|
|
|
|
|
|
- addToCache("nodes", nodeIndex, bone, nodes.size());
|
|
|
|
return bone;
|
|
return bone;
|
|
}
|
|
}
|
|
|
|
|
|
private void findChildren(int nodeIndex) {
|
|
private void findChildren(int nodeIndex) {
|
|
- Bone bone = fetchFromCache("nodes", nodeIndex, Bone.class);
|
|
|
|
|
|
+ BoneWrapper bw = fetchFromCache("nodes", nodeIndex, BoneWrapper.class);
|
|
JsonObject nodeData = nodes.get(nodeIndex).getAsJsonObject();
|
|
JsonObject nodeData = nodes.get(nodeIndex).getAsJsonObject();
|
|
JsonArray children = nodeData.getAsJsonArray("children");
|
|
JsonArray children = nodeData.getAsJsonArray("children");
|
|
if (children != null) {
|
|
if (children != null) {
|
|
for (JsonElement child : children) {
|
|
for (JsonElement child : children) {
|
|
- bone.addChild(fetchFromCache("nodes", child.getAsInt(), Bone.class));
|
|
|
|
|
|
+ int childIndex = child.getAsInt();
|
|
|
|
+ BoneWrapper cbw = fetchFromCache("nodes", childIndex, BoneWrapper.class);
|
|
|
|
+ if (cbw != null) {
|
|
|
|
+ bw.bone.addChild(cbw.bone);
|
|
|
|
+ bw.children.add(childIndex);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void setupControls() {
|
|
private void setupControls() {
|
|
- for (Skeleton skeleton : skinnedSpatials.keySet()) {
|
|
|
|
- List<Spatial> spatials = skinnedSpatials.get(skeleton);
|
|
|
|
- Spatial spatial = null;
|
|
|
|
|
|
+ for (SkinData skinData : skinnedSpatials.keySet()) {
|
|
|
|
+ List<Spatial> spatials = skinnedSpatials.get(skinData);
|
|
|
|
+ Spatial spatial;
|
|
if (spatials.size() >= 1) {
|
|
if (spatials.size() >= 1) {
|
|
spatial = findCommonAncestor(spatials);
|
|
spatial = findCommonAncestor(spatials);
|
|
} else {
|
|
} else {
|
|
spatial = spatials.get(0);
|
|
spatial = spatials.get(0);
|
|
}
|
|
}
|
|
- SkeletonControl control = new SkeletonControl(skeleton);
|
|
|
|
- spatial.addControl(control);
|
|
|
|
|
|
+
|
|
|
|
+ AnimControl animControl = spatial.getControl(AnimControl.class);
|
|
|
|
+ if (animControl != null) {
|
|
|
|
+ //The spatial already has an anim control, we need to merge it with the one in skinData. Then remove it.
|
|
|
|
+ for (String name : animControl.getAnimationNames()) {
|
|
|
|
+ Animation anim = animControl.getAnim(name);
|
|
|
|
+ skinData.animControl.addAnim(anim);
|
|
|
|
+ }
|
|
|
|
+ spatial.removeControl(animControl);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ spatial.addControl(skinData.animControl);
|
|
|
|
+ spatial.addControl(skinData.skeletonControl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -805,6 +901,43 @@ public class GltfLoader implements AssetLoader {
|
|
float[] weights;
|
|
float[] weights;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private class BoneWrapper {
|
|
|
|
+ Bone bone;
|
|
|
|
+ int boneIndex;
|
|
|
|
+ int skinIndex;
|
|
|
|
+ Matrix4f bindMatrix = new Matrix4f();
|
|
|
|
+ List<Integer> children = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ public BoneWrapper(Bone bone, int boneIndex, int skinIndex, Matrix4f inverseBindMatrix) {
|
|
|
|
+ this.bone = bone;
|
|
|
|
+ this.boneIndex = boneIndex;
|
|
|
|
+ this.skinIndex = skinIndex;
|
|
|
|
+ this.bindMatrix.set(inverseBindMatrix).invertLocal();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Applies the inverseBindMatrix to anim data.
|
|
|
|
+ */
|
|
|
|
+ public void update(AnimData data) {
|
|
|
|
+ Transform invBind = new Transform(bone.getBindPosition(), bone.getBindRotation(), bone.getBindScale());
|
|
|
|
+ invBind = invBind.invert();
|
|
|
|
+ //invBind.fromTransformMatrix(bindMatrix);
|
|
|
|
+ for (int i = 0; i < data.translations.length; i++) {
|
|
|
|
+ Transform t = new Transform(data.translations[i], data.rotations[i], data.scales[i]);
|
|
|
|
+ t.combineWithParent(invBind);
|
|
|
|
+ data.translations[i] = t.getTranslation();
|
|
|
|
+ data.rotations[i] = t.getRotation();
|
|
|
|
+ data.scales[i] = t.getScale();
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private class SkinData {
|
|
|
|
+ SkeletonControl skeletonControl;
|
|
|
|
+ AnimControl animControl;
|
|
|
|
+ }
|
|
|
|
+
|
|
private interface Populator<T> {
|
|
private interface Populator<T> {
|
|
T populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException;
|
|
T populate(Integer bufferViewIndex, int componentType, String type, int count, int byteOffset) throws IOException;
|
|
}
|
|
}
|
|
@@ -837,7 +970,6 @@ public class GltfLoader implements AssetLoader {
|
|
}
|
|
}
|
|
vb.setupData(VertexBuffer.Usage.Dynamic, numComponents, format, buff);
|
|
vb.setupData(VertexBuffer.Usage.Dynamic, numComponents, format, buff);
|
|
|
|
|
|
-
|
|
|
|
return vb;
|
|
return vb;
|
|
}
|
|
}
|
|
|
|
|