Przeglądaj źródła

Merge pull request #8949 from reimund/skeleton-viewer-local-axes

SkeletonViewer: Added option to show local rotation axis on each bone.
David Catuhe 5 lat temu
rodzic
commit
7b81ec53df

+ 1 - 0
dist/preview release/what's new.md

@@ -105,6 +105,7 @@
 ### Debug
 - Added new view modes to the `SkeletonViewer` class. ([Pryme8](https://github.com/Pryme8))
 - Added static methods to create debug shaders materials for a mesh with a skeleton. ([Pryme8](https://github.com/Pryme8))
+- Added ability to view local rotation axes of bones using new `displayOptions`: `showLocalAxes` and `localAxesSize` ([reimund](https://github.com/reimund))
 
 ### Sprites
 

+ 6 - 0
src/Debug/ISkeletonViewer.ts

@@ -42,6 +42,12 @@ export interface ISkeletonViewerDisplayOptions{
 
    /** Ratio for the Sphere Size */
    sphereFactor? : number;
+
+   /** Whether to show local axes or not  */
+   showLocalAxes? : boolean;
+
+   /** Length of each local axis */
+   localAxesSize? : number;
 }
 
 /**

+ 96 - 13
src/Debug/skeletonViewer.ts

@@ -1,5 +1,5 @@
 import { Vector3, Matrix, TmpVectors } from "../Maths/math.vector";
-import { Color3 } from '../Maths/math.color';
+import { Color3, Color4 } from '../Maths/math.color';
 import { Scene } from "../scene";
 import { Nullable } from "../types";
 import { Bone } from "../Bones/bone";
@@ -300,6 +300,9 @@ export class SkeletonViewer {
     /** The SkeletonViewers Mesh. */
     private _debugMesh: Nullable<LinesMesh>;
 
+    /** The local axes Meshes. */
+    private _localAxes: Nullable<LinesMesh> = null;
+
     /** If SkeletonViewer is enabled. */
     private _isEnabled = false;
 
@@ -386,6 +389,8 @@ export class SkeletonViewer {
         options.displayOptions.sphereBaseSize = options.displayOptions.sphereBaseSize ?? 0.15;
         options.displayOptions.sphereScaleUnit = options.displayOptions.sphereScaleUnit ?? 2;
         options.displayOptions.sphereFactor = options.displayOptions.sphereFactor ?? 0.865;
+        options.displayOptions.showLocalAxes = options.displayOptions.showLocalAxes ?? false;
+        options.displayOptions.localAxesSize = options.displayOptions.localAxesSize ?? 0.075;
         options.computeBonesUsingShaders = options.computeBonesUsingShaders ?? true;
         options.useAllBones = options.useAllBones ?? true;
 
@@ -447,6 +452,8 @@ export class SkeletonViewer {
                 break;
             }
         }
+
+        this._buildLocalAxes();
     }
 
     /** Gets or sets a boolean indicating if the viewer is enabled */
@@ -553,6 +560,17 @@ export class SkeletonViewer {
         }
     }
 
+    private getAbsoluteRestPose(bone: Nullable<Bone>, matrix: Matrix) {
+        if (bone === null || bone._index === -1) {
+            matrix.copyFrom(Matrix.Identity());
+            return;
+        }
+
+        this.getAbsoluteRestPose(bone.getParent(), matrix);
+        bone.getBindPose().multiplyToRef(matrix, matrix);
+        return;
+    }
+
     /** function to build and bind sphere joint points and spur bone representations. */
     private _buildSpheresAndSpurs(spheresOnly = true): void {
 
@@ -584,16 +602,6 @@ export class SkeletonViewer {
             }
 
             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++) {
@@ -604,7 +612,7 @@ export class SkeletonViewer {
                 }
 
                 let boneAbsoluteRestTransform = new Matrix();
-                getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
+                this.getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
 
                 let anchorPoint = new Vector3();
 
@@ -735,6 +743,75 @@ export class SkeletonViewer {
         }
     }
 
+    private _buildLocalAxes(): void {
+        if (this._localAxes) {
+            this._localAxes.dispose();
+        }
+
+        this._localAxes = null;
+
+        let displayOptions = this.options.displayOptions || {};
+
+        if (!displayOptions.showLocalAxes) {
+            return;
+        }
+
+        const targetScene = this._utilityLayer!.utilityLayerScene;
+        const size = displayOptions.localAxesSize || 0.075;
+        let lines = [];
+        let colors = [];
+        let red = new Color4(1, 0, 0, 1);
+        let green = new Color4(0, 1, 0, 1);
+        let blue = new Color4(0, 0, 1, 1);
+
+        let mwk: number[] = [];
+        let mik: number[] = [];
+        const vertsPerBone = 6;
+
+        for (let i in this.skeleton.bones) {
+            let bone = this.skeleton.bones[i];
+
+            if (bone._index === -1 || (!this._boneIndices.has(bone.getIndex()) && !this.options.useAllBones)) {
+                continue;
+            }
+
+            let boneAbsoluteRestTransform = new Matrix();
+            let boneOrigin = new Vector3();
+
+            this.getAbsoluteRestPose(bone, boneAbsoluteRestTransform);
+            boneAbsoluteRestTransform.decompose(undefined, undefined, boneOrigin);
+
+            let m = bone.getBindPose().getRotationMatrix();
+
+            let boneAxisX = Vector3.TransformCoordinates(new Vector3(0 + size, 0, 0), m);
+            let boneAxisY = Vector3.TransformCoordinates(new Vector3(0, 0 + size, 0), m);
+            let boneAxisZ = Vector3.TransformCoordinates(new Vector3(0, 0, 0 + size), m);
+
+            let axisX = [boneOrigin, boneOrigin.add(boneAxisX)];
+            let axisY = [boneOrigin, boneOrigin.add(boneAxisY)];
+            let axisZ = [boneOrigin, boneOrigin.add(boneAxisZ)];
+
+            let linePoints = [axisX, axisY, axisZ];
+            let lineColors = [[red, red], [green, green], [blue, blue]];
+
+            lines.push(...linePoints);
+            colors.push(...lineColors);
+
+            for (let j = 0; j < vertsPerBone; j++) {
+                mwk.push(1, 0, 0, 0);
+                mik.push(bone.getIndex(), 0, 0, 0);
+            }
+        }
+
+        this._localAxes = LinesBuilder.CreateLineSystem('localAxes', { lines: lines, colors: colors, updatable: true }, targetScene);
+        this._localAxes.setVerticesData(VertexBuffer.MatricesWeightsKind, mwk, false);
+        this._localAxes.setVerticesData(VertexBuffer.MatricesIndicesKind, mik, false);
+        this._localAxes.skeleton = this.skeleton;
+        this._localAxes.renderingGroupId = this.renderingGroupId;
+        this._localAxes.parent = this.mesh;
+        this._localAxes.computeBonesUsingShaders = this.options.computeBonesUsingShaders ?? true;
+    }
+
     /** Update the viewer to sync with current skeleton state, only used for the line display. */
     private  _displayLinesUpdate(): void {
         if (!this._utilityLayer) {
@@ -786,7 +863,13 @@ export class SkeletonViewer {
         }
     }
 
-    /** Changes the displayMode of the skeleton viewer
+    /** Sets a display option of the skeleton viewer
+     *
+     * | Option          | Type    | Default | Description |
+     * | --------------- | ------- | ------- | ----------- |
+     * | showLocalAxes   | boolean | false   | Displays local axes on all bones. |
+     * | localAxesSize   | float   | 0.075   | Determines the length of each local axis. |
+     *
      * @param option String of the option name
      * @param value The numerical option value
      */