Ver código fonte

add new gizmos

Trevor Baron 7 anos atrás
pai
commit
cb587e88de

+ 2 - 0
Playground/js/index.js

@@ -458,6 +458,8 @@
 
             } catch (e) {
                 showError(e.message, e);
+                // Also log error in console to help debug playgrounds
+                console.error(e);
             }
         };
         window.addEventListener("resize",

+ 5 - 1
Tools/Gulp/config.json

@@ -1024,7 +1024,11 @@
                 "../../src/Rendering/babylon.utilityLayerRenderer.js",
                 "../../src/Gizmos/babylon.gizmo.js",
                 "../../src/Gizmos/babylon.axisDragGizmo.js",
-                "../../src/Gizmos/babylon.positionGizmo.js"
+                "../../src/Gizmos/babylon.axisScaleGizmo.js",
+                "../../src/Gizmos/babylon.planeRotationGizmo.js",
+                "../../src/Gizmos/babylon.positionGizmo.js",
+                "../../src/Gizmos/babylon.rotationGizmo.js",
+                "../../src/Gizmos/babylon.scaleGizmo.js"
             ],
             "dependUpon": [
                 "shaderMaterial",

+ 8 - 0
src/Behaviors/Mesh/babylon.pointerDragBehavior.ts

@@ -30,6 +30,11 @@ module BABYLON {
          *  Mesh with the position where the drag plane should be placed
          */
         public _dragPlaneParent:Nullable<Mesh>=null;
+
+        /**
+         *  If the drag behavior will react to drag events
+         */
+        public enabled = true;
         
         /**
          * Creates a pointer drag behavior that can be attached to a mesh
@@ -91,6 +96,9 @@ module BABYLON {
             }
 
             this._pointerObserver = this.options.pointerObservableScene!.onPrePointerObservable.add((pointerInfoPre, eventState)=>{
+                if(!this.enabled){
+                    return;
+                }
                 // Check if attached mesh is picked
                 var pickInfo = pointerInfoPre.ray ? this._scene.pickWithRay(pointerInfoPre.ray, pickPredicate) : this._scene.pick(this._scene.pointerX, this._scene.pointerY, pickPredicate);
                 if(pickInfo){

+ 6 - 0
src/Gizmos/babylon.axisDragGizmo.ts

@@ -39,11 +39,17 @@ module BABYLON {
             this._dragBehavior.moveAttached = false;
             this._rootMesh.addBehavior(this._dragBehavior);
             this._dragBehavior.onDragObservable.add((event)=>{
+                if(!this.interactionsEnabled){
+                    return;
+                }
                 if(this.attachedMesh){
                     this.attachedMesh.position.addInPlace(event.delta);
                 }
             })
         }
+        protected _onInteractionsEnabledChanged(value:boolean){
+            this._dragBehavior.enabled = value;
+        }
         /**
          * Disposes of the gizmo
          */

+ 64 - 0
src/Gizmos/babylon.axisScaleGizmo.ts

@@ -0,0 +1,64 @@
+module BABYLON {
+    /**
+     * Single axis scale gizmo
+     */
+    export class AxisScaleGizmo extends Gizmo {
+        private _dragBehavior:PointerDragBehavior;
+        /**
+         * Creates an AxisScaleGizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         * @param dragAxis The axis which the gizmo will be able to scale on
+         * @param color The color of the gizmo
+         */
+        constructor(gizmoLayer:UtilityLayerRenderer, dragAxis:Vector3, color:Color3){
+            super(gizmoLayer);
+
+            // Create Material
+            var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
+            coloredMaterial.disableLighting = true;
+            coloredMaterial.emissiveColor = color;
+
+            // Build mesh on root node
+            var arrowMesh = BABYLON.MeshBuilder.CreateBox("yPosMesh", {size: 1}, gizmoLayer.utilityLayerScene);
+            var arrowTail = BABYLON.MeshBuilder.CreateCylinder("yPosMesh", {diameter:0.03, height: 0.2, tessellation: 96}, gizmoLayer.utilityLayerScene);
+            this._rootMesh.addChild(arrowMesh);
+            this._rootMesh.addChild(arrowTail);
+
+            // Position arrow pointing in its drag axis
+            arrowMesh.scaling.scaleInPlace(0.1);
+            arrowMesh.material = coloredMaterial;
+            arrowMesh.rotation.x = Math.PI/2;
+            arrowMesh.position.z+=0.3;
+            arrowTail.rotation.x = Math.PI/2;
+            arrowTail.material = coloredMaterial;
+            arrowTail.position.z+=0.2;
+            this._rootMesh.lookAt(this._rootMesh.position.subtract(dragAxis));
+
+            // Add drag behavior to handle events when the gizmo is dragged
+            this._dragBehavior = new PointerDragBehavior({dragAxis: dragAxis, pointerObservableScene: gizmoLayer.originalScene});
+            this._dragBehavior.moveAttached = false;
+            this._rootMesh.addBehavior(this._dragBehavior);
+
+            this._dragBehavior.onDragObservable.add((event)=>{
+                if(!this.interactionsEnabled){
+                    return;
+                }
+                if(this.attachedMesh){
+                    this.attachedMesh.scaling.addInPlace(event.delta);
+                }
+            })
+        }
+        
+        protected _onInteractionsEnabledChanged(value:boolean){
+            this._dragBehavior.enabled = value;
+        }
+        
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._dragBehavior.detach();
+            super.dispose();
+        } 
+    }
+}

+ 17 - 1
src/Gizmos/babylon.gizmo.ts

@@ -11,7 +11,23 @@ module BABYLON {
          * Mesh that the gizmo will be attached to. (eg. on a drag gizmo the mesh that will be dragged)
          */
         public attachedMesh:Nullable<AbstractMesh>;
+        protected _interactionsEnabled = true;
+        protected _onInteractionsEnabledChanged(value:boolean){
+        }
+
+        /**
+         * If interactions are enabled with this gizmo. (eg. dragging/rotation)
+         */
+        public set interactionsEnabled(value:boolean){
+            this._interactionsEnabled = value;
+            this._onInteractionsEnabledChanged(value);
+        }
+        public get interactionsEnabled(){
+            return this._interactionsEnabled;
+        }
+
         private _beforeRenderObserver:Nullable<Observer<Scene>>;
+        
         /**
          * Creates a gizmo
          * @param gizmoLayer The utility layer the gizmo will be added to
@@ -20,7 +36,7 @@ module BABYLON {
             this._rootMesh = new BABYLON.Mesh("gizmoRootNode",gizmoLayer.utilityLayerScene);
             this._beforeRenderObserver = this.gizmoLayer.utilityLayerScene.onBeforeRenderObservable.add(()=>{
                 if(this.gizmoLayer.utilityLayerScene.activeCamera && this.attachedMesh){
-                    var dist = this.attachedMesh.position.subtract(this.gizmoLayer.utilityLayerScene.activeCamera.position).length()/5;
+                    var dist = this.attachedMesh.position.subtract(this.gizmoLayer.utilityLayerScene.activeCamera.position).length()/3;
                     this._rootMesh.scaling.set(dist, dist, dist);
                 }
                 if(this.attachedMesh){

+ 95 - 0
src/Gizmos/babylon.planeRotationGizmo.ts

@@ -0,0 +1,95 @@
+module BABYLON {
+    /**
+     * Single plane rotation gizmo
+     */
+    export class PlaneRotationGizmo extends Gizmo {
+        private _dragBehavior:PointerDragBehavior;
+        /**
+         * Creates a PlaneRotationGizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         * @param planeNormal The normal of the plane which the gizmo will be able to rotate on
+         * @param color The color of the gizmo
+         */
+        constructor(gizmoLayer:UtilityLayerRenderer, planeNormal:Vector3, color:Color3){
+            super(gizmoLayer);
+
+            // Create Material
+            var coloredMaterial = new BABYLON.StandardMaterial("", gizmoLayer.utilityLayerScene);
+            coloredMaterial.disableLighting = true;
+            coloredMaterial.emissiveColor = color;
+
+            // Build mesh on root node
+            var rotationMesh = BABYLON.Mesh.CreateTorus("torus", 3, 0.3, 20, gizmoLayer.utilityLayerScene, false);
+            this._rootMesh.addChild(rotationMesh);
+
+            // Position arrow pointing in its drag axis
+            rotationMesh.scaling.scaleInPlace(0.1);
+            rotationMesh.material = coloredMaterial;
+            rotationMesh.rotation.x = Math.PI/2;
+            this._rootMesh.lookAt(this._rootMesh.position.subtract(planeNormal));
+
+            // Add drag behavior to handle events when the gizmo is dragged
+            this._dragBehavior = new PointerDragBehavior({dragPlaneNormal: planeNormal, pointerObservableScene: gizmoLayer.originalScene});
+            this._dragBehavior.moveAttached = false;
+            this._rootMesh.addBehavior(this._dragBehavior);
+
+            var lastDragPosition:Nullable<Vector3> = null;
+
+            this._dragBehavior.onDragStartObservable.add((e)=>{
+                if(!this.interactionsEnabled){
+                    return;
+                }
+                lastDragPosition = e.dragPlanePoint;
+            })
+
+            this._dragBehavior.onDragObservable.add((event)=>{
+                if(!this.interactionsEnabled){
+                    return;
+                }
+                if(this.attachedMesh && lastDragPosition){
+                    if(!this.attachedMesh.rotationQuaternion){
+                        this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
+                    }
+                    // Calc angle over full 360 degree (https://stackoverflow.com/questions/43493711/the-angle-between-two-3d-vectors-with-a-result-range-0-360)
+                    var newVector = event.dragPlanePoint.subtract(this.attachedMesh.position).normalize();
+                    var originalVector = lastDragPosition.subtract(this.attachedMesh.position).normalize();
+                    var cross = Vector3.Cross(newVector,originalVector);
+                    var dot = Vector3.Dot(newVector,originalVector);
+                    var angle = Math.atan2(cross.length(), dot);
+                    var up = planeNormal.clone();
+                    // Flip up vector depending on which side the camera is on
+                    if(gizmoLayer.utilityLayerScene.activeCamera){
+                        var camVec = gizmoLayer.utilityLayerScene.activeCamera.position.subtract(this.attachedMesh.position);
+                        if(Vector3.Dot(camVec, up) > 0){
+                            up.scaleInPlace(-1);
+                        }
+                    }
+                    var halfCircleSide = Vector3.Dot(up, cross) > 0.0;
+                    if (halfCircleSide) angle = -angle;
+                    
+
+                    // Convert angle and axis to quaternion (http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm)
+                    var quaternionCoefficient = Math.sin(angle/2)
+                    var amountToRotate = new BABYLON.Quaternion(up.x*quaternionCoefficient,up.y*quaternionCoefficient,up.z*quaternionCoefficient,Math.cos(angle/2));
+
+                    // Rotate selected mesh quaternion over fixed axis
+                    amountToRotate.multiplyToRef(this.attachedMesh.rotationQuaternion,this.attachedMesh.rotationQuaternion);
+
+                    lastDragPosition = event.dragPlanePoint;
+                }
+            })
+        }
+
+        protected _onInteractionsEnabledChanged(value:boolean){
+            this._dragBehavior.enabled = value;
+        }
+
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._dragBehavior.detach();
+            super.dispose();
+        } 
+    }
+}

