Skip to content

Commit 3c3dc59

Browse files
AnimComponent fixes (playcanvas#2886)
* anim component fixes Co-authored-by: Will Eastcott <will@playcanvas.com>
1 parent 8ef9152 commit 3c3dc59

14 files changed

+295
-165
lines changed

src/anim/binder/default-anim-binder.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,14 @@ class DefaultAnimBinder {
138138

139139
// #ifdef DEBUG
140140
var fallbackGraphPath = AnimBinder.encode(path.entityPath[path.entityPath.length - 1] || "", 'graph', path.propertyPath);
141-
if (this.visitedFallbackGraphPaths[fallbackGraphPath]) {
141+
if (this.visitedFallbackGraphPaths[fallbackGraphPath] === 1) {
142142
console.warn('Anim Binder: Multiple animation curves with the path ' + fallbackGraphPath + ' are present in the ' + this.graph.path + ' graph which may result in the incorrect binding of animations');
143143
}
144-
this.visitedFallbackGraphPaths[fallbackGraphPath] = true;
144+
if (!Number.isFinite(this.visitedFallbackGraphPaths[fallbackGraphPath])) {
145+
this.visitedFallbackGraphPaths[fallbackGraphPath] = 0;
146+
} else {
147+
this.visitedFallbackGraphPaths[fallbackGraphPath]++;
148+
}
145149
// #endif
146150
}
147151
return node;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { math } from '../../math/math.js';
2+
3+
import { AnimBlendTree } from './anim-blend-tree.js';
4+
5+
/**
6+
* @private
7+
* @class
8+
* @name AnimBlendTree1D
9+
* @classdesc An AnimBlendTree that calculates its weights using a 1D algorithm
10+
* @description Create a new BlendTree1D.
11+
*/
12+
class AnimBlendTree1D extends AnimBlendTree {
13+
constructor(state, parent, name, point, parameters, children, createTree, findParameter) {
14+
children.sort((a, b) => a.point - b.point);
15+
super(state, parent, name, point, parameters, children, createTree, findParameter);
16+
}
17+
18+
calculateWeights() {
19+
if (this.updateParameterValues()) return;
20+
var i;
21+
this._children[0].weight = 0.0;
22+
for (i = 0; i < this._children.length - 1; i++) {
23+
var c1 = this._children[i];
24+
var c2 = this._children[i + 1];
25+
if (c1.point === c2.point) {
26+
c1.weight = 0.5;
27+
c2.weight = 0.5;
28+
} else if (math.between(this._parameterValues[0], c1.point, c2.point, true)) {
29+
var child2Distance = Math.abs(c1.point - c2.point);
30+
var parameterDistance = Math.abs(c1.point - this._parameterValues[0]);
31+
var weight = (child2Distance - parameterDistance) / child2Distance;
32+
c1.weight = weight;
33+
c2.weight = (1.0 - weight);
34+
} else {
35+
c2.weight = 0.0;
36+
}
37+
}
38+
}
39+
}
40+
export { AnimBlendTree1D };
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Vec2 } from '../../math/vec2.js';
2+
import { math } from '../../math/math.js';
3+
4+
import { AnimBlendTree } from './anim-blend-tree.js';
5+
6+
/**
7+
* @private
8+
* @class
9+
* @name AnimBlendTreeCartesian2D
10+
* @classdesc An AnimBlendTree that calculates its weights using a 2D Cartesian algorithm
11+
* @description Create a new BlendTree1D.
12+
*/
13+
class AnimBlendTreeCartesian2D extends AnimBlendTree {
14+
15+
static _p = new Vec2();
16+
17+
static _pip = new Vec2();
18+
19+
pointDistanceCache(i, j) {
20+
var pointKey = `${i}${j}`;
21+
if (!this._pointCache[pointKey]) {
22+
this._pointCache[pointKey] = this._children[j].point.clone().sub(this._children[i].point);
23+
}
24+
return this._pointCache[pointKey];
25+
}
26+
27+
calculateWeights() {
28+
if (this.updateParameterValues()) return;
29+
var i, j, pi, pipj, minj, result, weightSum;
30+
AnimBlendTreeCartesian2D._p.set(...this._parameterValues);
31+
weightSum = 0.0;
32+
for (i = 0; i < this._children.length; i++) {
33+
pi = this._children[i].point;
34+
minj = Number.MAX_VALUE;
35+
for (j = 0; j < this._children.length; j++) {
36+
if (i === j) continue;
37+
pipj = this.pointDistanceCache(i, j);
38+
AnimBlendTreeCartesian2D._pip = AnimBlendTreeCartesian2D._p.clone().sub(pi);
39+
result = math.clamp(1.0 - (AnimBlendTreeCartesian2D._pip.dot(pipj) / pipj.lengthSq()), 0.0, 1.0);
40+
if (result < minj) minj = result;
41+
}
42+
this._children[i].weight = minj;
43+
weightSum += minj;
44+
}
45+
for (i = 0; i < this._children.length; i++) {
46+
this._children[i].weight = this._children[i]._weight / weightSum;
47+
}
48+
}
49+
}
50+
51+
export { AnimBlendTreeCartesian2D };
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Vec2 } from '../../math/vec2.js';
2+
import { math } from '../../math/math';
3+
4+
import { AnimBlendTree } from './anim-blend-tree.js';
5+
6+
/**
7+
* @private
8+
* @class
9+
* @name AnimBlendTreeDirectional2D
10+
* @classdesc An AnimBlendTree that calculates its weights using a 2D directional algorithm
11+
* @description Create a new BlendTree1D.
12+
*/
13+
class AnimBlendTreeDirectional2D extends AnimBlendTree {
14+
15+
static _p = new Vec2();
16+
17+
static _pip = new Vec2();
18+
19+
pointCache(i, j) {
20+
var pointKey = `${i}${j}`;
21+
if (!this._pointCache[pointKey]) {
22+
this._pointCache[pointKey] = new Vec2(
23+
(this._children[j].pointLength - this._children[i].pointLength) / ((this._children[j].pointLength + this._children[i].pointLength) / 2),
24+
Vec2.angleRad(this._children[i].point, this._children[j].point) * 2.0
25+
);
26+
}
27+
return this._pointCache[pointKey];
28+
}
29+
30+
calculateWeights() {
31+
if (this.updateParameterValues()) return;
32+
var i, j, pi, pipj, minj, result, weightSum;
33+
AnimBlendTreeDirectional2D._p.set(...this._parameterValues);
34+
var pLength = AnimBlendTreeDirectional2D._p.length();
35+
weightSum = 0.0;
36+
for (i = 0; i < this._children.length; i++) {
37+
pi = this._children[i].point;
38+
var piLength = this._children[i].pointLength;
39+
minj = Number.MAX_VALUE;
40+
for (j = 0; j < this._children.length; j++) {
41+
if (i === j) continue;
42+
var pjLength = this._children[j].pointLength;
43+
pipj = this.pointCache(i, j);
44+
AnimBlendTreeDirectional2D._pip.set((pLength - piLength) / ((pjLength + piLength) / 2), Vec2.angleRad(pi, AnimBlendTreeDirectional2D._p) * 2.0);
45+
result = math.clamp(1.0 - Math.abs((AnimBlendTreeDirectional2D._pip.dot(pipj) / pipj.lengthSq())), 0.0, 1.0);
46+
if (result < minj) minj = result;
47+
}
48+
this._children[i].weight = minj;
49+
weightSum += minj;
50+
}
51+
for (i = 0; i < this._children.length; i++) {
52+
this._children[i].weight = this._children[i]._weight / weightSum;
53+
}
54+
}
55+
}
56+
57+
export { AnimBlendTreeDirectional2D };
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { AnimBlendTree } from './anim-blend-tree.js';
2+
3+
/**
4+
* @private
5+
* @class
6+
* @name AnimBlendTreeDirect
7+
* @classdesc An AnimBlendTree that calculates normalised weight values based on the total weight
8+
* @description Create a new BlendTree1D.
9+
*/
10+
class AnimBlendTreeDirect extends AnimBlendTree {
11+
calculateWeights() {
12+
if (this.updateParameterValues()) return;
13+
var i;
14+
var weightSum = 0.0;
15+
for (i = 0; i < this._children.length; i++) {
16+
weightSum += Math.max(this._parameterValues[i], 0.0);
17+
}
18+
for (i = 0; i < this._children.length; i++) {
19+
this._children[i].weight = Math.max(this._parameterValues[i], 0.0) / weightSum;
20+
}
21+
}
22+
}
23+
24+
export { AnimBlendTreeDirect };

0 commit comments

Comments
 (0)