Source: objects/SkinnedMesh.js

import { OBJECT_TYPE } from '../const.js';
import { Mesh } from './Mesh.js';
import { Matrix4 } from '../math/Matrix4.js';

/**
 * A mesh that has a {@link zen3d.Skeleton} with bones that can then be used to animate the vertices of the geometry.
 * The material must support skinning.
 * @constructor
 * @memberof zen3d
 * @extends zen3d.Mesh
 */
function SkinnedMesh(geometry, material) {
	Mesh.call(this, geometry, material);

	this.type = OBJECT_TYPE.SKINNED_MESH;

	/**
     * Skeleton created from the bones of the Geometry.
     * @member {zen3d.Skeleton}
     */
	this.skeleton = undefined;

	/**
     * Either "attached" or "detached".
     * "attached" uses the {@link zen3d.SkinnedMesh#worldMatrix} property for the base transform matrix of the bones.
     * "detached" uses the {@link zen3d.SkinnedMesh#bindMatrix}.
     * @member {string}
     * @default "attached"
     */
	this.bindMode = 'attached';

	/**
     * The base matrix that is used for the bound bone transforms.
     * @member {zen3d.Matrix4}
     */
	this.bindMatrix = new Matrix4();

	/**
     * The base matrix that is used for resetting the bound bone transforms.
     * @member {zen3d.Matrix4}
     */
	this.bindMatrixInverse = new Matrix4();
}

SkinnedMesh.prototype = Object.assign(Object.create(Mesh.prototype), /** @lends zen3d.SkinnedMesh.prototype */{

	constructor: SkinnedMesh,

	/**
     * Bind a skeleton to the skinned mesh.
     * The bindMatrix gets saved to .bindMatrix property and the .bindMatrixInverse gets calculated.
     * @param {zen3d.Skeleton} skeleton - Skeleton created from a Bones tree.
     * @param {zen3d.Matrix4} [bindMatrix=] - Matrix4 that represents the base transform of the skeleton.
     */
	bind: function (skeleton, bindMatrix) {
		this.skeleton = skeleton;

		if (bindMatrix === undefined) {
			this.updateMatrix();

			bindMatrix = this.worldMatrix;
		}

		this.bindMatrix.copy(bindMatrix);
		this.bindMatrixInverse.getInverse(bindMatrix);
	},

	updateMatrix: function(force) {
		Mesh.prototype.updateMatrix.call(this, force);

		if (this.bindMode === 'attached') {
			this.bindMatrixInverse.getInverse(this.worldMatrix);
		} else if (this.bindMode === 'detached') {
			this.bindMatrixInverse.getInverse(this.bindMatrix);
		} else {
			console.warn('zen3d.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode);
		}
	},

	clone: function () {
		return new this.constructor(this.geometry, this.material).copy(this);
	}

});

export { SkinnedMesh };