+ 6 - 0
src/Gizmos/babylon.positionGizmo.ts

@@ -23,6 +23,12 @@ module BABYLON {
             this._zDrag = new AxisDragGizmo(gizmoLayer, new Vector3(0,0,1), BABYLON.Color3.FromHexString("#0984e3"));
         }
 
+        protected _onInteractionsEnabledChanged(value:boolean){
+            this._xDrag.interactionsEnabled = value
+            this._yDrag.interactionsEnabled = value
+            this._zDrag.interactionsEnabled = value
+        }
+        
         /**
          * Disposes of the gizmo
          */

+ 41 - 0
src/Gizmos/babylon.rotationGizmo.ts

@@ -0,0 +1,41 @@
+module BABYLON {
+    /**
+     * Gizmo that enables rotating a mesh along 3 axis
+     */
+    export class RotationGizmo extends Gizmo {
+        private _xDrag:PlaneRotationGizmo;
+        private _yDrag:PlaneRotationGizmo;
+        private _zDrag:PlaneRotationGizmo;
+
+        public set attachedMesh(mesh:Nullable<AbstractMesh>){
+            this._xDrag.attachedMesh = mesh;
+            this._yDrag.attachedMesh = mesh;
+            this._zDrag.attachedMesh = mesh;
+        }
+        /**
+         * Creates a RotationGizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         */
+        constructor(gizmoLayer:UtilityLayerRenderer){
+            super(gizmoLayer);
+            this._xDrag = new PlaneRotationGizmo(gizmoLayer, new Vector3(1,0,0), BABYLON.Color3.FromHexString("#00b894"));
+            this._yDrag = new PlaneRotationGizmo(gizmoLayer, new Vector3(0,1,0), BABYLON.Color3.FromHexString("#d63031"));
+            this._zDrag = new PlaneRotationGizmo(gizmoLayer, new Vector3(0,0,1), BABYLON.Color3.FromHexString("#0984e3"));
+        }
+
+        protected _onInteractionsEnabledChanged(value:boolean){
+            this._xDrag.interactionsEnabled = value
+            this._yDrag.interactionsEnabled = value
+            this._zDrag.interactionsEnabled = value
+        }
+
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._xDrag.dispose();
+            this._yDrag.dispose();
+            this._zDrag.dispose();
+        }
+    }
+}

