|
@@ -54,6 +54,8 @@ export class SkeletonViewer {
|
|
|
/** The Utility Layer to render the gizmos in. */
|
|
|
private _utilityLayer: Nullable<UtilityLayerRenderer>;
|
|
|
|
|
|
+ private _boneIndices: Set<number>;
|
|
|
+
|
|
|
/** Gets the Scene. */
|
|
|
get scene(): Scene {
|
|
|
return this._scene;
|
|
@@ -137,6 +139,21 @@ export class SkeletonViewer {
|
|
|
options.displayOptions.sphereFactor = options.displayOptions.sphereFactor ?? 0.865;
|
|
|
options.computeBonesUsingShaders = options.computeBonesUsingShaders ?? true;
|
|
|
|
|
|
+ const boneIndices = mesh.getVerticesData(VertexBuffer.MatricesIndicesKind);
|
|
|
+ const boneWeights = mesh.getVerticesData(VertexBuffer.MatricesWeightsKind);
|
|
|
+
|
|
|
+ this._boneIndices = new Set();
|
|
|
+
|
|
|
+ if (boneIndices && boneWeights) {
|
|
|
+ for (let i = 0; i < boneIndices.length; ++i) {
|
|
|
+ const index = boneIndices[i], weight = boneWeights[i];
|
|
|
+
|
|
|
+ if (weight !== 0) {
|
|
|
+ this._boneIndices.add(index);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* Create Utility Layer */
|
|
|
this._utilityLayer = new UtilityLayerRenderer(this._scene, false);
|
|
|
this._utilityLayer.pickUtilitySceneFirst = false;
|
|
@@ -234,17 +251,22 @@ export class SkeletonViewer {
|
|
|
|
|
|
let mesh = this.mesh._effectiveMesh;
|
|
|
var meshPos = mesh.position;
|
|
|
+ let idx = 0;
|
|
|
for (var i = 0; i < len; i++) {
|
|
|
var bone = bones[i];
|
|
|
- var points = this._debugLines[i];
|
|
|
+ var points = this._debugLines[idx];
|
|
|
+ if (bone._index === -1 || !this._boneIndices.has(bone.getIndex())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
if (!points) {
|
|
|
points = [Vector3.Zero(), Vector3.Zero()];
|
|
|
- this._debugLines[i] = points;
|
|
|
+ this._debugLines[idx] = 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);
|
|
|
+ idx++;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -257,7 +279,7 @@ export class SkeletonViewer {
|
|
|
for (var i = len - 1; i >= 0; i--) {
|
|
|
var childBone = bones[i];
|
|
|
var parentBone = childBone.getParent();
|
|
|
- if (!parentBone) {
|
|
|
+ if (!parentBone || !this._boneIndices.has(childBone.getIndex())) {
|
|
|
continue;
|
|
|
}
|
|
|
var points = this._debugLines[boneNum];
|
|
@@ -274,14 +296,14 @@ export class SkeletonViewer {
|
|
|
}
|
|
|
|
|
|
/** function to revert the mesh and scene back to the initial state. */
|
|
|
- private _revert(): void {
|
|
|
+ private _revert(animationState: boolean): void {
|
|
|
if (this.options.pauseAnimations) {
|
|
|
- this.scene.animationsEnabled = true;
|
|
|
+ this.scene.animationsEnabled = animationState;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** function to build and bind sphere joint points and spur bone representations. */
|
|
|
- private _buildSpheresAndSpurs(spheresOnly = true): Promise<void> {
|
|
|
+ private _buildSpheresAndSpurs(spheresOnly = true): void {
|
|
|
|
|
|
if (this._debugMesh) {
|
|
|
this._debugMesh.dispose();
|
|
@@ -292,183 +314,175 @@ export class SkeletonViewer {
|
|
|
this._ready = false;
|
|
|
let scene = this.scene;
|
|
|
let bones: Bone[] = this.skeleton.bones;
|
|
|
- let spheres: Mesh[] = [];
|
|
|
+ let spheres: Array<[Mesh, Bone]> = [];
|
|
|
let spurs: Mesh[] = [];
|
|
|
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- try {
|
|
|
- if (this.options.pauseAnimations) {
|
|
|
- scene.animationsEnabled = false;
|
|
|
- }
|
|
|
+ const animationState = scene.animationsEnabled;
|
|
|
|
|
|
- if (this.options.returnToRest) {
|
|
|
- this.skeleton.returnToRest();
|
|
|
+ try {
|
|
|
+ if (this.options.pauseAnimations) {
|
|
|
+ scene.animationsEnabled = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.options.returnToRest) {
|
|
|
+ this.skeleton.returnToRest();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.autoUpdateBonesMatrices) {
|
|
|
+ this.skeleton.computeAbsoluteTransforms();
|
|
|
+ }
|
|
|
+
|
|
|
+ let longestBoneLength = Number.NEGATIVE_INFINITY;
|
|
|
+ let getAbsoluteRestPose = function(bone: Nullable<Bone>, matrix: Matrix) {
|
|
|
+ if (bone === null || bone._index === -1) {
|
|
|
+ matrix.copyFrom(Matrix.Identity());
|
|
|
+ return;
|
|
|
}
|
|
|
+ getAbsoluteRestPose(bone.getParent(), matrix);
|
|
|
+ bone.getBindPose().multiplyToRef(matrix, matrix);
|
|
|
+ return;
|
|
|
+ };
|
|
|
+
|
|
|
+ let displayOptions = this.options.displayOptions || {};
|
|
|
+
|
|
|
+ for (let i = 0; i < bones.length; i++) {
|
|
|
+ let bone = bones[i];
|
|
|
|
|
|
- if (this.autoUpdateBonesMatrices) {
|
|
|
- this.skeleton.computeAbsoluteTransforms();
|
|
|
+ if (bone._index === -1 || !this._boneIndices.has(bone.getIndex())) {
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- let longestBoneLength = Number.NEGATIVE_INFINITY;
|
|
|
- let getAbsoluteRestPose = function(bone: Nullable<Bone>, matrix: Matrix) {
|
|
|
- if (bone == null) {
|
|
|
- matrix.copyFrom(Matrix.Identity());
|
|
|
- return;
|
|
|
- }
|
|
|
- getAbsoluteRestPose(bone.getParent(), matrix);
|
|
|
- bone.getRestPose().multiplyToRef(matrix, matrix);
|
|
|
- return;
|
|
|
- };
|
|
|
+ let boneAbsoluteRestTransform = new Matrix();
|
|
|
+ getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
|
|
|
+
|
|
|
+ let anchorPoint = new Vector3();
|
|
|
+ boneAbsoluteRestTransform.decompose(undefined, undefined, anchorPoint);
|
|
|
|
|
|
- let displayOptions = this.options.displayOptions || {};
|
|
|
+ bone.children.forEach((bc, i) => {
|
|
|
+ let childAbsoluteRestTransform : Matrix = new Matrix();
|
|
|
+ bc.getRestPose().multiplyToRef(boneAbsoluteRestTransform, childAbsoluteRestTransform);
|
|
|
+ let childPoint = new Vector3();
|
|
|
+ childAbsoluteRestTransform.decompose(undefined, undefined, childPoint);
|
|
|
|
|
|
- for (let i = 0; i < bones.length; i++) {
|
|
|
- let bone: Bone = bones[i];
|
|
|
+ let distanceFromParent = Vector3.Distance(anchorPoint, childPoint);
|
|
|
|
|
|
- if (bone._index === null) {
|
|
|
- bone._index = i;
|
|
|
+ if (distanceFromParent > longestBoneLength) {
|
|
|
+ longestBoneLength = distanceFromParent;
|
|
|
}
|
|
|
- if (bone._index === -1) {
|
|
|
- continue;
|
|
|
+ if (spheresOnly) {
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- let boneAbsoluteRestTransform = new Matrix();
|
|
|
- getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
|
|
|
-
|
|
|
- let anchorPoint = new Vector3();
|
|
|
- boneAbsoluteRestTransform.decompose(undefined, undefined, anchorPoint);
|
|
|
-
|
|
|
- bone.children.forEach((bc, i) => {
|
|
|
- let childAbsoluteRestTransform : Matrix = new Matrix();
|
|
|
- bc.getRestPose().multiplyToRef(boneAbsoluteRestTransform, childAbsoluteRestTransform);
|
|
|
- let childPoint = new Vector3();
|
|
|
- childAbsoluteRestTransform.decompose(undefined, undefined, childPoint);
|
|
|
-
|
|
|
- let distanceFromParent = Vector3.Distance(anchorPoint, childPoint);
|
|
|
-
|
|
|
- if (distanceFromParent > longestBoneLength) {
|
|
|
- longestBoneLength = distanceFromParent;
|
|
|
- }
|
|
|
- if (spheresOnly) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- let dir = childPoint.clone().subtract(anchorPoint.clone());
|
|
|
- let h = dir.length();
|
|
|
- let up = dir.normalize().scale(h);
|
|
|
-
|
|
|
- let midStep = displayOptions.midStep || 0.165;
|
|
|
- let midStepFactor = displayOptions.midStepFactor || 0.215;
|
|
|
-
|
|
|
- let up0 = up.scale(midStep);
|
|
|
-
|
|
|
- let spur = ShapeBuilder.ExtrudeShapeCustom(bc.name + ':spur',
|
|
|
- {
|
|
|
- shape: [
|
|
|
- new Vector3(1, -1, 0),
|
|
|
- new Vector3(1, 1, 0),
|
|
|
- new Vector3(-1, 1, 0),
|
|
|
- new Vector3(-1, -1, 0),
|
|
|
- new Vector3(1, -1, 0)
|
|
|
- ],
|
|
|
- path: [ Vector3.Zero(), up0, up ],
|
|
|
- scaleFunction:
|
|
|
- (i: number) => {
|
|
|
- switch (i){
|
|
|
- case 0:
|
|
|
- case 2:
|
|
|
- return 0;
|
|
|
- case 1:
|
|
|
- return h * midStepFactor;
|
|
|
- }
|
|
|
+ let dir = childPoint.clone().subtract(anchorPoint.clone());
|
|
|
+ let h = dir.length();
|
|
|
+ let up = dir.normalize().scale(h);
|
|
|
+
|
|
|
+ let midStep = displayOptions.midStep || 0.165;
|
|
|
+ let midStepFactor = displayOptions.midStepFactor || 0.215;
|
|
|
+
|
|
|
+ let up0 = up.scale(midStep);
|
|
|
+
|
|
|
+ let spur = ShapeBuilder.ExtrudeShapeCustom(bc.name + ':spur',
|
|
|
+ {
|
|
|
+ shape: [
|
|
|
+ new Vector3(1, -1, 0),
|
|
|
+ new Vector3(1, 1, 0),
|
|
|
+ new Vector3(-1, 1, 0),
|
|
|
+ new Vector3(-1, -1, 0),
|
|
|
+ new Vector3(1, -1, 0)
|
|
|
+ ],
|
|
|
+ path: [ Vector3.Zero(), up0, up ],
|
|
|
+ scaleFunction:
|
|
|
+ (i: number) => {
|
|
|
+ switch (i){
|
|
|
+ case 0:
|
|
|
+ case 2:
|
|
|
return 0;
|
|
|
- },
|
|
|
- sideOrientation: Mesh.DEFAULTSIDE,
|
|
|
- updatable: true
|
|
|
- }, scene);
|
|
|
+ case 1:
|
|
|
+ return h * midStepFactor;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ },
|
|
|
+ sideOrientation: Mesh.DEFAULTSIDE,
|
|
|
+ updatable: false
|
|
|
+ }, scene);
|
|
|
+
|
|
|
+ spur.convertToFlatShadedMesh();
|
|
|
+
|
|
|
+ let numVertices = spur.getTotalVertices();
|
|
|
+ let mwk: number[] = [], mik: number[] = [];
|
|
|
|
|
|
- let ind = spur.getIndices() || [];
|
|
|
- let mwk: number[] = [], mik: number[] = [];
|
|
|
+ for (let i = 0; i < numVertices; i++) {
|
|
|
+ mwk.push(1, 0, 0, 0);
|
|
|
+ mik.push(bone.getIndex(), 0, 0, 0);
|
|
|
+ }
|
|
|
+ spur.position = anchorPoint.clone();
|
|
|
|
|
|
- for (let i = 0; i < ind.length; i++) {
|
|
|
- mwk.push(1, 0, 0, 0);
|
|
|
- mik.push(bone.getIndex(), 0, 0, 0);
|
|
|
- }
|
|
|
- spur.convertToFlatShadedMesh();
|
|
|
- spur.position = anchorPoint.clone();
|
|
|
+ spur.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
|
|
|
+ spur.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
|
|
|
|
|
|
- spur.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
|
|
|
- spur.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
|
|
|
- spurs.push(spur);
|
|
|
+ spurs.push(spur);
|
|
|
+ });
|
|
|
|
|
|
- });
|
|
|
+ let sphereBaseSize = displayOptions.sphereBaseSize || 0.2;
|
|
|
|
|
|
- let sphereBaseSize = displayOptions.sphereBaseSize || 0.2;
|
|
|
+ let sphere = SphereBuilder.CreateSphere(bone.name + ':sphere', {
|
|
|
+ segments: 6,
|
|
|
+ diameter: sphereBaseSize,
|
|
|
+ updatable: false
|
|
|
+ }, scene);
|
|
|
|
|
|
- let sphere = SphereBuilder.CreateSphere(bone.name + ':sphere', {
|
|
|
- segments: 6,
|
|
|
- diameter: sphereBaseSize,
|
|
|
- updatable: true
|
|
|
- }, scene);
|
|
|
+ const numVertices = sphere.getTotalVertices();
|
|
|
|
|
|
- let ind = sphere.getIndices() || [];
|
|
|
- let mwk: number[] = [], mik: number[] = [];
|
|
|
+ let mwk: number[] = [], mik: number[] = [];
|
|
|
|
|
|
- for (let i = 0; i < ind.length; i++) {
|
|
|
- mwk.push(1, 0, 0, 0);
|
|
|
- mik.push(bone.getIndex(), 0, 0, 0);
|
|
|
- }
|
|
|
-
|
|
|
- sphere.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
|
|
|
- sphere.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
|
|
|
- sphere.position = anchorPoint.clone();
|
|
|
- spheres.push(sphere);
|
|
|
+ for (let i = 0; i < numVertices; i++) {
|
|
|
+ mwk.push(1, 0, 0, 0);
|
|
|
+ mik.push(bone.getIndex(), 0, 0, 0);
|
|
|
}
|
|
|
|
|
|
- let skip = 0;
|
|
|
- let sphereScaleUnit = displayOptions.sphereScaleUnit || 2;
|
|
|
- let sphereFactor = displayOptions.sphereFactor || 0.85;
|
|
|
+ sphere.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
|
|
|
+ sphere.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
|
|
|
|
|
|
- for (let i = 0; i < bones.length; i++) {
|
|
|
- let bone: Nullable<Bone> = bones[i];
|
|
|
- if (bone.getIndex() === -1) {
|
|
|
- skip++;
|
|
|
- continue;
|
|
|
- }
|
|
|
- let sphere = spheres[i - skip];
|
|
|
- let scale = 1 / (sphereScaleUnit / longestBoneLength);
|
|
|
+ sphere.position = anchorPoint.clone();
|
|
|
+ spheres.push([sphere, bone]);
|
|
|
+ }
|
|
|
|
|
|
- let _stepsOut = 0;
|
|
|
- let _b: Bone = (bone as Bone) || {};
|
|
|
+ let sphereScaleUnit = displayOptions.sphereScaleUnit || 2;
|
|
|
+ let sphereFactor = displayOptions.sphereFactor || 0.85;
|
|
|
|
|
|
- while ((_b.getParent()) && (_b.getParent() as Bone).getIndex() !== -1) {
|
|
|
- _stepsOut++;
|
|
|
- _b = (_b.getParent() as Bone);
|
|
|
- }
|
|
|
- sphere.scaling.scaleInPlace(scale * Math.pow(sphereFactor, _stepsOut));
|
|
|
- }
|
|
|
+ const meshes = [];
|
|
|
+ for (let i = 0; i < spheres.length; i++) {
|
|
|
+ let [sphere, bone] = spheres[i];
|
|
|
+ let scale = 1 / (sphereScaleUnit / longestBoneLength);
|
|
|
+
|
|
|
+ let _stepsOut = 0;
|
|
|
+ let _b = bone;
|
|
|
|
|
|
- this.debugMesh = Mesh.MergeMeshes(spheres.concat(spurs), true, true);
|
|
|
- if (this.debugMesh) {
|
|
|
- this.debugMesh.renderingGroupId = this.renderingGroupId;
|
|
|
- this.debugMesh.skeleton = this.skeleton;
|
|
|
- this.debugMesh.parent = this.mesh;
|
|
|
- this.debugMesh.computeBonesUsingShaders = this.options.computeBonesUsingShaders ?? true;
|
|
|
+ while ((_b.getParent()) && (_b.getParent() as Bone).getIndex() !== -1) {
|
|
|
+ _stepsOut++;
|
|
|
+ _b = (_b.getParent() as Bone);
|
|
|
}
|
|
|
+ sphere.scaling.scaleInPlace(scale * Math.pow(sphereFactor, _stepsOut));
|
|
|
+ meshes.push(sphere);
|
|
|
+ }
|
|
|
|
|
|
- resolve();
|
|
|
- } catch (err) {
|
|
|
- console.log(err);
|
|
|
- this._revert();
|
|
|
- this.dispose();
|
|
|
+ this.debugMesh = Mesh.MergeMeshes(meshes.concat(spurs), true, true);
|
|
|
+ if (this.debugMesh) {
|
|
|
+ this.debugMesh.renderingGroupId = this.renderingGroupId;
|
|
|
+ this.debugMesh.skeleton = this.skeleton;
|
|
|
+ this.debugMesh.parent = this.mesh;
|
|
|
+ this.debugMesh.computeBonesUsingShaders = this.options.computeBonesUsingShaders ?? true;
|
|
|
+ this.debugMesh.alwaysSelectAsActiveMesh = true;
|
|
|
}
|
|
|
- }).then(() => {
|
|
|
- this._revert();
|
|
|
+
|
|
|
+ this._revert(animationState);
|
|
|
this.ready = true;
|
|
|
- }).catch((err) => {
|
|
|
- console.log(err);
|
|
|
+ } catch (err) {
|
|
|
+ console.error(err);
|
|
|
+ this._revert(animationState);
|
|
|
this.dispose();
|
|
|
- });
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/** Update the viewer to sync with current skeleton state, only used for the line display. */
|
|
@@ -476,7 +490,6 @@ export class SkeletonViewer {
|
|
|
if (!this._utilityLayer) {
|
|
|
return;
|
|
|
}
|
|
|
- console.log("dlup");
|
|
|
|
|
|
if (this.autoUpdateBonesMatrices) {
|
|
|
this.skeleton.computeAbsoluteTransforms();
|
|
@@ -509,7 +522,6 @@ export class SkeletonViewer {
|
|
|
public changeDisplayMode(mode: number): void {
|
|
|
let wasEnabled = (this.isEnabled) ? true : false;
|
|
|
if (this.displayMode !== mode) {
|
|
|
- console.log("Change Display Mode!", mode, wasEnabled);
|
|
|
this.isEnabled = false;
|
|
|
if (this._debugMesh) {
|
|
|
this._debugMesh.dispose();
|
|
@@ -521,7 +533,6 @@ export class SkeletonViewer {
|
|
|
this.update();
|
|
|
this._bindObs();
|
|
|
this.isEnabled = wasEnabled;
|
|
|
- console.log(this._utilityLayer, this._debugMesh);
|
|
|
}
|
|
|
}
|
|
|
|