123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- import { Color3, Vector3, Matrix, Tmp } from "../Maths/math";
- import { Scene } from "../scene";
- import { Nullable } from "../types";
- import { Bone } from "../Bones/bone";
- import { Skeleton } from "../Bones/skeleton";
- import { AbstractMesh } from "../Meshes/abstractMesh";
- import { LinesMesh } from "../Meshes/linesMesh";
- import { LinesBuilder } from "../Meshes/Builders/linesBuilder";
- import { UtilityLayerRenderer } from "../Rendering/utilityLayerRenderer";
- /**
- * Class used to render a debug view of a given skeleton
- * @see http://www.babylonjs-playground.com/#1BZJVJ#8
- */
- export class SkeletonViewer {
- /** Gets or sets the color used to render the skeleton */
- public color: Color3 = Color3.White();
- private _scene: Scene;
- private _debugLines = new Array<Array<Vector3>>();
- private _debugMesh: Nullable<LinesMesh>;
- private _isEnabled = false;
- private _renderFunction: () => void;
- private _utilityLayer: Nullable<UtilityLayerRenderer>;
- /**
- * Returns the mesh used to render the bones
- */
- public get debugMesh(): Nullable<LinesMesh> {
- return this._debugMesh;
- }
- /**
- * Creates a new SkeletonViewer
- * @param skeleton defines the skeleton to render
- * @param mesh defines the mesh attached to the skeleton
- * @param scene defines the hosting scene
- * @param autoUpdateBonesMatrices defines a boolean indicating if bones matrices must be forced to update before rendering (true by default)
- * @param renderingGroupId defines the rendering group id to use with the viewer
- */
- constructor(
- /** defines the skeleton to render */
- public skeleton: Skeleton,
- /** defines the mesh attached to the skeleton */
- public mesh: AbstractMesh,
- scene: Scene,
- /** defines a boolean indicating if bones matrices must be forced to update before rendering (true by default) */
- public autoUpdateBonesMatrices = true,
- /** defines the rendering group id to use with the viewer */
- public renderingGroupId = 1,
- /** defines an optional utility layer to render the helper on */
- ) {
- this._scene = scene;
- this._utilityLayer = new UtilityLayerRenderer(this._scene, false);
- this._utilityLayer.pickUtilitySceneFirst = false;
- this._utilityLayer.utilityLayerScene.autoClearDepthAndStencil = true;
- this.update();
- this._renderFunction = this.update.bind(this);
- }
- /** Gets or sets a boolean indicating if the viewer is enabled */
- public set isEnabled(value: boolean) {
- if (this._isEnabled === value) {
- return;
- }
- this._isEnabled = value;
- if (value) {
- this._scene.registerBeforeRender(this._renderFunction);
- } else {
- this._scene.unregisterBeforeRender(this._renderFunction);
- }
- }
- public get isEnabled(): boolean {
- return this._isEnabled;
- }
- private _getBonePosition(position: Vector3, bone: Bone, meshMat: Matrix, x = 0, y = 0, z = 0): void {
- var tmat = Tmp.Matrix[0];
- var parentBone = bone.getParent();
- tmat.copyFrom(bone.getLocalMatrix());
- if (x !== 0 || y !== 0 || z !== 0) {
- var tmat2 = Tmp.Matrix[1];
- Matrix.IdentityToRef(tmat2);
- tmat2.setTranslationFromFloats(x, y, z);
- tmat2.multiplyToRef(tmat, tmat);
- }
- if (parentBone) {
- tmat.multiplyToRef(parentBone.getAbsoluteTransform(), tmat);
- }
- tmat.multiplyToRef(meshMat, tmat);
- position.x = tmat.m[12];
- position.y = tmat.m[13];
- position.z = tmat.m[14];
- }
- private _getLinesForBonesWithLength(bones: Bone[], meshMat: Matrix): void {
- var len = bones.length;
- var meshPos = this.mesh.position;
- for (var i = 0; i < len; i++) {
- var bone = bones[i];
- var points = this._debugLines[i];
- if (!points) {
- points = [Vector3.Zero(), Vector3.Zero()];
- this._debugLines[i] = points;
- }
- this._getBonePosition(points[0], bone, meshMat);
- this._getBonePosition(points[1], bone, meshMat, 0, bone.length, 0);
- points[0].subtractInPlace(meshPos);
- points[1].subtractInPlace(meshPos);
- }
- }
- private _getLinesForBonesNoLength(bones: Bone[], meshMat: Matrix): void {
- var len = bones.length;
- var boneNum = 0;
- var meshPos = this.mesh.position;
- for (var i = len - 1; i >= 0; i--) {
- var childBone = bones[i];
- var parentBone = childBone.getParent();
- if (!parentBone) {
- continue;
- }
- var points = this._debugLines[boneNum];
- if (!points) {
- points = [Vector3.Zero(), Vector3.Zero()];
- this._debugLines[boneNum] = points;
- }
- childBone.getAbsolutePositionToRef(this.mesh, points[0]);
- parentBone.getAbsolutePositionToRef(this.mesh, points[1]);
- points[0].subtractInPlace(meshPos);
- points[1].subtractInPlace(meshPos);
- boneNum++;
- }
- }
- /** Update the viewer to sync with current skeleton state */
- public update() {
- if (!this._utilityLayer) {
- return;
- }
- if (this.autoUpdateBonesMatrices) {
- this.skeleton.computeAbsoluteTransforms();
- }
- if (this.skeleton.bones[0].length === undefined) {
- this._getLinesForBonesNoLength(this.skeleton.bones, this.mesh.getWorldMatrix());
- } else {
- this._getLinesForBonesWithLength(this.skeleton.bones, this.mesh.getWorldMatrix());
- }
- const targetScene = this._utilityLayer.utilityLayerScene;
- if (!this._debugMesh) {
- this._debugMesh = LinesBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: null }, targetScene);
- this._debugMesh.renderingGroupId = this.renderingGroupId;
- } else {
- LinesBuilder.CreateLineSystem("", { lines: this._debugLines, updatable: true, instance: this._debugMesh }, targetScene);
- }
- this._debugMesh.position.copyFrom(this.mesh.position);
- this._debugMesh.color = this.color;
- }
- /** Release associated resources */
- public dispose() {
- this.isEnabled = false;
- if (this._debugMesh) {
- this.isEnabled = false;
- this._debugMesh.dispose();
- this._debugMesh = null;
- }
- if (this._utilityLayer) {
- this._utilityLayer.dispose();
- this._utilityLayer = null;
- }
- }
- }
|