Browse Source

Initial work..still a remaining issue

David Catuhe 5 years ago
parent
commit
2f895d09cc

+ 1 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animationGroupPropertyGridComponent.tsx

@@ -136,6 +136,7 @@ export class AnimationGroupGridComponent extends React.Component<IAnimationGroup
                     <TextLineComponent label="Animation count" value={animationGroup.targetedAnimations.length.toString()} />
                     <TextLineComponent label="From" value={animationGroup.from.toFixed(2)} />
                     <TextLineComponent label="To" value={animationGroup.to.toFixed(2)} />
+                    <TextLineComponent label="Unique ID" value={animationGroup.uniqueId.toString()} />
                 </LineContainerComponent>
             </div>
         );

+ 15 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/bonePropertyGridComponent.tsx

@@ -23,14 +23,28 @@ export class BonePropertyGridComponent extends React.Component<IBonePropertyGrid
         super(props);
     }
 
+    onTransformNodeLink() {
+        if (!this.props.globalState.onSelectionChangedObservable) {
+            return;
+        }
+
+        const node = this.props.bone.getTransformNode()!;
+        this.props.globalState.onSelectionChangedObservable.notifyObservers(node);
+    }    
+
     render() {
         const bone = this.props.bone;
 
         return (
             <div className="pane">
                 <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
-                    <TextLineComponent label="ID" value={bone.id} />
+                    <TextLineComponent label="Name" value={bone.name} />
+                    <TextLineComponent label="Index" value={bone.getIndex().toString()} />
                     <TextLineComponent label="Unique ID" value={bone.uniqueId.toString()} />
+                    {
+                        bone.getTransformNode() &&
+                        <TextLineComponent label="Linked node" value={bone.getTransformNode()!.name} onLink={() => this.onTransformNodeLink()}/>
+                    }
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="TRANSFORMATIONS">
                     <Vector3LineComponent label="Position" target={bone} propertyName="position" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 13 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/meshPropertyGridComponent.tsx

@@ -218,6 +218,15 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
         this.props.onSelectionChangedObservable.notifyObservers(instanceMesh.sourceMesh);
     }
 
+    onSkeletonLink() {
+        if (!this.props.onSelectionChangedObservable) {
+            return;
+        }
+
+        const mesh = this.props.mesh;
+        this.props.onSelectionChangedObservable.notifyObservers(mesh.skeleton);
+    }
+
     convertPhysicsTypeToString(): string {
         const mesh = this.props.mesh;
         switch (mesh.physicsImpostor!.type) {
@@ -288,7 +297,10 @@ export class MeshPropertyGridComponent extends React.Component<IMeshPropertyGrid
                     <TextLineComponent label="Vertices" value={mesh.getTotalVertices().toString()} />
                     <TextLineComponent label="Faces" value={(mesh.getTotalIndices() / 3).toFixed(0)} />
                     <TextLineComponent label="Sub-meshes" value={mesh.subMeshes ? mesh.subMeshes.length.toString() : "0"} />
-                    <TextLineComponent label="Has skeleton" value={mesh.skeleton ? "Yes" : "No"} />
+                    {
+                        mesh.skeleton &&
+                        <TextLineComponent label="Skeleton" value={mesh.skeleton.name} onLink={() => this.onSkeletonLink()}/>
+                    }
                     <CheckBoxLineComponent label="Is enabled" isSelected={() => mesh.isEnabled()} onSelect={(value) => mesh.setEnabled(value)} />
                     <CheckBoxLineComponent label="Is pickable" target={mesh} propertyName="isPickable" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     {

+ 1 - 1
inspector/src/components/actionTabs/tabs/propertyGrids/meshes/skeletonPropertyGridComponent.tsx

@@ -98,7 +98,7 @@ export class SkeletonPropertyGridComponent extends React.Component<ISkeletonProp
             <div className="pane">
                 <CustomPropertyGridComponent globalState={this.props.globalState} target={skeleton}
                     lockObject={this.props.lockObject}
-                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />                    
                 <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
                     <TextLineComponent label="ID" value={skeleton.id} />
                     <TextLineComponent label="Bone count" value={skeleton.bones.length.toString()} />

+ 8 - 0
src/Bones/bone.ts

@@ -141,6 +141,14 @@ export class Bone extends Node {
         return this.children;
     }
 
+    /** 
+     * Gets the node index in matrix array generated for rendering
+     * @returns the node index
+     */
+    public getIndex(): number {
+        return this._index === null ? this.getSkeleton().bones.indexOf(this) : this._index;
+    }
+
     /**
      * Sets the parent bone
      * @param parent defines the parent (can be null if the bone is the root)

+ 8 - 1
src/Bones/skeleton.ts

@@ -547,11 +547,13 @@ export class Skeleton implements IAnimatable {
      * @param id defines the id of the new skeleton
      * @returns the new skeleton
      */
-    public clone(name: string, id: string): Skeleton {
+    public clone(name: string, id?: string): Skeleton {
         var result = new Skeleton(name, id || name, this._scene);
 
         result.needInitialSkinMatrix = this.needInitialSkinMatrix;
 
+        result.overrideMesh = this.overrideMesh;
+
         for (var index = 0; index < this.bones.length; index++) {
             var source = this.bones[index];
             var parentBone = null;
@@ -563,6 +565,11 @@ export class Skeleton implements IAnimatable {
             }
 
             var bone = new Bone(source.name, result, parentBone, source.getBaseMatrix().clone(), source.getRestPose().clone());
+
+            if (source._linkedTransformNode) {
+                bone.linkTransformNode(source._linkedTransformNode);
+            }
+
             DeepCopier.DeepCopy(source.animations, bone.animations);
         }
 

+ 5 - 0
src/Loading/sceneLoader.ts

@@ -891,6 +891,11 @@ export class SceneLoader {
 
         var errorHandler = (message: Nullable<string>, exception?: any) => {
             let errorMessage = "Unable to load assets from " + fileInfo.url + (message ? ": " + message : "");
+
+            if (exception && exception.message) {
+                errorMessage += ` (${exception.message})`;
+            }
+
             if (onError) {
                 onError(scene, errorMessage, exception);
             } else {

+ 13 - 4
src/Meshes/mesh.ts

@@ -396,7 +396,7 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
                 "source", "metadata", "hasLODLevels", "geometry", "isBlocked", "areNormalsFrozen",
                 "onBeforeDrawObservable", "onBeforeRenderObservable", "onAfterRenderObservable", "onBeforeDraw",
                 "onAfterWorldMatrixUpdateObservable", "onCollideObservable", "onCollisionPositionChangeObservable", "onRebuildObservable",
-                "onDisposeObservable", "lightSources"
+                "onDisposeObservable", "lightSources", "morphTargetManager"
             ],
                 ["_poseMatrix"]);
 
@@ -465,6 +465,11 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
                 }
             }
 
+            // Morphs
+            if (source.morphTargetManager) {
+                this.morphTargetManager = source.morphTargetManager;
+            }
+
             // Physics clone
             if (scene.getPhysicsEngine) {
                 var physicsEngine = scene.getPhysicsEngine();
@@ -497,8 +502,8 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
     }
 
     // Methods
-    public instantiateHierarchy(newParent: Nullable<TransformNode> = null): Nullable<TransformNode> {
-        let instance = this.getTotalVertices() > 0 ? this.createInstance("instance of " + (this.name || this.id)) :  this.clone("Clone of " +  (this.name || this.id), newParent || this.parent, true);
+    public instantiateHierarchy(newParent: Nullable<TransformNode> = null, options?: { doNotInstantiate: boolean}, onNewNodeCreated?: (source: TransformNode, clone: TransformNode) => void): Nullable<TransformNode> {
+        let instance = (this.getTotalVertices() > 0 && (!options || !options.doNotInstantiate)) ? this.createInstance("instance of " + (this.name || this.id)) :  this.clone("Clone of " +  (this.name || this.id), newParent || this.parent, true);
 
         if (instance) {
             instance.parent = newParent || this.parent;
@@ -509,10 +514,14 @@ export class Mesh extends AbstractMesh implements IGetSetVerticesData {
             } else {
                 instance.rotation = this.rotation.clone();
             }
+
+            if (onNewNodeCreated) {
+                onNewNodeCreated(this, instance);
+            }
         }
 
         for (var child of this.getChildTransformNodes(true)) {
-            child.instantiateHierarchy(instance);
+            child.instantiateHierarchy(instance, options, onNewNodeCreated);
         }
 
         return instance;

+ 10 - 2
src/Meshes/transformNode.ts

@@ -423,13 +423,21 @@ export class TransformNode extends Node {
     /**
      * Instantiate (when possible) or clone that node with its hierarchy
      * @param newParent defines the new parent to use for the instance (or clone)
+     * @param options defines options to configure how copy is done
+     * @param onNewNodeCreated defines an option callback to call when a clone or an instance is created
      * @returns an instance (or a clone) of the current node with its hiearchy
      */
-    public instantiateHierarchy(newParent: Nullable<TransformNode> = null): Nullable<TransformNode> {
+    public instantiateHierarchy(newParent: Nullable<TransformNode> = null, options?: { doNotInstantiate: boolean}, onNewNodeCreated?: (source: TransformNode, clone: TransformNode) => void): Nullable<TransformNode> {
         let clone = this.clone("Clone of " +  (this.name || this.id), newParent || this.parent, true);
 
+        if (clone) {        
+            if (onNewNodeCreated) {
+                onNewNodeCreated(this, clone);
+            }
+        }
+
         for (var child of this.getChildTransformNodes(true)) {
-            child.instantiateHierarchy(clone);
+            child.instantiateHierarchy(clone, options, onNewNodeCreated);
         }
 
         return clone;

+ 6 - 0
src/Misc/deepCopier.ts

@@ -1,3 +1,5 @@
+import { StringTools } from './stringTools';
+
 var cloneValue = (source: any, destinationObject: any) => {
     if (!source) {
         return null;
@@ -33,6 +35,10 @@ export class DeepCopier {
                 continue;
             }
 
+            if (StringTools.EndsWith(prop, "Observable")) {
+                continue;
+            }
+
             if (doNotCopyList && doNotCopyList.indexOf(prop) !== -1) {
                 continue;
             }

+ 23 - 0
src/Morph/morphTarget.ts

@@ -27,6 +27,7 @@ export class MorphTarget implements IAnimatable {
     private _tangents: Nullable<FloatArray> = null;
     private _uvs: Nullable<FloatArray> = null;
     private _influence: number;
+    private _uniqueId = 0;
 
     /**
      * Observable raised when the influence changes
@@ -89,6 +90,17 @@ export class MorphTarget implements IAnimatable {
         public name: string, influence = 0, scene: Nullable<Scene> = null) {
         this._scene = scene || EngineStore.LastCreatedScene;
         this.influence = influence;
+        
+        if (this._scene) {
+            this._uniqueId = this._scene.getUniqueId();
+        }
+    }
+    
+    /**
+     * Gets the unique ID of this manager
+     */
+    public get uniqueId(): number {
+        return this._uniqueId;
     }
 
     /**
@@ -207,6 +219,17 @@ export class MorphTarget implements IAnimatable {
         return this._uvs;
     }
 
+    public clone(): MorphTarget {
+        let newOne = SerializationHelper.Clone(() => new MorphTarget(this.name, this.influence, this._scene), this);
+
+        newOne._positions = this._positions;
+        newOne._normals = this._normals;
+        newOne._tangents = this._tangents;
+        newOne._uvs = this._uvs;
+
+        return newOne;
+    }
+
     /**
      * Serializes the current target into a Serialization object
      * @returns the serialized object

+ 18 - 0
src/Morph/morphTargetManager.ts

@@ -162,6 +162,24 @@ export class MorphTargetManager {
     }
 
     /**
+     * Clone the current manager
+     * @returns a new MorphTargetManager
+     */
+    public clone(): MorphTargetManager {
+        let copy = new MorphTargetManager(this._scene);
+        
+        for (var target of this._targets) {
+            copy.addTarget(target.clone());
+        }
+
+        copy.enableNormalMorphing = this.enableNormalMorphing;
+        copy.enableTangentMorphing = this.enableTangentMorphing;
+        copy.enableUVMorphing = this.enableUVMorphing;
+
+        return copy;
+    }
+
+    /**
      * Serializes the current manager into a Serialization object
      * @returns the serialized object
      */

+ 119 - 0
src/assetContainer.ts

@@ -1,6 +1,9 @@
 import { AbstractScene } from "./abstractScene";
 import { Scene } from "./scene";
 import { Mesh } from "./Meshes/mesh";
+import { TransformNode } from './Meshes';
+import { Skeleton } from './Bones';
+import { AnimationGroup } from './Animations';
 
 /**
  * Set of assets to keep when moving a scene into an asset container.
@@ -8,6 +11,26 @@ import { Mesh } from "./Meshes/mesh";
 export class KeepAssets extends AbstractScene { }
 
 /**
+ * Class used to store the output of the AssetContainer.instantiateAllMeshesToScene function
+ */
+export class InstantiatedEntries {
+    /**
+     * List of new root nodes (eg. nodes with no parent)
+     */
+    public rootNodes: TransformNode[] = [];
+
+    /**
+     * List of new skeletons
+     */    
+    public skeletons: Skeleton[] = [];
+
+    /**
+     * List of new animation groups
+     */
+    public animationGroups: AnimationGroup[] = [];
+}
+
+/**
  * Container with a set of assets that can be added or removed from a scene.
  */
 export class AssetContainer extends AbstractScene {
@@ -32,6 +55,102 @@ export class AssetContainer extends AbstractScene {
     }
 
     /**
+     * Instantiate or clone all meshes and add the new ones to the scene.
+     * Skeletons and animation groups will all be cloned
+     */
+    public instantiateAllMeshesToScene(): InstantiatedEntries {
+        let convertionMap: {[key: number]: number} = {};
+        let storeMap: {[key: number]: any} = {};
+        let result = new InstantiatedEntries();
+
+        let options = {
+            doNotInstantiate: true
+        }
+
+        let onClone = (source: TransformNode, clone: TransformNode) => {
+            convertionMap[source.uniqueId] = clone.uniqueId;
+            storeMap[clone.uniqueId] = clone;
+
+            if (clone instanceof Mesh) {
+                let clonedMesh = clone as Mesh;
+
+                if (clonedMesh.morphTargetManager) {
+                    let oldMorphTargetManager = (source as Mesh).morphTargetManager!;
+                    clonedMesh.morphTargetManager = oldMorphTargetManager.clone();
+
+                    for (var index = 0; index < oldMorphTargetManager.numTargets; index++) {
+                        let oldTarget = oldMorphTargetManager.getTarget(index);
+                        let newTarget = clonedMesh.morphTargetManager.getTarget(index);
+
+                        convertionMap[oldTarget.uniqueId] = newTarget.uniqueId;                    
+                        storeMap[newTarget.uniqueId] = newTarget;
+                    }
+                }
+            }
+        }
+
+        this.transformNodes.forEach((o) => {
+            if (!o.parent) {
+                let newOne = o.instantiateHierarchy(null, options, (source, clone) => {
+                    onClone(source, clone);
+                });
+
+                if (newOne) {
+                    result.rootNodes.push(newOne);
+                }
+            }
+        });
+
+        this.meshes.forEach((o) => {
+            if (!o.parent) {
+                let newOne = o.instantiateHierarchy(null, options, (source, clone) => {
+                    onClone(source, clone);
+                });
+
+                if (newOne) {
+                    result.rootNodes.push(newOne);
+                }
+            }
+        });
+        
+        this.skeletons.forEach((s) => {
+            let clone = s.clone("clone of " + s.name);
+
+            if (s.overrideMesh) {
+                clone.overrideMesh = storeMap[convertionMap[s.overrideMesh.uniqueId]];
+            }
+
+            for (var m of this.meshes) {
+                if (m.skeleton === s && !m.isAnInstance) {
+                    let copy = storeMap[convertionMap[m.uniqueId]];
+                    (copy as Mesh).skeleton = clone;
+
+                    // Check if bones are mesh linked
+                    for (var bone of clone.bones) {
+                        if (bone._linkedTransformNode) {
+                            bone._linkedTransformNode = storeMap[convertionMap[bone._linkedTransformNode.uniqueId]];
+                        }
+                    }
+                }
+            }
+
+            result.skeletons.push(clone);
+        });
+        
+        this.animationGroups.forEach((o) => {
+            let clone = o.clone(o.name, oldTarget => {
+                let newTarget = storeMap[convertionMap[oldTarget.uniqueId]];
+
+                return newTarget || oldTarget;
+            });
+
+            result.animationGroups.push(clone);
+        });
+
+        return result;
+    }
+
+    /**
      * Adds all the assets from the container to the scene.
      */
     public addAllToScene() {