Skip to content

Instantly share code, notes, and snippets.

@devcem
Created May 13, 2020 09:17
Show Gist options
  • Save devcem/0de6441f43326e438dfbadfc1bcea510 to your computer and use it in GitHub Desktop.
Save devcem/0de6441f43326e438dfbadfc1bcea510 to your computer and use it in GitHub Desktop.
PlayCanvas animation blending, a clone from repository
var Mixer = pc.createScript('mixer');
Mixer.attributes.add('spineBone', { type: 'string', default: 'SpineBone', title: 'Spine Bone' });
Mixer.attributes.add('upperLayerMask', { type: 'string', array : true });
Mixer.attributes.add('lowerLayerMask', { type: 'string', array : true });
Mixer.attributes.add('animationNames', { type: 'string', array : true });
Mixer.attributes.add('animationMasks', { type: 'string', array : true });
Mixer.prototype.initialize = function() {
this.skins = this.entity.model.model.skinInstances;
this.bones = {};
this.force = false;
this.timestamp = 0;
this.currentTime = 0;
this.currentSpeed = 1;
this.animationStop = false;
for(var s = 0; s < this.skins.length; s++) {
for(var b = 0; b < this.skins[s].bones.length; b++) {
this.bones[this.skins[s].bones[b].name] = this.skins[s].bones[b];
}
}
this.layers = [];
this.frames = [];
this.animations = this.entity.animation.data.animations;
for(var animationIndex in this.animationNames){
var animation = this.animationNames[animationIndex];
this.layers.push(this.CreateAvatarAnim(
this.spineBone,
this[this.animationMasks[animationIndex]],
this.CreateLayerAnim(this[this.animationMasks[animationIndex]], animation,
this.entity.animation.getAnimation(animation)
)
));
}
};
Mixer.prototype.CreateLayerAnim = function(layer, id, anim){
return {
'layer' : layer,
'id' : id,
'anim' : anim
};
};
Mixer.prototype.CreateSkeleton = function(rootBone, skinnedMesh, targetBones) {
var boneGraph = skinnedMesh.model.model.getGraph();
var rootBoneNodes = boneGraph.findByName(rootBone);
var bones = { };
var thisGraph = [];
var skins = skinnedMesh.model.model.skinInstances;
for(var s = 0; s < skins.length; s++) {
for(var b = 0; b < skins[s].bones.length; b++) {
bones[skins[s].bones[b].name] = skins[s].bones[b];
}
}
for(var index in targetBones) {
var boneNode = targetBones[index];
for(var xindex in bones) {
var bone = bones[xindex];
if(bone.name == boneNode) {
thisGraph.push(bone);
}
}
}
var rootBoneSkeleton = new pc.Skeleton(rootBoneNodes);
rootBoneSkeleton.setGraph(rootBoneNodes);
rootBoneSkeleton.boneGraph = thisGraph;
return rootBoneSkeleton;
};
Mixer.prototype.CreateAvatarAnim = function(rootBone, targetBones, animObject, animation){
var thisSkeleton = this.CreateSkeleton(rootBone, this.entity, targetBones);
this.layerSkeletonAnimClip = new pc.Animation();
var layerSkeletonNodes = animObject.anim.nodes;
var relevantFilteredNodes = layerSkeletonNodes.filter(function(node) {
for(var index in targetBones) {
var skelNode = targetBones[index];
if(node._name == skelNode) {
return node;
}
}
});
for(var index in relevantFilteredNodes) {
var node = relevantFilteredNodes[index];
if(index != "binaryIndexOf"){
this.layerSkeletonAnimClip.addNode(node);
}
}
this.layerSkeletonAnimClip.name = animObject.id;
this.layerSkeletonAnimClip.duration = animObject.anim.duration;
thisSkeleton.animation = this.layerSkeletonAnimClip;
thisSkeleton.updateAnim = false;
thisSkeleton.targetBones = targetBones;
thisSkeleton.id = animObject.id;
return thisSkeleton;
};
Mixer.prototype.play = function(id, time, speed) {
this.layers.find(function(layer){
if(layer.id == id) {
layer.updateAnim = true;
}
});
this.timestamp = 0;
this.currentTime = time;
this.currentSpeed = speed;
this.animationStop = false;
};
Mixer.prototype.stop = function() {
if(this.animationStop){
return false;
}
this.force = true;
this.currentTime = 0;
this.timestamp = 0;
for(var index in this.layers) {
var skeletonLayer = this.layers[index];
skeletonLayer.updateAnim = false;
}
this.animationStop = true;
};
Mixer.prototype.postUpdate = function(dt) {
for(var index in this.layers) {
var skeletonLayer = this.layers[index];
if(skeletonLayer.updateAnim) {
skeletonLayer.addTime(dt * this.currentSpeed);
skeletonLayer.updateGraph();
}
}
if(this.timestamp > this.currentTime){
this.stop();
}
this.timestamp+=dt;
};
@constlet
Copy link

Hey @devcem, does this still work? I would really like to use this, but cannot figure it out. Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment