Selaa lähdekoodia

Adding front-face detection

rickfromwork 4 vuotta sitten
vanhempi
commit
e43a589ced
1 muutettua tiedostoa jossa 89 lisäystä ja 52 poistoa
  1. 89 52
      gui/src/3D/controls/touchButton3D.ts

+ 89 - 52
gui/src/3D/controls/touchButton3D.ts

@@ -1,8 +1,10 @@
+import { Nullable } from "babylonjs/types";
 import { Vector3 } from "babylonjs/Maths/math.vector";
 import { Mesh } from "babylonjs/Meshes/mesh";
 import { LinesMesh } from "babylonjs/Meshes/linesMesh";
 import { TransformNode } from "babylonjs/Meshes/transformNode";
 import { Scene } from "babylonjs/scene";
+import { Ray } from "babylonjs/Culling/ray";
 
 import { Button3D } from "./button3D";
 import { Color3 } from 'babylonjs/Maths/math.color';
@@ -26,7 +28,7 @@ export class TouchButton3D extends Button3D {
     /** @hidden */
     protected _buttonState: ButtonState;
     protected _collisionMesh: Mesh;
-    protected _collidableFront: Vector3;
+    protected _collidableFrontDirection: Vector3;
 
     protected _drawDebugData = true;
 
@@ -40,12 +42,43 @@ export class TouchButton3D extends Button3D {
 
         this._buttonState = ButtonState.None;
         this._collisionMesh = collisionMesh;
-        this._collidableFront = collisionMesh.forward;
+        this._collidableFrontDirection = collisionMesh.forward;
+    }
+
+    // Returns whether the collidable is in front of the button,
+    // as determined by this._collidableFrontDirection.
+    private _getTouchPoint(collidable: Vector3, maxDist: number): Nullable<Vector3> {
+        const frontToButton = this._collidableFrontDirection.negate();
+        const collidableToButton = _this._collisionMesh.getAbsolutePosition() - collidable;
+
+        const projectionScalar = collidableToButton.dot(frontToButton);
+        if (projectionScalar <= 0)
+        {
+            // Collidable is behind the button
+            return false;
+        }
+
+        const projection = projectionScalar * frontToButton;
+        const rejection = collidableToButton - projection;
+
+        const rejectionLength = rejection.length();
+
+        // On a circular button, we can just check the rejectionLength
+        // For all other buttons, we should do a proper collision check
+        const ray = new Ray(collidable, frontToButton, maxDist);
+        const pickingInfo = this._collisionMesh.intersects(ray);
+
+        if (pickingInfo.hit && (pickingInfo.pickedMesh == this._collisionMesh))
+        {
+            return pickingInfo.pickedPoint;
+        }
+
+        return null;
     }
 
     public set collidableFront(front: Vector3)
     {
-        this._collidableFront = front;
+        this._collidableFrontDirection = front.normalize();
     }
 
     protected _getTypeName(): string {
@@ -63,7 +96,6 @@ export class TouchButton3D extends Button3D {
                 const distance = _this._collisionMesh.getAbsolutePosition().subtract(indexMesh.getAbsolutePosition()).length();
                 console.log(distance);
 
-                const dummyPosition = Vector3.Zero();
                 const dummyPointerId = 0;
                 const buttonIndex = 0; // Left click
 
@@ -72,56 +104,61 @@ export class TouchButton3D extends Button3D {
                 const hoverDepth = scale * 0.8;
 
                 // A delta to avoid state flickering when on the threshold
-                const flickerDelta = scale * 0.05; 
+                const flickerDelta = scale * 0.05;
 
-                debugColour = Color3.Red();
+                const touchPoint = _getTouchPoint(indexMesh.getAbsolutePosition(), hoverDepth);
 
-                // Update button state and fire events
-                switch(_this._buttonState)
+                if (touchPoint)
                 {
-                    case ButtonState.None:
-                        if (distance < hoverDepth - flickerDelta)
-                        {
-                            console.log("Now hovering");
-                            _this._buttonState = ButtonState.Hover;
-                            _this._onPointerEnter(_this);
-                        }
-
-                        break;
-                    case ButtonState.Hover:
-                        debugColour = Color3.Yellow();
-                        if (distance > hoverDepth + flickerDelta)
-                        {
-                            console.log("Out of range");
-                            _this._buttonState = ButtonState.None;
-                            _this._onPointerOut(_this);
-                        }
-                        else if (distance < touchDepth - flickerDelta)
-                        {
-                            console.log("now pressing");
-                            _this._buttonState = ButtonState.Press;
-                            _this._onPointerDown(_this, dummyPosition, dummyPointerId, buttonIndex);
-                        }
-                        else
-                        {
-                            _this._onPointerMove(_this, dummyPosition);
-                        }
-
-                        break;
-                    case ButtonState.Press:
-                        debugColour = Color3.Green();
-                        if (distance > touchDepth + flickerDelta)
-                        {
-                            console.log("no longer pressing");
-                            _this._buttonState = ButtonState.Hover;
-                            _this._onPointerUp(_this, dummyPosition, dummyPointerId, buttonIndex, false /*notifyClick*/);
-                        }
-                        else
-                        {
-                            _this._onPointerMove(_this, dummyPosition);
-                        }
-
-                        break;
+                    debugColour = Color3.Red();
+
+                    // Update button state and fire events
+                    switch(_this._buttonState)
+                    {
+                        case ButtonState.None:
+                            if (distance < hoverDepth - flickerDelta)
+                            {
+                                console.log("Now hovering");
+                                _this._buttonState = ButtonState.Hover;
+                                _this._onPointerEnter(_this);
+                            }
+
+                            break;
+                        case ButtonState.Hover:
+                            debugColour = Color3.Yellow();
+                            if (distance > hoverDepth + flickerDelta)
+                            {
+                                console.log("Out of range");
+                                _this._buttonState = ButtonState.None;
+                                _this._onPointerOut(_this);
+                            }
+                            else if (distance < touchDepth - flickerDelta)
+                            {
+                                console.log("now pressing");
+                                _this._buttonState = ButtonState.Press;
+                                _this._onPointerDown(_this, touchPoint, dummyPointerId, buttonIndex);
+                            }
+                            else
+                            {
+                                _this._onPointerMove(_this, touchPoint);
+                            }
+
+                            break;
+                        case ButtonState.Press:
+                            debugColour = Color3.Green();
+                            if (distance > touchDepth + flickerDelta)
+                            {
+                                console.log("no longer pressing");
+                                _this._buttonState = ButtonState.Hover;
+                                _this._onPointerUp(_this, touchPoint, dummyPointerId, buttonIndex, false /*notifyClick*/);
+                            }
+                            else
+                            {
+                                _this._onPointerMove(_this, touchPoint);
+                            }
+
+                            break;
+                    }
                 }
 
                 if (_this._drawDebugData)
@@ -136,7 +173,7 @@ export class TouchButton3D extends Button3D {
                     
                     // Draw a line from the button front to the button to the hand
                     debugLineMesh = Mesh.CreateLines("debug_line", [
-                        _this._collisionMesh.getAbsolutePosition().add(_this._collidableFront).scale(scale),
+                        _this._collisionMesh.getAbsolutePosition().add(_this._collidableFrontDirection).scale(scale),
                         _this._collisionMesh.getAbsolutePosition(),
                         indexMesh.getAbsolutePosition()
                     ], scene);