File size: 2,679 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
import { LineSegments } from '../objects/LineSegments.js';
import { Matrix4 } from '../math/Matrix4.js';
import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
import { Color } from '../math/Color.js';
import { Vector3 } from '../math/Vector3.js';
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';

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

class SkeletonHelper extends LineSegments {
	constructor(object) {
		const bones = getBoneList(object);

		const geometry = new BufferGeometry();

		const vertices = [];
		const colors = [];

		const color1 = new Color(0, 0, 1);
		const color2 = new Color(0, 1, 0);

		for (let i = 0; i < bones.length; i++) {
			const bone = bones[i];

			if (bone.parent && bone.parent.isBone) {
				vertices.push(0, 0, 0);
				vertices.push(0, 0, 0);
				colors.push(color1.r, color1.g, color1.b);
				colors.push(color2.r, color2.g, color2.b);
			}
		}

		geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
		geometry.setAttribute('color', new Float32BufferAttribute(colors, 3));

		const material = new LineBasicMaterial({ vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true });

		super(geometry, material);

		this.type = 'SkeletonHelper';
		this.isSkeletonHelper = true;

		this.root = object;
		this.bones = bones;

		this.matrix = object.matrixWorld;
		this.matrixAutoUpdate = false;
	}

	updateMatrixWorld(force) {
		const bones = this.bones;

		const geometry = this.geometry;
		const position = geometry.getAttribute('position');

		_matrixWorldInv.copy(this.root.matrixWorld).invert();

		for (let i = 0, j = 0; i < bones.length; i++) {
			const bone = bones[i];

			if (bone.parent && bone.parent.isBone) {
				_boneMatrix.multiplyMatrices(_matrixWorldInv, bone.matrixWorld);
				_vector.setFromMatrixPosition(_boneMatrix);
				position.setXYZ(j, _vector.x, _vector.y, _vector.z);

				_boneMatrix.multiplyMatrices(_matrixWorldInv, bone.parent.matrixWorld);
				_vector.setFromMatrixPosition(_boneMatrix);
				position.setXYZ(j + 1, _vector.x, _vector.y, _vector.z);

				j += 2;
			}
		}

		geometry.getAttribute('position').needsUpdate = true;

		super.updateMatrixWorld(force);
	}
}

function getBoneList(object) {
	const boneList = [];

	if (object && object.isBone) {
		boneList.push(object);
	}

	for (let i = 0; i < object.children.length; i++) {
		boneList.push.apply(boneList, getBoneList(object.children[i]));
	}

	return boneList;
}

export { SkeletonHelper };