Selaa lähdekoodia

use alternate picked point when rotating along drag plane

Trevor Baron 7 vuotta sitten
vanhempi
commit
58c6a1fc08

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

@@ -7,7 +7,7 @@
 - New GUI 3D controls toolset. [Complete doc + demos](http://doc.babylonjs.com/how_to/gui3d) ([Deltakosh](https://github.com/deltakosh))
 - Added [Environment Texture Tools](https://doc.babylonjs.com/how_to/physically_based_rendering#creating-a-compressed-environment-texture) to reduce the size of the usual .DDS file ([sebavan](http://www.github.com/sebavan))
 - New GUI control: the [Grid](http://doc.babylonjs.com/how_to/gui#grid) ([Deltakosh](https://github.com/deltakosh))
-- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, rotation, scale and bounding box ([TrevorDev](https://github.com/TrevorDev))
+- Gizmo and GizmoManager classes used to manipulate meshes in a scene. Gizmo types include: position, scale, rotation and bounding box ([TrevorDev](https://github.com/TrevorDev))
 - Particle system improvements ([Deltakosh](https://github.com/deltakosh))
   - Added a ParticleHelper class to create some pre-configured particle systems in a one-liner method style. [Doc](https://doc.babylonjs.com/How_To/ParticleHelper) ([Deltakosh](https://github.com/deltakosh)) / ([DevChris](https://github.com/yovanoc))
   - Improved CPU particles rendering performance (up to x2 on low end devices)

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

@@ -9,6 +9,14 @@ module BABYLON {
         private _pointerObserver:Nullable<Observer<PointerInfo>>;
         private static _planeScene:Scene;
         /**
+         * The maximum tolerated angle between the drag plane and dragging pointer rays to trigger pointer events. Set to 0 to allow any angle (default: 0)
+         */
+        public maxDragAngle = 0;
+        /**
+         * @ignore
+         */
+        public _useAlternatePickedPointAboveMaxDragAngle = false;
+        /**
          * The id of the pointer that is currently interacting with the behavior (-1 when no pointer is active)
          */
         public currentDraggingPointerID = -1;
@@ -95,6 +103,7 @@ module BABYLON {
         public init() {}
 
         private _tmpVector = new Vector3(0,0,0);
+        private _alternatePickedPoint = new Vector3(0,0,0);
         private _worldDragAxis = new Vector3(0,0,0);
         /**
          * Attaches the drag behavior the passed in mesh
@@ -200,6 +209,35 @@ module BABYLON {
             if(!ray){
                 return null;
             }
+
+            // Calculate angle between plane normal and ray
+            var angle = Math.acos(Vector3.Dot(this._dragPlane.forward, ray.direction));
+            // Correct if ray is casted from oposite side
+            if(angle > Math.PI/2){
+                angle = Math.PI - angle;
+            }
+
+            // If the angle is too perpendicular to the plane pick another point on the plane where it is looking
+            if(this.maxDragAngle > 0 && angle > this.maxDragAngle){
+                if(this._useAlternatePickedPointAboveMaxDragAngle){
+                    // Invert ray direction along the towards object axis
+                    this._tmpVector.copyFrom(ray.direction);
+                    (<Mesh>this._attachedNode).absolutePosition.subtractToRef(ray.origin, this._alternatePickedPoint);
+                    this._alternatePickedPoint.normalize();
+                    this._alternatePickedPoint.scaleInPlace(-2*Vector3.Dot(this._alternatePickedPoint, this._tmpVector));
+                    this._tmpVector.addInPlace(this._alternatePickedPoint);
+                    
+                    // Project resulting vector onto the drag plane and add it to the attached nodes absolute position to get a picked point
+                    var dot = Vector3.Dot(this._dragPlane.forward, this._tmpVector);
+                    this._dragPlane.forward.scaleToRef(-dot, this._alternatePickedPoint);
+                    this._alternatePickedPoint.addInPlace(this._tmpVector);
+                    this._alternatePickedPoint.addInPlace((<Mesh>this._attachedNode).absolutePosition);
+                    return this._alternatePickedPoint
+                }else{
+                    return null;
+                }
+            }
+
             var pickResult = PointerDragBehavior._planeScene.pickWithRay(ray, (m)=>{return m == this._dragPlane})
             if (pickResult && pickResult.hit && pickResult.pickedMesh && pickResult.pickedPoint) {
                 return pickResult.pickedPoint;

+ 6 - 4
src/Gizmos/babylon.planeRotationGizmo.ts

@@ -52,13 +52,15 @@ module BABYLON {
             // Add drag behavior to handle events when the gizmo is dragged
             this.dragBehavior = new PointerDragBehavior({dragPlaneNormal: planeNormal});
             this.dragBehavior.moveAttached = false;
+            this.dragBehavior.maxDragAngle =  Math.PI*4/10;
+            this.dragBehavior._useAlternatePickedPointAboveMaxDragAngle = true;
             this._rootMesh.addBehavior(this.dragBehavior);
 
-            var lastDragPosition:Nullable<Vector3> = null;
+            var lastDragPosition = new Vector3();
 
             this.dragBehavior.onDragStartObservable.add((e)=>{
                 if(this.attachedMesh){
-                    lastDragPosition = e.dragPlanePoint;
+                    lastDragPosition.copyFrom(e.dragPlanePoint);
                 }
             })
 
@@ -69,7 +71,7 @@ module BABYLON {
             var tmpSnapEvent = {snapDistance: 0};
             var currentSnapDragDistance = 0;
             this.dragBehavior.onDragObservable.add((event)=>{
-                if(this.attachedMesh && lastDragPosition){
+                if(this.attachedMesh){
                     if(!this.attachedMesh.rotationQuaternion){
                         this.attachedMesh.rotationQuaternion = new BABYLON.Quaternion();
                     }
@@ -116,7 +118,7 @@ module BABYLON {
                      // Rotate selected mesh quaternion over fixed axis
                      this.attachedMesh.rotationQuaternion.multiplyToRef(amountToRotate,this.attachedMesh.rotationQuaternion);
 
-                    lastDragPosition = event.dragPlanePoint;
+                    lastDragPosition.copyFrom(event.dragPlanePoint);
                     if(snapped){
                         tmpSnapEvent.snapDistance = angle;
                         this.onSnapObservable.notifyObservers(tmpSnapEvent);