Explorar o código

particle external storage

Jérôme Bousquié %!s(int64=5) %!d(string=hai) anos
pai
achega
92f3ca209f
Modificáronse 2 ficheiros con 84 adicións e 27 borrados
  1. 8 2
      src/Particles/solidParticle.ts
  2. 76 25
      src/Particles/solidParticleSystem.ts

+ 8 - 2
src/Particles/solidParticle.ts

@@ -16,6 +16,10 @@ export class SolidParticle {
      */
     public idx: number = 0;
     /**
+     * particle identifier
+     */
+    public id: number = 0;
+    /**
      * The color of the particle
      */
     public color: Nullable<Color4> = new Color4(1.0, 1.0, 1.0, 1.0);
@@ -127,7 +131,8 @@ export class SolidParticle {
     /**
      * Creates a Solid Particle object.
      * Don't create particles manually, use instead the Solid Particle System internal tools like _addParticle()
-     * @param particleIndex (integer) is the particle index in the Solid Particle System pool. It's also the particle identifier.
+     * @param particleIndex (integer) is the particle index in the Solid Particle System pool. 
+     * @param particleId (integer) is the particle identifier. Unless some particles are removed from the SPS, it's the same value than the particle idx.
      * @param positionIndex (integer) is the starting index of the particle vertices in the SPS "positions" array.
      * @param indiceIndex (integer) is the starting index of the particle indices in the SPS "indices" array.
      * @param model (ModelShape) is a reference to the model shape on what the particle is designed.
@@ -136,8 +141,9 @@ export class SolidParticle {
      * @param sps defines the sps it is associated to
      * @param modelBoundingInfo is the reference to the model BoundingInfo used for intersection computations.
      */
-    constructor(particleIndex: number, positionIndex: number, indiceIndex: number, model: Nullable<ModelShape>, shapeId: number, idxInShape: number, sps: SolidParticleSystem, modelBoundingInfo: Nullable<BoundingInfo> = null) {
+    constructor(particleIndex: number, particleId: number, positionIndex: number, indiceIndex: number, model: Nullable<ModelShape>, shapeId: number, idxInShape: number, sps: SolidParticleSystem, modelBoundingInfo: Nullable<BoundingInfo> = null) {
         this.idx = particleIndex;
+        this.id = particleId;
         this._pos = positionIndex;
         this._ind = indiceIndex;
         this._model = <ModelShape>model;

+ 76 - 25
src/Particles/solidParticleSystem.ts

@@ -104,7 +104,7 @@ export class SolidParticleSystem implements IDisposable {
     private _depthSort: boolean = false;
     private _expandable: boolean = false;
     private _shapeCounter: number = 0;
-    private _copy: SolidParticle = new SolidParticle(0, 0, 0, null, 0, 0, this);
+    private _copy: SolidParticle = new SolidParticle(0, 0, 0, 0, null, 0, 0, this);
     private _color: Color4 = new Color4(0, 0, 0, 0);
     private _computeParticleColor: boolean = true;
     private _computeParticleTexture: boolean = true;
@@ -117,7 +117,8 @@ export class SolidParticleSystem implements IDisposable {
     private _particlesIntersect: boolean = false;
     private _needs32Bits: boolean = false;
     private _isNotBuilt: boolean = true;
-    private _lastParticleIdx: number = 0;
+    private _lastParticleId: number = 0;
+    private _idxOfId: number[] = [];            // array : key = particle.id / value = particle.idx
 
     /**
      * Creates a SPS (Solid Particle System) object.
@@ -227,9 +228,10 @@ export class SolidParticleSystem implements IDisposable {
      * @param options {facetNb} (optional integer, default 1) is the number of mesh facets per particle, this parameter is overriden by the parameter `number` if any
      * {delta} (optional integer, default 0) is the random extra number of facets per particle , each particle will have between `facetNb` and `facetNb + delta` facets
      * {number} (optional positive integer) is the wanted number of particles : each particle is built with `mesh_total_facets / number` facets
+     * {storage} (optional existing array) is an array where the particles will be stored for a further use instead of being inserted in the SPS.  
      * @returns the current SPS
      */
-    public digest(mesh: Mesh, options?: { facetNb?: number; number?: number; delta?: number }): SolidParticleSystem {
+    public digest(mesh: Mesh, options?: { facetNb?: number; number?: number; delta?: number; storage?: [] }): SolidParticleSystem {
         var size: number = (options && options.facetNb) || 1;
         var number: number = (options && options.number) || 0;
         var delta: number = (options && options.delta) || 0;
@@ -238,6 +240,7 @@ export class SolidParticleSystem implements IDisposable {
         var meshUV = <FloatArray>mesh.getVerticesData(VertexBuffer.UVKind);
         var meshCol = <FloatArray>mesh.getVerticesData(VertexBuffer.ColorKind);
         var meshNor = <FloatArray>mesh.getVerticesData(VertexBuffer.NormalKind);
+        var storage = (options && options.storage) ? options.storage : null;
 
         var f: number = 0;                              // facet counter
         var totalFacets: number = meshInd.length / 3;   // a facet is a triangle, so 3 indices
@@ -324,14 +327,16 @@ export class SolidParticleSystem implements IDisposable {
             var currentPos = this._positions.length;
             var currentInd = this._indices.length;
             this._meshBuilder(this._index, shape, this._positions, shapeInd, this._indices, facetUV, this._uvs, shapeCol, this._colors, shapeNor, this._normals, idx, 0, null);
-            this._addParticle(this._lastParticleIdx, currentPos, currentInd, modelShape, this._shapeCounter, 0, bInfo);
+            this._addParticle(idx, this._lastParticleId, currentPos, currentInd, modelShape, this._shapeCounter, 0, bInfo, storage);
             // initialize the particle position
             this.particles[this.nbParticles].position.addInPlace(barycenter);
 
-            this._index += shape.length;
-            idx++;
-            this.nbParticles++;
-            this._lastParticleIdx++;
+            if (storage) {
+                this._index += shape.length;
+                idx++;
+                this.nbParticles++;
+            }
+            this._lastParticleId++;
             this._shapeCounter++;
             f += size;
         }
@@ -394,6 +399,7 @@ export class SolidParticleSystem implements IDisposable {
         const copy = this._copy;
         copy.idx = idx;
         copy.idxInShape = idxInShape;
+        const storeApart = (options && options.storage) ? true : false;
         if (options && options.positionFunction) {        // call to custom positionFunction
             options.positionFunction(copy, idx, idxInShape);
             this._mustUnrotateFixedNormals = true;
@@ -415,6 +421,12 @@ export class SolidParticleSystem implements IDisposable {
             pivotBackTranslation.copyFrom(scaledPivot);
         }
 
+        // in case the particle geometry must not be inserted in the SPS mesh geometry
+        if (storeApart) {
+            return copy;
+        }
+        
+
         for (i = 0; i < shape.length; i++) {
             tmpVertex.copyFrom(shape[i]);
             if (options && options.vertexFunction) {
@@ -425,6 +437,7 @@ export class SolidParticleSystem implements IDisposable {
             Vector3.TransformCoordinatesToRef(tmpVertex, rotMatrix, tmpRotated);
             tmpRotated.addInPlace(pivotBackTranslation).addInPlace(copy.position);
             positions.push(tmpRotated.x, tmpRotated.y, tmpRotated.z);
+            
             if (meshUV) {
                 const copyUvs = copy.uvs;
                 uvs.push((copyUvs.z - copyUvs.x) * meshUV[u] + copyUvs.x, (copyUvs.w - copyUvs.y) * meshUV[u + 1] + copyUvs.y);
@@ -449,7 +462,7 @@ export class SolidParticleSystem implements IDisposable {
             }
             colors.push(this._color.r, this._color.g, this._color.b, this._color.a);
             c += 4;
-
+    
             if (!this.recomputeNormals && meshNor) {
                 tmpVertex.x = meshNor[n];
                 tmpVertex.y = meshNor[n + 1];
@@ -504,9 +517,10 @@ export class SolidParticleSystem implements IDisposable {
     }
 
     // adds a new particle object in the particles array
-    private _addParticle(idx: number, idxpos: number, idxind: number, model: ModelShape, shapeId: number, idxInShape: number, bInfo: Nullable<BoundingInfo> = null): SolidParticle {
-        var sp = new SolidParticle(idx, idxpos, idxind, model, shapeId, idxInShape, this, bInfo);
-        this.particles.push(sp);
+    private _addParticle(idx: number, id: number, idxpos: number, idxind: number, model: ModelShape, shapeId: number, idxInShape: number, bInfo: Nullable<BoundingInfo> = null, storage: Nullable<[]> = null): SolidParticle {
+        var sp = new SolidParticle(idx, id, idxpos, idxind, model, shapeId, idxInShape, this, bInfo);
+        var target = (storage) ? storage : this.particles;
+        target.push(sp);
         return sp;
     }
 
@@ -517,9 +531,10 @@ export class SolidParticleSystem implements IDisposable {
      * @param nb (positive integer) the number of particles to be created from this model
      * @param options {positionFunction} is an optional javascript function to called for each particle on SPS creation.
      * {vertexFunction} is an optional javascript function to called for each vertex of each particle on SPS creation
+     * {storage} (optional existing array) is an array where the particles will be stored for a further use instead of being inserted in the SPS.  
      * @returns the number of shapes in the system
      */
-    public addShape(mesh: Mesh, nb: number, options?: { positionFunction?: any; vertexFunction?: any }): number {
+    public addShape(mesh: Mesh, nb: number, options?: { positionFunction?: any; vertexFunction?: any; storage?: [] }): number {
         var meshPos = <FloatArray>mesh.getVerticesData(VertexBuffer.PositionKind);
         var meshInd = <IndicesArray>mesh.getIndices();
         var meshUV = <FloatArray>mesh.getVerticesData(VertexBuffer.UVKind);
@@ -529,6 +544,7 @@ export class SolidParticleSystem implements IDisposable {
         var indices = Array.from(meshInd);
         var shapeNormals = Array.from(meshNor);
         var shapeColors = (meshCol) ? Array.from(meshCol) : [];
+        var storage = (options && options.storage) ? options.storage : null;
         var bbInfo;
         if (this._particlesIntersect) {
             bbInfo = mesh.getBoundingInfo();
@@ -551,7 +567,7 @@ export class SolidParticleSystem implements IDisposable {
             var currentInd = this._indices.length;
             currentCopy = this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, meshNor, this._normals, idx, i, options);
             if (this._updatable) {
-                sp = this._addParticle(this._lastParticleIdx, currentPos, currentInd, modelShape, this._shapeCounter, i, bbInfo);
+                sp = this._addParticle(idx, this._lastParticleId, currentPos, currentInd, modelShape, this._shapeCounter, i, bbInfo, storage);
                 sp.position.copyFrom(currentCopy.position);
                 sp.rotation.copyFrom(currentCopy.rotation);
                 if (currentCopy.rotationQuaternion && sp.rotationQuaternion) {
@@ -563,13 +579,15 @@ export class SolidParticleSystem implements IDisposable {
                 sp.scaling.copyFrom(currentCopy.scaling);
                 sp.uvs.copyFrom(currentCopy.uvs);
             }
-            this._index += shape.length;
-            idx++;
-            this._lastParticleIdx++;
-        }
-        this.nbParticles += nb;
+            if (!storage) {
+                this._index += shape.length;
+                idx++;
+                this.nbParticles++;
+            }
+            this._lastParticleId++;
+        } 
         this._shapeCounter++;
-        this._isNotBuilt = true;        // buildMesh() is now expected for setParticles() to work
+        this._isNotBuilt = true;        // buildMesh() call is now expected for setParticles() to work
         return this._shapeCounter - 1;
     }
 
@@ -665,6 +683,7 @@ export class SolidParticleSystem implements IDisposable {
         this._uvs.length = 0;
         this._normals.length = 0;
         this._index = 0;
+        this._idxOfId.length = 0;
         const particlesLength = particles.length;
         for (var p = 0; p < particlesLength; p++) {
             var particle = particles[p];
@@ -674,6 +693,8 @@ export class SolidParticleSystem implements IDisposable {
             var modelNormals = model._normals;
             var modelColors = model._shapeColors;
             var modelUVs = model._shapeUV;
+            particle.idx = p;
+            this._idxOfId[particle.id] = p;
             this._meshBuilder(this._index, shape, this._positions, modelIndices, this._indices, modelUVs, this._uvs, modelColors, this._colors, modelNormals, this._normals, particle.idx, particle.idxInShape, null);
             this._index += shape.length;
         }
@@ -824,7 +845,7 @@ export class SolidParticleSystem implements IDisposable {
 
                 const particleHasParent = (particle.parentId !== null);
                 if (particleHasParent) {
-                    const parent = this.particles[particle.parentId!];
+                    const parent = this.getParticleById(particle.parentId!);
                     if (parent) {
                         const parentRotationMatrix = parent._rotationMatrix;
                         const parentGlobalPosition = parent._globalPosition;
@@ -1096,21 +1117,51 @@ export class SolidParticleSystem implements IDisposable {
      */
     public getParticleById(id: number): Nullable<SolidParticle> {
         const p = this.particles[id];
-        if (p && p.idx == id) {
+        if (p && p.id == id) {
             return p;
         }
+        const particles = this.particles;
+        const idx = this._idxOfId[id];
+        if (idx !== undefined) {
+            return particles[idx];
+        }
         var i = 0;
         const nb = this.nbParticles;
-        const particles = this.particles;
         while (i < nb) {
-            if (particles[i].idx == id) {
-                return particles[i];
+            var particle = particles[i];
+            if (particle.id == id) {
+                return particle;
             }
             i++;
         }
         return null;
     }
     /**
+     * Returns a new array populated with the particles having the passed shapeId.
+     * @param shapeId (integer)
+     */
+    public getParticlesByShapeId(shapeId: number): SolidParticle[] {
+        var ref: SolidParticle[] = [];
+        this.getParticlesByShapeIdToRef(shapeId, ref);
+        return ref;
+    }
+    /**
+     * Populates the passed array "ref" with the particles having the passed shapeId.
+     * Returns the SPS.
+     * @param shapeId 
+     * @param ref 
+     */
+    public getParticlesByShapeIdToRef(shapeId: number, ref: SolidParticle[]): SolidParticleSystem {
+        ref.length = 0;
+        for (var i = 0; i < this.nbParticles; i++) {
+            var p = this.particles[i];
+            if (p.shapeId == shapeId) {
+                ref.push(p);
+            }
+        }
+        return this;
+    }
+    /**
      * Visibilty helper : Recomputes the visible size according to the mesh bounding box
      * doc : http://doc.babylonjs.com/how_to/Solid_Particle_System#sps-visibility
      * @returns the SPS.