Browse Source

Merge pull request #7765 from jbousquie/fix.SPS.PickAndMultimaterial

Fix.sps.pick and multimaterial
mergify[bot] 5 years ago
parent
commit
6112642137

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

@@ -35,9 +35,11 @@
 ## Bugs
 
 - Fix infinite loop in `GlowLayer.unReferenceMeshFromUsingItsOwnMaterial` ([Popov72](https://github.com/Popov72)
+- Fix picking issue in the Solid Particle System when MultiMaterial is enabled ([jerome](https://github.com/jbousquie))
 - `QuadraticErrorSimplification` was not exported ([RaananW](https://github.com/Raananw)
 - Fix NME Frames bug where collapsing and moving a frame removed the nodes inside ([Kyle Belfort](https://github.com/belfortk)
 - Fix moving / disappearing controls when freezing/unfreezing the ScrollViewer ([Popov72](https://github.com/Popov72)
 - Fix: when using instances, master mesh (if displayed) does not have correct instance buffer values ([Popov72](https://github.com/Popov72)
 
+
 ## Breaking changes

+ 10 - 1
src/Particles/solidParticle.ts

@@ -117,6 +117,10 @@ export class SolidParticle {
      */
     public materialIndex: Nullable<number> = null;
     /**
+     * Custom object or properties.
+     */
+    public props: Nullable<any> = null;
+    /**
      * The culling strategy to use to check whether the solid particle must be culled or not when using isInFrustum().
      * The possible values are :
      * - AbstractMesh.CULLINGSTRATEGY_STANDARD
@@ -358,6 +362,10 @@ export class ModelShape {
  */
 export class DepthSortedParticle {
     /**
+     * Particle index
+     */
+    public idx: number = 0;
+    /**
      * Index of the particle in the "indices" array
      */
     public ind: number = 0;
@@ -378,7 +386,8 @@ export class DepthSortedParticle {
      * Creates a new sorted particle
      * @param materialIndex
      */
-    constructor(ind: number, indLength: number, materialIndex: number) {
+    constructor(idx: number, ind: number, indLength: number, materialIndex: number) {
+        this.idx = idx;
         this.ind = ind;
         this.indicesLength = indLength;
         this.materialIndex = materialIndex;

+ 69 - 2
src/Particles/solidParticleSystem.ts

@@ -15,6 +15,7 @@ import { SubMesh } from '../Meshes/subMesh';
 import { Material } from '../Materials/material';
 import { StandardMaterial } from '../Materials/standardMaterial';
 import { MultiMaterial } from '../Materials/multiMaterial';
+import { PickingInfo } from '../Collisions/pickingInfo';
 
 /**
  * The SPS is a single updatable mesh. The solid particles are simply separate parts or faces fo this big mesh.
@@ -66,10 +67,25 @@ export class SolidParticleSystem implements IDisposable {
      * Each element of this array is an object `{idx: int, faceId: int}`.
      * `idx` is the picked particle index in the `SPS.particles` array
      * `faceId` is the picked face index counted within this particle.
+     * This array is the first element of the pickedBySubMesh array : sps.pickBySubMesh[0].
+     * It's not pertinent to use it when using a SPS with the support for MultiMaterial enabled.
+     * Use the method SPS.pickedParticle(pickingInfo) instead.
      * Please read : http://doc.babylonjs.com/how_to/Solid_Particle_System#pickable-particles
      */
     public pickedParticles: { idx: number; faceId: number }[];
     /**
+     * This array is populated when the SPS is set as 'pickable'
+     * Each key of this array is a submesh index.
+     * Each element of this array is a second array defined like this :
+     * Each key of this second array is a `faceId` value that you can get from a pickResult object.
+     * Each element of this second array is an object `{idx: int, faceId: int}`.
+     * `idx` is the picked particle index in the `SPS.particles` array
+     * `faceId` is the picked face index counted within this particle.
+     * It's better to use the method SPS.pickedParticle(pickingInfo) rather than using directly this array.
+     * Please read : http://doc.babylonjs.com/how_to/Solid_Particle_System#pickable-particles
+     */
+    public pickedBySubMesh: { idx: number; faceId: number}[][];
+    /**
      * This array is populated when `enableDepthSort` is set to true.
      * Each element of this array is an instance of the class DepthSortedParticle.
      */
@@ -169,7 +185,8 @@ export class SolidParticleSystem implements IDisposable {
             this._updatable = true;
         }
         if (this._pickable) {
-            this.pickedParticles = [];
+            this.pickedBySubMesh = [[]];
+            this.pickedParticles = this.pickedBySubMesh[0];
         }
         if (this._depthSort || this._multimaterialEnabled) {
             this.depthSortedParticles = [];
@@ -430,6 +447,7 @@ export class SolidParticleSystem implements IDisposable {
         copy.uvs.copyFromFloats(0.0, 0.0, 1.0, 1.0);
         copy.color = null;
         copy.translateFromPivot = false;
+        copy.shapeId = 0;
         copy.materialIndex = null;
     }
 
@@ -464,6 +482,7 @@ export class SolidParticleSystem implements IDisposable {
         const storeApart = (options && options.storage) ? true : false;
         copy.idx = idx;
         copy.idxInShape = idxInShape;
+        copy.shapeId = model.shapeID;
         if (this._useModelMaterial) {
             var materialId = model._material!.uniqueId;
             const materialIndexesById = this._materialIndexesById;
@@ -563,7 +582,7 @@ export class SolidParticleSystem implements IDisposable {
 
         if (this._depthSort || this._multimaterialEnabled) {
             var matIndex = (copy.materialIndex !== null) ? copy.materialIndex : 0;
-            this.depthSortedParticles.push(new DepthSortedParticle(ind, meshInd.length, matIndex));
+            this.depthSortedParticles.push(new DepthSortedParticle(idx, ind, meshInd.length, matIndex));
         }
 
         return copy;
@@ -992,6 +1011,7 @@ export class SolidParticleSystem implements IDisposable {
             // camera-particle distance for depth sorting
             if (this._depthSort && this._depthSortParticles) {
                 var dsp = this.depthSortedParticles[p];
+                dsp.idx = particle.idx;
                 dsp.ind = particle._ind;
                 dsp.indicesLength = particle._model._indicesLength;
                 dsp.sqDistance = Vector3.DistanceSquared(particle.position, camInvertedPosition);
@@ -1291,6 +1311,29 @@ export class SolidParticleSystem implements IDisposable {
         (<any>this._uvs32) = null;
         (<any>this._colors32) = null;
         (<any>this.pickedParticles) = null;
+        (<any>this.pickedBySubMesh) = null;
+        (<any>this._materials) = null;
+        (<any>this._materialIndexes) = null;
+        (<any>this._indicesByMaterial) = null;
+        (<any>this._idxOfId) = null;
+    }
+    /** Returns an object {idx: numbern faceId: number} for the picked particle from the passed pickingInfo object.
+     * idx is the particle index in the SPS
+     * faceId is the picked face index counted within this particle.
+     * Returns null if the pickInfo can't identify a picked particle.
+     * @param pickingInfo (PickingInfo object)
+     * @returns {idx: number, faceId: number} or null
+     */
+    public pickedParticle(pickingInfo: PickingInfo): Nullable<{idx: number, faceId: number}> {
+        if (pickingInfo.hit) {
+            const subMesh = pickingInfo.subMeshId;
+            const faceId = pickingInfo.faceId;
+            const picked = this.pickedBySubMesh;
+            if (picked[subMesh] && picked[subMesh][faceId]) {
+                return picked[subMesh][faceId];
+            }
+        }
+        return null;
     }
 
     /**
@@ -1367,6 +1410,7 @@ export class SolidParticleSystem implements IDisposable {
                 sortedPart.materialIndex = part.materialIndex;
                 sortedPart.ind = part._ind;
                 sortedPart.indicesLength = part._model._indicesLength;
+                sortedPart.idx = part.idx;
             }
         }
         this._sortParticlesByMaterial();
@@ -1401,9 +1445,16 @@ export class SolidParticleSystem implements IDisposable {
         const length = depthSortedParticles.length;
         const indices32 = this._indices32;
         const indices = this._indices;
+
+        let subMeshIndex = 0;
+        let subMeshFaceId = 0;
         let sid = 0;
         let lastMatIndex = depthSortedParticles[0].materialIndex;
         materialIndexes.push(lastMatIndex);
+        if (this._pickable) {
+            this.pickedBySubMesh = [[]];
+            this.pickedParticles = this.pickedBySubMesh[0];
+        }
         for (let sorted = 0; sorted < length; sorted++) {
             let sortedPart = depthSortedParticles[sorted];
             let lind = sortedPart.indicesLength;
@@ -1412,12 +1463,28 @@ export class SolidParticleSystem implements IDisposable {
                 lastMatIndex = sortedPart.materialIndex;
                 indicesByMaterial.push(sid);
                 materialIndexes.push(lastMatIndex);
+                if (this._pickable) {
+                    subMeshIndex++;
+                    this.pickedBySubMesh[subMeshIndex] = [];
+                    subMeshFaceId = 0;
+                }
             }
+            let faceId = 0;
             for (let i = 0; i < lind; i++) {
                 indices32[sid] = indices[sind + i];
+                if (this._pickable) {
+                    let f = i % 3;
+                    if (f == 0) {
+                        const pickedData = {idx: sortedPart.idx, faceId: faceId};
+                        this.pickedBySubMesh[subMeshIndex][subMeshFaceId] = pickedData;
+                        subMeshFaceId++;
+                        faceId++;
+                    }
+                }
                 sid++;
             }
         }
+
         indicesByMaterial.push(indices32.length);   // add the last number to ease the indices start/count values for subMeshes creation
         if (this._updatable) {
             this.mesh.updateIndices(indices32);