فهرست منبع

Merge pull request #6722 from BabylonJSGuide/master

Added multiPickSprites and WithRay
David Catuhe 6 سال پیش
والد
کامیت
edc230a259
3فایلهای تغییر یافته به همراه151 افزوده شده و 3 حذف شده
  1. 1 0
      dist/preview release/what's new.md
  2. 74 3
      src/Sprites/spriteManager.ts
  3. 76 0
      src/Sprites/spriteSceneComponent.ts

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

@@ -14,6 +14,7 @@
 
 ## Updates
 - SpritePackedManager extends SpriteManager so that a sprite sheet with different size sprites can be used ([JohnK](https://github.com/BabylonJSGuide))
+- MultiPickSprite and multiPickSpriteWithRay added to sprites ([JohnK](https://github.com/BabylonJSGuide))
 
 ### General
 - Added support for dual shock gamepads ([Deltakosh](https://github.com/deltakosh/))

+ 74 - 3
src/Sprites/spriteManager.ts

@@ -56,6 +56,15 @@ export interface ISpriteManager extends IDisposable {
      */
     intersects(ray: Ray, camera: Camera, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
 
+        /**
+     * Intersects the sprites with a ray
+     * @param ray defines the ray to intersect with
+     * @param camera defines the current active camera
+     * @param predicate defines a predicate used to select candidate sprites
+     * @returns null if no hit or a PickingInfo array
+     */
+    multiIntersects(ray: Ray, camera: Camera, predicate?: (sprite: Sprite) => boolean): Nullable<PickingInfo[]>;
+
     /**
      * Renders the list of sprites on screen.
      */
@@ -341,8 +350,8 @@ export class SpriteManager implements ISpriteManager {
         var max = Vector3.Zero();
         var distance = Number.MAX_VALUE;
         var currentSprite: Nullable<Sprite> = null;
-        var pickedPoint = Vector3.Zero();
-        var cameraSpacePosition = Vector3.Zero();
+        var pickedPoint = TmpVectors.Vector3[0].copyFromFloats(0, 0, 0);
+        var cameraSpacePosition = TmpVectors.Vector3[1].copyFromFloats(0, 0, 0);
         var cameraView = camera.getViewMatrix();
 
         for (var index = 0; index < count; index++) {
@@ -387,7 +396,7 @@ export class SpriteManager implements ISpriteManager {
             result.distance = distance;
 
             // Get picked point
-            let direction = TmpVectors.Vector3[0];
+            let direction = TmpVectors.Vector3[2];
             direction.copyFrom(ray.direction);
             direction.normalize();
             direction.scaleInPlace(distance);
@@ -402,6 +411,68 @@ export class SpriteManager implements ISpriteManager {
     }
 
     /**
+     * Intersects the sprites with a ray
+     * @param ray defines the ray to intersect with
+     * @param camera defines the current active camera
+     * @param predicate defines a predicate used to select candidate sprites
+     * @returns null if no hit or a PickingInfo array
+     */
+    public multiIntersects(ray: Ray, camera: Camera, predicate?: (sprite: Sprite) => boolean): Nullable<PickingInfo[]> {
+        var count = Math.min(this._capacity, this.sprites.length);
+        var min = Vector3.Zero();
+        var max = Vector3.Zero();
+        var distance: number;
+        var results: Nullable<PickingInfo[]> = [];
+        var pickedPoint = TmpVectors.Vector3[0].copyFromFloats(0, 0, 0);
+        var cameraSpacePosition = TmpVectors.Vector3[1].copyFromFloats(0, 0, 0);
+        var cameraView = camera.getViewMatrix();
+
+        for (var index = 0; index < count; index++) {
+            var sprite = this.sprites[index];
+            if (!sprite) {
+                continue;
+            }
+
+            if (predicate) {
+                if (!predicate(sprite)) {
+                    continue;
+                }
+            } else if (!sprite.isPickable) {
+                continue;
+            }
+
+            Vector3.TransformCoordinatesToRef(sprite.position, cameraView, cameraSpacePosition);
+
+            min.copyFromFloats(cameraSpacePosition.x - sprite.width / 2, cameraSpacePosition.y - sprite.height / 2, cameraSpacePosition.z);
+            max.copyFromFloats(cameraSpacePosition.x + sprite.width / 2, cameraSpacePosition.y + sprite.height / 2, cameraSpacePosition.z);
+
+            if (ray.intersectsBoxMinMax(min, max)) {
+                distance = Vector3.Distance(cameraSpacePosition, ray.origin);
+
+                var result = new PickingInfo();
+                results.push(result);
+
+                cameraView.invertToRef(TmpVectors.Matrix[0]);
+                result.hit = true;
+                result.pickedSprite = sprite;
+                result.distance = distance;
+
+                // Get picked point
+                let direction = TmpVectors.Vector3[2];
+                direction.copyFrom(ray.direction);
+                direction.normalize();
+                direction.scaleInPlace(distance);
+
+                ray.origin.addToRef(direction, pickedPoint);
+                result.pickedPoint = Vector3.TransformCoordinates(pickedPoint, TmpVectors.Matrix[0]);
+            }
+
+        }
+
+        return results;
+    }
+
+    /**
      * Render all child sprites
      */
     public render(): void {

+ 76 - 0
src/Sprites/spriteSceneComponent.ts

@@ -61,6 +61,26 @@ declare module "../scene" {
          */
         pickSpriteWithRay(ray: Ray, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo>;
 
+        /** @hidden */
+        _internalMultiPickSprites(ray: Ray, predicate?: (sprite: Sprite) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+
+        /** Launch a ray to try to pick sprites in the scene
+         * @param x position on screen
+         * @param y position on screen
+         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param camera camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+         * @returns a PickingInfo array
+         */
+        multiPickSprite(x: number, y: number, predicate?: (sprite: Sprite) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+
+        /** Use the given ray to pick sprites in the scene
+         * @param ray The ray (in world space) to use to pick meshes
+         * @param predicate Predicate function used to determine eligible sprites. Can be set to null. In this case, a sprite must have isPickable set to true
+         * @param camera camera to use. Can be set to null. In this case, the scene.activeCamera will be used
+         * @returns a PickingInfo array
+         */
+        multiPickSpriteWithRay(ray: Ray, predicate?: (sprite: Sprite) => boolean, camera?: Camera): Nullable<PickingInfo[]>;
+
         /**
          * Force the sprite under the pointer
          * @param sprite defines the sprite to use
@@ -117,6 +137,39 @@ Scene.prototype._internalPickSprites = function(ray: Ray, predicate?: (sprite: S
     return pickingInfo || new PickingInfo();
 };
 
+Scene.prototype._internalMultiPickSprites = function(ray: Ray, predicate?: (sprite: Sprite) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
+    if (!PickingInfo) {
+        return null;
+    }
+
+    var pickingInfos = new Array<PickingInfo>();
+
+    if (!camera) {
+        if (!this.activeCamera) {
+            return null;
+        }
+        camera = this.activeCamera;
+    }
+
+    if (this.spriteManagers.length > 0) {
+        for (var spriteIndex = 0; spriteIndex < this.spriteManagers.length; spriteIndex++) {
+            var spriteManager = this.spriteManagers[spriteIndex];
+
+            if (!spriteManager.isPickable) {
+                continue;
+            }
+
+            var results = spriteManager.multiIntersects(ray, camera, predicate);
+
+             if (results !== null) {
+                 pickingInfos = pickingInfos.concat(results);
+             }
+        }
+    }
+
+    return pickingInfos;
+};
+
 Scene.prototype.pickSprite = function(x: number, y: number, predicate?: (sprite: Sprite) => boolean, fastCheck?: boolean, camera?: Camera): Nullable<PickingInfo> {
     this.createPickingRayInCameraSpaceToRef(x, y, this._tempSpritePickingRay!, camera);
 
@@ -140,6 +193,29 @@ Scene.prototype.pickSpriteWithRay = function(ray: Ray, predicate?: (sprite: Spri
     return this._internalPickSprites(this._tempSpritePickingRay, predicate, fastCheck, camera);
 };
 
+Scene.prototype.multiPickSprite = function(x: number, y: number, predicate?: (sprite: Sprite) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
+    this.createPickingRayInCameraSpaceToRef(x, y, this._tempSpritePickingRay!, camera);
+
+    return this._internalMultiPickSprites(this._tempSpritePickingRay!, predicate, camera);
+};
+
+Scene.prototype.multiPickSpriteWithRay = function(ray: Ray, predicate?: (sprite: Sprite) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
+    if (!this._tempSpritePickingRay) {
+        return null;
+    }
+
+    if (!camera) {
+        if (!this.activeCamera) {
+            return null;
+        }
+        camera = this.activeCamera;
+    }
+
+    Ray.TransformToRef(ray, camera.getViewMatrix(), this._tempSpritePickingRay);
+
+    return this._internalMultiPickSprites(this._tempSpritePickingRay, predicate, camera);
+};
+
 Scene.prototype.setPointerOverSprite = function(sprite: Nullable<Sprite>): void {
     if (this._pointerOverSprite === sprite) {
         return;