@openhps/core
Version:
Open Hybrid Positioning System - Core component
122 lines (117 loc) • 3.79 kB
JavaScript
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();
/**
* A helper object to assist with visualizing a {@link Skeleton}.
*
* ```js
* const helper = new THREE.SkeletonHelper( skinnedMesh );
* scene.add( helper );
* ```
*
* @augments LineSegments
*/
class SkeletonHelper extends LineSegments {
/**
* Constructs a new hemisphere light helper.
*
* @param {Object3D} object - Usually an instance of {@link SkinnedMesh}. However, any 3D object
* can be used if it represents a hierarchy of bones (see {@link Bone}).
*/
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 flag can be used for type testing.
*
* @type {boolean}
* @readonly
* @default true
*/
this.isSkeletonHelper = true;
this.type = 'SkeletonHelper';
/**
* The object being visualized.
*
* @type {Object3D}
*/
this.root = object;
/**
* he list of bones that the helper visualizes.
*
* @type {Array<Bone>}
*/
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);
}
/**
* Frees the GPU-related resources allocated by this instance. Call this
* method whenever this instance is no longer used in your app.
*/
dispose() {
this.geometry.dispose();
this.material.dispose();
}
}
function getBoneList(object) {
const boneList = [];
if (object.isBone === true) {
boneList.push(object);
}
for (let i = 0; i < object.children.length; i++) {
boneList.push(...getBoneList(object.children[i]));
}
return boneList;
}
export { SkeletonHelper };