David Catuhe 5 年 前
コミット
a0f9be0c68

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

@@ -231,6 +231,7 @@
 - Added the feature "storable particles" and `insertParticlesFromArray()` to the Solid Particle System ([jerome](https://github.com/jbousquie/))
 - Added the support for MultiMaterials to the Solid Particle System ([jerome](https://github.com/jbousquie/))
 - Added support for `CustomParticleEmitter`. [Doc](https://doc.babylonjs.com/babylon101/particles#custom-emitter) ([Deltakosh](https://github.com/deltakosh/))
+- Added support for `MeshParticleEmitter`. [Doc](https://doc.babylonjs.com/babylon101/particles#mesh-emitter) ([Deltakosh](https://github.com/deltakosh/))
 
 ### Navigation Mesh
 

+ 3 - 1
src/Particles/EmitterTypes/IParticleEmitterType.ts

@@ -1,6 +1,7 @@
 import { Vector3, Matrix } from "../../Maths/math.vector";
 import { Effect } from "../../Materials/effect";
 import { Particle } from "../../Particles/particle";
+import { Scene } from '../../scene';
 /**
  * Particle emitter represents a volume emitting particles.
  * This is the responsibility of the implementation to define the volume shape like cone/sphere/box.
@@ -55,6 +56,7 @@ export interface IParticleEmitterType {
     /**
      * Parse properties from a JSON object
      * @param serializationObject defines the JSON object
+     * @param scene defines the hosting scene
      */
-    parse(serializationObject: any): void;
+    parse(serializationObject: any, scene: Scene): void;
 }

+ 2 - 1
src/Particles/EmitterTypes/index.ts

@@ -5,4 +5,5 @@ export * from "./hemisphericParticleEmitter";
 export * from "./IParticleEmitterType";
 export * from "./pointParticleEmitter";
 export * from "./sphereParticleEmitter";
-export * from "./customParticleEmitter";
+export * from "./customParticleEmitter";
+export * from "./meshParticleEmitter";

+ 181 - 0
src/Particles/EmitterTypes/meshParticleEmitter.ts

@@ -0,0 +1,181 @@
+import { DeepCopier } from "../../Misc/deepCopier";
+import { Vector3, Matrix, TmpVectors } from "../../Maths/math.vector";
+import { Scalar } from "../../Maths/math.scalar";
+import { Effect } from "../../Materials/effect";
+import { Particle } from "../../Particles/particle";
+import { IParticleEmitterType } from "./IParticleEmitterType";
+import { IndicesArray, Nullable, FloatArray } from '../../types';
+import { VertexBuffer } from '../../Meshes/buffer';
+import { Scene } from '../../scene';
+import { AbstractMesh } from '../../Meshes/abstractMesh';
+/**
+ * Particle emitter emitting particles from the inside of a box.
+ * It emits the particles randomly between 2 given directions.
+ */
+export class MeshParticleEmitter implements IParticleEmitterType {
+    private _indices: Nullable<IndicesArray> = null;
+    private _positions: Nullable<FloatArray> = null;
+    private _normals: Nullable<FloatArray> = null;
+    private _storedNormal = Vector3.Zero();
+
+    /**
+     * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+     */
+    public direction1 = new Vector3(0, 1.0, 0);
+    /**
+     * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
+     */
+    public direction2 = new Vector3(0, 1.0, 0);
+
+    /**
+     * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
+     */
+    public useMeshNormalsForDirection = true;
+
+    /**
+     * Creates a new instance MeshParticleEmitter
+     * @param mesh defines the mesh to use as source
+     */
+    constructor(
+        /** Defines the mesh to use as source */
+        public mesh?: AbstractMesh) {
+
+        if (mesh) {
+            this._indices = mesh.getIndices();
+            this._positions = mesh.getVerticesData(VertexBuffer.PositionKind);
+            this._normals = mesh.getVerticesData(VertexBuffer.NormalKind);
+        }
+    }
+
+    /**
+     * Called by the particle System when the direction is computed for the created particle.
+     * @param worldMatrix is the world matrix of the particle system
+     * @param directionToUpdate is the direction vector to update with the result
+     * @param particle is the particle we are computed the direction for
+     */
+    public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle): void {
+        if (this.useMeshNormalsForDirection && this._normals) {
+            Vector3.TransformNormalToRef(this._storedNormal, worldMatrix, directionToUpdate);
+            return;    
+        }
+
+        var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
+        var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
+        var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
+
+        Vector3.TransformNormalFromFloatsToRef(randX, randY, randZ, worldMatrix, directionToUpdate);
+    }
+
+    /**
+     * Called by the particle System when the position is computed for the created particle.
+     * @param worldMatrix is the world matrix of the particle system
+     * @param positionToUpdate is the position vector to update with the result
+     * @param particle is the particle we are computed the position for
+     */
+    public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle): void {
+        if (!this._indices || !this._positions) {
+            return;
+        }
+
+        let randomFaceIndex = 3 * Math.random() * (this._indices.length / 3) | 0;
+        let bu = Math.random();
+        let bv = Math.random() * (1.0 - bu);
+        let bw = 1.0 - bu - bv;
+
+        let faceIndexA = this._indices[randomFaceIndex];
+        let faceIndexB = this._indices[randomFaceIndex + 1];
+        let faceIndexC = this._indices[randomFaceIndex + 2];
+        let vertexA = TmpVectors.Vector3[0];
+        let vertexB = TmpVectors.Vector3[1];
+        let vertexC = TmpVectors.Vector3[2];
+        let randomVertex = TmpVectors.Vector3[3];
+        
+        Vector3.FromArrayToRef(this._positions, faceIndexA * 3, vertexA);
+        Vector3.FromArrayToRef(this._positions, faceIndexB * 3, vertexB);
+        Vector3.FromArrayToRef(this._positions, faceIndexC * 3, vertexC);
+
+        randomVertex.x = bu * vertexA.x + bv * vertexB.x + bw * vertexC.x;
+        randomVertex.y = bu * vertexA.y + bv * vertexB.y + bw * vertexC.y;
+        randomVertex.z = bu * vertexA.z + bv * vertexB.z + bw * vertexC.z;
+
+        Vector3.TransformCoordinatesFromFloatsToRef(randomVertex.x, randomVertex.y, randomVertex.z, worldMatrix, positionToUpdate);
+
+        if (this.useMeshNormalsForDirection && this._normals) {
+            Vector3.FromArrayToRef(this._normals, faceIndexA * 3, vertexA);
+            Vector3.FromArrayToRef(this._normals, faceIndexB * 3, vertexB);
+            Vector3.FromArrayToRef(this._normals, faceIndexC * 3, vertexC);
+
+            this._storedNormal.x = bu * vertexA.x + bv * vertexB.x + bw * vertexC.x;
+            this._storedNormal.y = bu * vertexA.y + bv * vertexB.y + bw * vertexC.y;
+            this._storedNormal.z = bu * vertexA.z + bv * vertexB.z + bw * vertexC.z;
+        }
+    }
+
+    /**
+     * Clones the current emitter and returns a copy of it
+     * @returns the new emitter
+     */
+    public clone(): MeshParticleEmitter {
+        let newOne = new MeshParticleEmitter(this.mesh);
+
+        DeepCopier.DeepCopy(this, newOne);
+
+        return newOne;
+    }
+
+    /**
+     * Called by the GPUParticleSystem to setup the update shader
+     * @param effect defines the update shader
+     */
+    public applyToShader(effect: Effect): void {
+        effect.setVector3("direction1", this.direction1);
+        effect.setVector3("direction2", this.direction2);
+    }
+
+    /**
+     * Returns a string to use to update the GPU particles update shader
+     * @returns a string containng the defines string
+     */
+    public getEffectDefines(): string {
+        return "";
+    }
+
+    /**
+     * Returns the string "BoxParticleEmitter"
+     * @returns a string containing the class name
+     */
+    public getClassName(): string {
+        return "MeshParticleEmitter";
+    }
+
+    /**
+     * Serializes the particle system to a JSON object.
+     * @returns the JSON object
+     */
+    public serialize(): any {
+        var serializationObject: any = {};
+
+        serializationObject.type = this.getClassName();
+        serializationObject.direction1 = this.direction1.asArray();
+        serializationObject.direction2 = this.direction2.asArray();
+        serializationObject.meshId = this.mesh?.id;
+        serializationObject.useMeshNormalsForDirection = this.useMeshNormalsForDirection;
+
+        return serializationObject;
+    }
+
+    /**
+     * Parse properties from a JSON object
+     * @param serializationObject defines the JSON object
+     */
+    public parse(serializationObject: any, scene: Scene): void {
+        Vector3.FromArrayToRef(serializationObject.direction1, 0, this.direction1);
+        Vector3.FromArrayToRef(serializationObject.direction2, 0, this.direction2);
+
+        if (serializationObject.meshId) {
+            this.mesh = scene.getLastMeshByID(serializationObject.meshId) || undefined;
+        }
+
+        this.useMeshNormalsForDirection = serializationObject.useMeshNormalsForDirection;
+    }
+}

+ 2 - 2
src/Particles/particleSystem.ts

@@ -2533,10 +2533,10 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
                     break;
             }
 
-            emitterType.parse(parsedParticleSystem.particleEmitterType);
+            emitterType.parse(parsedParticleSystem.particleEmitterType, scene);
         } else {
             emitterType = new BoxParticleEmitter();
-            emitterType.parse(parsedParticleSystem);
+            emitterType.parse(parsedParticleSystem, scene);
         }
         particleSystem.particleEmitterType = emitterType;