+ 41 - 0
src/Gizmos/babylon.scaleGizmo.ts

@@ -0,0 +1,41 @@
+module BABYLON {
+    /**
+     * Gizmo that enables scaling a mesh along 3 axis
+     */
+    export class ScaleGizmo extends Gizmo {
+        private _xDrag:AxisScaleGizmo;
+        private _yDrag:AxisScaleGizmo;
+        private _zDrag:AxisScaleGizmo;
+
+        public set attachedMesh(mesh:Nullable<AbstractMesh>){
+            this._xDrag.attachedMesh = mesh;
+            this._yDrag.attachedMesh = mesh;
+            this._zDrag.attachedMesh = mesh;
+        }
+        /**
+         * Creates a ScaleGizmo
+         * @param gizmoLayer The utility layer the gizmo will be added to
+         */
+        constructor(gizmoLayer:UtilityLayerRenderer){
+            super(gizmoLayer);
+            this._xDrag = new AxisScaleGizmo(gizmoLayer, new Vector3(1,0,0), BABYLON.Color3.FromHexString("#00b894"));
+            this._yDrag = new AxisScaleGizmo(gizmoLayer, new Vector3(0,1,0), BABYLON.Color3.FromHexString("#d63031"));
+            this._zDrag = new AxisScaleGizmo(gizmoLayer, new Vector3(0,0,1), BABYLON.Color3.FromHexString("#0984e3"));
+        }
+
+        protected _onInteractionsEnabledChanged(value:boolean){
+            this._xDrag.interactionsEnabled = value
+            this._yDrag.interactionsEnabled = value
+            this._zDrag.interactionsEnabled = value
+        }
+
+        /**
+         * Disposes of the gizmo
+         */
+        public dispose(){
+            this._xDrag.dispose();
+            this._yDrag.dispose();
+            this._zDrag.dispose();
+        }
+    }
+}