File size: 2,965 Bytes
2b7aae2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { Mesh } from './Mesh.js';
import { Matrix4 } from '../math/Matrix4.js';
import { Vector3 } from '../math/Vector3.js';
import { Vector4 } from '../math/Vector4.js';

const _basePosition = /*@__PURE__*/ new Vector3();

const _skinIndex = /*@__PURE__*/ new Vector4();
const _skinWeight = /*@__PURE__*/ new Vector4();

const _vector = /*@__PURE__*/ new Vector3();
const _matrix = /*@__PURE__*/ new Matrix4();

class SkinnedMesh extends Mesh {
	constructor(geometry, material) {
		super(geometry, material);

		this.type = 'SkinnedMesh';

		this.bindMode = 'attached';
		this.bindMatrix = new Matrix4();
		this.bindMatrixInverse = new Matrix4();
	}

	copy(source) {
		super.copy(source);

		this.bindMode = source.bindMode;
		this.bindMatrix.copy(source.bindMatrix);
		this.bindMatrixInverse.copy(source.bindMatrixInverse);

		this.skeleton = source.skeleton;

		return this;
	}

	bind(skeleton, bindMatrix) {
		this.skeleton = skeleton;

		if (bindMatrix === undefined) {
			this.updateMatrixWorld(true);

			this.skeleton.calculateInverses();

			bindMatrix = this.matrixWorld;
		}

		this.bindMatrix.copy(bindMatrix);
		this.bindMatrixInverse.copy(bindMatrix).invert();
	}

	pose() {
		this.skeleton.pose();
	}

	normalizeSkinWeights() {
		const vector = new Vector4();

		const skinWeight = this.geometry.attributes.skinWeight;

		for (let i = 0, l = skinWeight.count; i < l; i++) {
			vector.x = skinWeight.getX(i);
			vector.y = skinWeight.getY(i);
			vector.z = skinWeight.getZ(i);
			vector.w = skinWeight.getW(i);

			const scale = 1.0 / vector.manhattanLength();

			if (scale !== Infinity) {
				vector.multiplyScalar(scale);
			} else {
				vector.set(1, 0, 0, 0); // do something reasonable
			}

			skinWeight.setXYZW(i, vector.x, vector.y, vector.z, vector.w);
		}
	}

	updateMatrixWorld(force) {
		super.updateMatrixWorld(force);

		if (this.bindMode === 'attached') {
			this.bindMatrixInverse.copy(this.matrixWorld).invert();
		} else if (this.bindMode === 'detached') {
			this.bindMatrixInverse.copy(this.bindMatrix).invert();
		} else {
			console.warn('THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode);
		}
	}

	boneTransform(index, target) {
		const skeleton = this.skeleton;
		const geometry = this.geometry;

		_skinIndex.fromBufferAttribute(geometry.attributes.skinIndex, index);
		_skinWeight.fromBufferAttribute(geometry.attributes.skinWeight, index);

		_basePosition.copy(target).applyMatrix4(this.bindMatrix);

		target.set(0, 0, 0);

		for (let i = 0; i < 4; i++) {
			const weight = _skinWeight.getComponent(i);

			if (weight !== 0) {
				const boneIndex = _skinIndex.getComponent(i);

				_matrix.multiplyMatrices(skeleton.bones[boneIndex].matrixWorld, skeleton.boneInverses[boneIndex]);

				target.addScaledVector(_vector.copy(_basePosition).applyMatrix4(_matrix), weight);
			}
		}

		return target.applyMatrix4(this.bindMatrixInverse);
	}
}

SkinnedMesh.prototype.isSkinnedMesh = true;

export { SkinnedMesh };