Kaynağa Gözat

Make sure the particle effect is created with all uniforms/attributes/samplers/defines needed

Popov72 5 yıl önce
ebeveyn
işleme
4bc7ef8e77

+ 27 - 15
src/Materials/Node/nodeMaterial.ts

@@ -810,7 +810,7 @@ export class NodeMaterial extends PushMaterial {
         return postProcess;
     }
 
-    private _createEffectForParticles(particleSystem?: ParticleSystem, onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void, effect?: Effect, defines?: NodeMaterialDefines, dummyMesh?: AbstractMesh): Effect {
+    private _createEffectForParticles(particleSystem: ParticleSystem, onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void, effect?: Effect, defines?: NodeMaterialDefines, dummyMesh?: AbstractMesh) {
         let tempName = this.name + this._buildId;
 
         if (!defines) {
@@ -823,16 +823,21 @@ export class NodeMaterial extends PushMaterial {
 
         let buildId = this._buildId;
 
+        let particleSystemDefines: Array<string> = [];
+        let particleSystemDefinesJoined = "";
+
         if (!effect) {
             const result = this._processDefines(dummyMesh, defines);
 
             Effect.RegisterShader(tempName, this._fragmentCompilationState._builtCompilationString);
 
-            effect = this.getScene().getEngine().createEffectForParticles(tempName, this._fragmentCompilationState.uniforms, this._fragmentCompilationState.samplers, defines.toString(), result?.fallbacks, onCompiled, onError);
+            particleSystem.fillDefines(particleSystemDefines, particleSystem.blendMode);
 
-            if (particleSystem) {
-                particleSystem.customEffect = effect;
-            }
+            particleSystemDefinesJoined = particleSystemDefines.join("\n");
+
+            effect = this.getScene().getEngine().createEffectForParticles(tempName, this._fragmentCompilationState.uniforms, this._fragmentCompilationState.samplers, defines.toString() + "\n" + particleSystemDefinesJoined, result?.fallbacks, onCompiled, onError, particleSystem);
+
+            particleSystem.customEffect = effect;
         }
 
         effect.onBindObservable.add((effect) => {
@@ -846,16 +851,26 @@ export class NodeMaterial extends PushMaterial {
                 buildId = this._buildId;
             }
 
+            particleSystemDefines.length = 0;
+
+            particleSystem.fillDefines(particleSystemDefines, particleSystem.blendMode);
+
+            const particleSystemDefinesJoinedCurrent = particleSystemDefines.join("\n");
+
+            if (particleSystemDefinesJoinedCurrent !== particleSystemDefinesJoined) {
+                defines!.markAsUnprocessed();
+                particleSystemDefinesJoined = particleSystemDefinesJoinedCurrent;
+            }
+
             const result = this._processDefines(dummyMesh!, defines!);
 
             if (result) {
                 Effect.RegisterShader(tempName, this._fragmentCompilationState._builtCompilationString);
 
-                if (particleSystem) {
-                    particleSystem.customEffect = this.getScene().getEngine().createEffectForParticles(tempName, this._fragmentCompilationState.uniforms, this._fragmentCompilationState.samplers, defines!.toString(), result?.fallbacks, onCompiled, onError);
-                    this._createEffectForParticles(particleSystem, onCompiled, onError, particleSystem.customEffect, defines, dummyMesh);
-                    return;
-                }
+                effect = this.getScene().getEngine().createEffectForParticles(tempName, this._fragmentCompilationState.uniforms, this._fragmentCompilationState.samplers, defines!.toString() + "\n" + particleSystemDefinesJoined, result?.fallbacks, onCompiled, onError, particleSystem);
+                particleSystem.customEffect = effect;
+                this._createEffectForParticles(particleSystem, onCompiled, onError, effect, defines, dummyMesh); // add the effect.onBindObservable observer
+                return;
             }
 
             // Animated blocks
@@ -883,8 +898,6 @@ export class NodeMaterial extends PushMaterial {
                 inputBlock._transmit(effect, this.getScene());
             }
         });
-
-        return effect;
     }
 
     /**
@@ -892,10 +905,9 @@ export class NodeMaterial extends PushMaterial {
      * @param particleSystem Particle system to create the effect for
      * @param onCompiled defines a function to call when the effect creation is successful
      * @param onError defines a function to call when the effect creation has failed
-     * @returns The new effect
      */
-    public createEffectForParticles(particleSystem?: ParticleSystem, onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void): Effect {
-        return this._createEffectForParticles(particleSystem, onCompiled, onError);
+    public createEffectForParticles(particleSystem: ParticleSystem, onCompiled?: (effect: Effect) => void, onError?: (effect: Effect, errors: string) => void) {
+        this._createEffectForParticles(particleSystem, onCompiled, onError);
     }
 
     private _processDefines(mesh: AbstractMesh, defines: NodeMaterialDefines, useInstances = false): Nullable<{

+ 22 - 0
src/Particles/particleSystem.ts

@@ -224,6 +224,20 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
         this._customEffect = effect;
     }
 
+    /** @hidden */
+    private _onBeforeDrawParticlesObservable: Nullable<Observable<Nullable<Effect>>> = null;
+
+    /**
+     * Observable that will be called just before the particles are drawn
+     */
+    public get onBeforeDrawParticlesObservable(): Observable<Nullable<Effect>> {
+        if (!this._onBeforeDrawParticlesObservable) {
+            this._onBeforeDrawParticlesObservable = new Observable<Nullable<Effect>>();
+        }
+
+        return this._onBeforeDrawParticlesObservable;
+    }
+
     /**
      * Instantiates a particle system.
      * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
@@ -1891,6 +1905,10 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
                 break;
         }
 
+        if (this._onBeforeDrawParticlesObservable) {
+            this._onBeforeDrawParticlesObservable.notifyObservers(effect);
+        }
+
         if (this._useInstancing) {
             engine.drawArraysType(Material.TriangleFanDrawMode, 0, 4, this._particles.length);
         } else {
@@ -1982,6 +2000,10 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
             (<AbstractMesh>this.emitter).dispose(true);
         }
 
+        if (this._onBeforeDrawParticlesObservable) {
+            this._onBeforeDrawParticlesObservable.clear();
+        }
+
         // Remove from scene
         var index = this._scene.particleSystems.indexOf(this);
         if (index > -1) {