David Catuhe 6 년 전
부모
커밋
55b50c406c
4개의 변경된 파일53개의 추가작업 그리고 23개의 파일을 삭제
  1. 25 14
      src/Culling/ray.ts
  2. 5 2
      src/Meshes/abstractMesh.ts
  3. 9 3
      src/Meshes/subMesh.ts
  4. 14 4
      src/scene.ts

+ 25 - 14
src/Culling/ray.ts

@@ -535,6 +535,8 @@ export class Ray {
 
 // Picking
 
+export type TrianglePickingPredicate = (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean;
+
 declare module "../scene" {
     export interface Scene {
         /** @hidden */
@@ -547,10 +549,10 @@ declare module "../scene" {
         _pickWithRayInverseMatrix: Matrix;
 
         /** @hidden */
-        _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo>;
+        _internalPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo>;
 
         /** @hidden */
-        _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]>;
+        _internalMultiPick(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]>;
 
     }
 }
@@ -619,7 +621,9 @@ Scene.prototype.createPickingRayInCameraSpaceToRef = function(x: number, y: numb
     return this;
 };
 
-Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo> {
+Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean, 
+    fastCheck?: boolean,
+    trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
     if (!PickingInfo) {
         return null;
     }
@@ -640,7 +644,7 @@ Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, pr
         var world = mesh.getWorldMatrix();
         var ray = rayFunction(world);
 
-        var result = mesh.intersects(ray, fastCheck);
+        var result = mesh.intersects(ray, fastCheck, trianglePredicate);
         if (!result || !result.hit) {
             continue;
         }
@@ -659,7 +663,9 @@ Scene.prototype._internalPick = function(rayFunction: (world: Matrix) => Ray, pr
     return pickingInfo || new PickingInfo();
 };
 
-Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ray, predicate?: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]> {
+Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ray, 
+        predicate?: (mesh: AbstractMesh) => boolean,
+        trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
     if (!PickingInfo) {
         return null;
     }
@@ -679,7 +685,7 @@ Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ra
         var world = mesh.getWorldMatrix();
         var ray = rayFunction(world);
 
-        var result = mesh.intersects(ray, false);
+        var result = mesh.intersects(ray, false, trianglePredicate);
         if (!result || !result.hit) {
             continue;
         }
@@ -690,7 +696,9 @@ Scene.prototype._internalMultiPick = function(rayFunction: (world: Matrix) => Ra
     return pickingInfos;
 };
 
-Scene.prototype.pick = function(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo> {
+Scene.prototype.pick = function(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, 
+    fastCheck?: boolean, camera?: Nullable<Camera>,
+    trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
     if (!PickingInfo) {
         return null;
     }
@@ -701,14 +709,15 @@ Scene.prototype.pick = function(x: number, y: number, predicate?: (mesh: Abstrac
 
         this.createPickingRayToRef(x, y, world, this._tempPickingRay, camera || null);
         return this._tempPickingRay;
-    }, predicate, fastCheck);
+    }, predicate, fastCheck, trianglePredicate);
     if (result) {
         result.ray = this.createPickingRay(x, y, Matrix.Identity(), camera || null);
     }
     return result;
 };
 
-Scene.prototype.pickWithRay = function(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo> {
+Scene.prototype.pickWithRay = function(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, 
+    fastCheck?: boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
     var result = this._internalPick((world) => {
         if (!this._pickWithRayInverseMatrix) {
             this._pickWithRayInverseMatrix = Matrix.Identity();
@@ -721,18 +730,20 @@ Scene.prototype.pickWithRay = function(ray: Ray, predicate?: (mesh: AbstractMesh
 
         Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
         return this._cachedRayForTransform;
-    }, predicate, fastCheck);
+    }, predicate, fastCheck, trianglePredicate);
     if (result) {
         result.ray = ray;
     }
     return result;
 };
 
-Scene.prototype.multiPick = function(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
-    return this._internalMultiPick((world) => this.createPickingRay(x, y, world, camera || null), predicate);
+Scene.prototype.multiPick = function(x: number, y: number, 
+    predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
+    return this._internalMultiPick((world) => this.createPickingRay(x, y, world, camera || null), predicate, trianglePredicate);
 };
 
-Scene.prototype.multiPickWithRay = function(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]> {
+Scene.prototype.multiPickWithRay = function(ray: Ray, 
+    predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
     return this._internalMultiPick((world) => {
         if (!this._pickWithRayInverseMatrix) {
             this._pickWithRayInverseMatrix = Matrix.Identity();
@@ -745,7 +756,7 @@ Scene.prototype.multiPickWithRay = function(ray: Ray, predicate: (mesh: Abstract
 
         Ray.TransformToRef(ray, this._pickWithRayInverseMatrix, this._cachedRayForTransform);
         return this._cachedRayForTransform;
-    }, predicate);
+    }, predicate, trianglePredicate);
 };
 
 Camera.prototype.getForwardRay = function(length = 100, transform?: Matrix, origin?: Vector3): Ray {

+ 5 - 2
src/Meshes/abstractMesh.ts

@@ -1443,10 +1443,11 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
      * Checks if the passed Ray intersects with the mesh
      * @param ray defines the ray to use
      * @param fastCheck defines if fast mode (but less precise) must be used (false by default)
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns the picking info
      * @see http://doc.babylonjs.com/babylon101/intersect_collisions_-_mesh
      */
-    public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
+    public intersects(ray: Ray, fastCheck?: boolean, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean): PickingInfo {
         var pickingInfo = new PickingInfo();
         const intersectionThreshold = this.getClassName() === "InstancedLinesMesh" || this.getClassName() === "LinesMesh" ? (this as any).intersectionThreshold : 0;
         const boundingInfo = this._boundingInfo;
@@ -1470,7 +1471,9 @@ export class AbstractMesh extends TransformNode implements IDisposable, ICullabl
                 continue;
             }
 
-            var currentIntersectInfo = subMesh.intersects(ray, (<Vector3[]>this._positions), (<IndicesArray>this.getIndices()), fastCheck);
+            var currentIntersectInfo = subMesh.intersects(ray, (<Vector3[]>this._positions), 
+                (<IndicesArray>this.getIndices()), fastCheck,
+                trianglePredicate);
 
             if (currentIntersectInfo) {
                 if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {

+ 9 - 3
src/Meshes/subMesh.ts

@@ -343,7 +343,8 @@ export class SubMesh extends BaseSubMesh implements ICullable {
      * @param fastCheck defines if only bounding info should be used
      * @returns intersection info or null if no intersection
      */
-    public intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo> {
+    public intersects(ray: Ray, positions: Vector3[], indices: IndicesArray, 
+        fastCheck?: boolean, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean): Nullable<IntersectionInfo> {
         const material = this.getMaterial();
         if (!material) {
             return null;
@@ -364,7 +365,7 @@ export class SubMesh extends BaseSubMesh implements ICullable {
             return this._intersectLines(ray, positions, indices, (this._mesh as any).intersectionThreshold, fastCheck);
         }
 
-        return this._intersectTriangles(ray, positions, indices, fastCheck);
+        return this._intersectTriangles(ray, positions, indices, fastCheck, trianglePredicate);
     }
 
     /** @hidden */
@@ -393,7 +394,8 @@ export class SubMesh extends BaseSubMesh implements ICullable {
     }
 
     /** @hidden */
-    private _intersectTriangles(ray: Ray, positions: Vector3[], indices: IndicesArray, fastCheck?: boolean): Nullable<IntersectionInfo> {
+    private _intersectTriangles(ray: Ray, positions: Vector3[], indices: IndicesArray, 
+        fastCheck?: boolean, trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3, ray: Ray) => boolean): Nullable<IntersectionInfo> {
         var intersectInfo: Nullable<IntersectionInfo> = null;
         // Triangles test
         for (var index = this.indexStart; index < this.indexStart + this.indexCount; index += 3) {
@@ -401,6 +403,10 @@ export class SubMesh extends BaseSubMesh implements ICullable {
             var p1 = positions[indices[index + 1]];
             var p2 = positions[indices[index + 2]];
 
+            if (trianglePredicate && !trianglePredicate(p0, p1, p2, ray)) {
+                continue;
+            }
+
             var currentIntersectInfo = ray.intersectsTriangle(p0, p1, p2);
 
             if (currentIntersectInfo) {

+ 14 - 4
src/scene.ts

@@ -47,6 +47,7 @@ import { AbstractActionManager } from './Actions/abstractActionManager';
 import { _DevTools } from './Misc/devTools';
 
 declare type Ray = import("./Culling/ray").Ray;
+declare type TrianglePickingPredicate = import("./Culling/ray").TrianglePickingPredicate;
 declare type Animation = import("./Animations/animation").Animation;
 declare type Animatable = import("./Animations/animatable").Animatable;
 declare type AnimationGroup = import("./Animations/animationGroup").AnimationGroup;
@@ -4750,9 +4751,13 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
      * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null.
      * @param camera to use for computing the picking ray. Can be set to null. In this case, the scene.activeCamera will be used
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns a PickingInfo
      */
-    public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>): Nullable<PickingInfo> {
+    public pick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, 
+        fastCheck?: boolean, camera?: Nullable<Camera>,
+        trianglePredicate?: (p0: Vector3, p1: Vector3, p2: Vector3) => boolean
+        ): Nullable<PickingInfo> {
         // Dummy info if picking as not been imported
         const pi = new PickingInfo();
         pi._pickingUnavailable = true;
@@ -4763,9 +4768,11 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param ray The ray to use to pick meshes
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must have isPickable set to true
      * @param fastCheck Launch a fast check only using the bounding boxes. Can be set to null
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns a PickingInfo
      */
-    public pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean): Nullable<PickingInfo> {
+    public pickWithRay(ray: Ray, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean,
+        trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
         throw _DevTools.WarnImport("Ray");
     }
 
@@ -4775,9 +4782,11 @@ export class Scene extends AbstractScene implements IAnimatable {
      * @param y Y position on screen
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with 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
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns an array of PickingInfo
      */
-    public multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera): Nullable<PickingInfo[]> {
+    public multiPick(x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, camera?: Camera,
+        trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
         throw _DevTools.WarnImport("Ray");
     }
 
@@ -4785,9 +4794,10 @@ export class Scene extends AbstractScene implements IAnimatable {
      * Launch a ray to try to pick a mesh in the scene
      * @param ray Ray to use
      * @param predicate Predicate function used to determine eligible meshes. Can be set to null. In this case, a mesh must be enabled, visible and with isPickable set to true
+     * @param trianglePredicate defines an optional predicate used to select faces when a mesh intersection is detected
      * @returns an array of PickingInfo
      */
-    public multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean): Nullable<PickingInfo[]> {
+    public multiPickWithRay(ray: Ray, predicate: (mesh: AbstractMesh) => boolean, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo[]> {
         throw _DevTools.WarnImport("Ray");
     }