Pārlūkot izejas kodu

Fix gpu part with particle editor

David Catuhe 5 gadi atpakaļ
vecāks
revīzija
b8af37b441

+ 14 - 0
.vscode/launch.json

@@ -54,6 +54,20 @@
             ]
         },
         {
+            "name": "Launch playground (Edge)",
+            "type": "edge",
+            "version": "dev",
+            "request": "launch",
+            "url": "http://localhost:1338/Playground/index-local.html",
+            "webRoot": "${workspaceRoot}/",
+            "sourceMaps": true,
+            "preLaunchTask": "run",
+            "userDataDir": "${workspaceRoot}/.tempChromeProfileForDebug",
+            "runtimeArgs": [
+                "--enable-unsafe-es3-apis"
+            ]
+        },
+        {
             "name": "Launch playground (Chrome+WebGL 1.0 forced)",
             "type": "chrome",
             "request": "launch",

+ 1 - 1
inspector/src/components/actionTabs/actionTabs.scss

@@ -227,7 +227,7 @@ $line-padding-left: 2px;
                         cursor: pointer;
                     }
 
-                    .button {
+                    .link-button {
                         grid-column: 2;
 
                         button {

+ 1 - 1
inspector/src/components/actionTabs/lines/linkButtonComponent.tsx

@@ -24,7 +24,7 @@ export class LinkButtonComponent extends React.Component<ILinkButtonComponentPro
                 <div className="link" title={this.props.label} onClick={() => this.onLink()}>
                     {this.props.label}
                 </div>
-                <div className="button">
+                <div className="link-button">
                     <button onClick={() => this.props.onClick()}>{this.props.buttonLabel}</button>
                 </div> 
             </div>

+ 3 - 2
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/colorGradientStepGridComponent.tsx

@@ -6,6 +6,7 @@ import { ColorGradient, Color3Gradient } from 'babylonjs/Misc/gradients';
 import { LockObject } from '../lockObject';
 import { Color3, Color4 } from 'babylonjs/Maths/math.color';
 import { IParticleSystem } from 'babylonjs/Particles/IParticleSystem';
+import { ParticleSystem } from 'babylonjs/Particles/particleSystem';
 
 interface IColorGradientStepGridComponent {
     globalState: GlobalState;
@@ -113,8 +114,8 @@ export class ColorGradientStepGridComponent extends React.Component<IColorGradie
                     </div>
                 }
                 {
-                    gradient instanceof ColorGradient &&
-                    <div className="color1">
+                    this.props.host instanceof ParticleSystem && gradient instanceof ColorGradient &&
+                    <div className="color2">
                         <input type="color" value={gradient.color2 ? gradient.color2.toHexString(true) : "#000000"} onChange={(evt) => this.updateColor2(evt.target.value)} />
                     </div>
                 }

+ 8 - 4
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/factorGradientStepGridComponent.tsx

@@ -5,6 +5,7 @@ import { GlobalState } from '../../../../globalState';
 import { FactorGradient } from 'babylonjs/Misc/gradients';
 import { LockObject } from '../lockObject';
 import { IParticleSystem } from 'babylonjs/Particles/IParticleSystem';
+import { ParticleSystem } from 'babylonjs/Particles/particleSystem';
 
 interface IFactorGradientStepGridComponent {
     globalState: GlobalState;
@@ -91,10 +92,13 @@ export class FactorGradientStepGridComponent extends React.Component<IFactorGrad
                     <input type="number" step={"0.01"} className="numeric-input" value={gradient.factor1} onBlur={() => this.unlock()} onFocus={() => this.lock()}
                         onChange={evt => this.updateFactor1(parseFloat(evt.target.value))} />
                 </div>
-                <div className="factor2">
-                    <input type="number" step={"0.01"} className={"numeric-input" + ((gradient.factor1 === gradient.factor2 || gradient.factor2 === undefined) ? " grayed" : "")} value={gradient.factor2} onBlur={() => this.unlock()} onFocus={() => this.lock()} 
-                        onChange={evt => this.updateFactor2(parseFloat(evt.target.value))} />
-                </div>
+                {
+                    this.props.host instanceof ParticleSystem &&
+                    <div className="factor2">
+                        <input type="number" step={"0.01"} className={"numeric-input" + ((gradient.factor1 === gradient.factor2 || gradient.factor2 === undefined) ? " grayed" : "")} value={gradient.factor2} onBlur={() => this.unlock()} onFocus={() => this.lock()} 
+                            onChange={evt => this.updateFactor2(parseFloat(evt.target.value))} />
+                    </div>
+                }
                 <div className="step-value">
                     {gradient.gradient.toFixed(2)}
                 </div>

+ 105 - 91
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/particleSystemPropertyGridComponent.tsx

@@ -118,9 +118,10 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
         if (system instanceof GPUParticleSystem) {
             let isStarted = system.isStarted() && !system.isStopped();
             return (
-                <ButtonLineComponent label={isStarted ? "Pause" : "Start"} onClick={() => {
+                <ButtonLineComponent label={isStarted ? "Stop" : "Start"} onClick={() => {
                     if (isStarted) {
                         system.stop();
+                        system.reset();
                     } else {
                         system.start();
                     }
@@ -165,11 +166,12 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
         Tools.ReadFile(file, (data) => {
             let decoder = new TextDecoder("utf-8");
             let jsonObject = JSON.parse(decoder.decode(data));
+            let isGpu = system instanceof GPUParticleSystem
             
             system.dispose();            
             this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
 
-            let newSystem = ParticleSystem.Parse(jsonObject, scene, "");
+            let newSystem = isGpu ? GPUParticleSystem.Parse(jsonObject, scene, "") : ParticleSystem.Parse(jsonObject, scene, "");
             this.props.globalState.onSelectionChangedObservable.notifyObservers(newSystem);
         }, undefined, true);
     }
@@ -219,7 +221,7 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                     <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={system} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
                     <TextLineComponent label="Class" value={system.getClassName()} />  
                     <TextLineComponent label="Capacity" value={system.getCapacity().toString()} />  
-                    <TextLineComponent label="Capacity" value={system.getActiveCount().toString()} />  
+                    <TextLineComponent label="Active count" value={system.getActiveCount().toString()} />  
                     <TextureLinkLineComponent label="Texture" texture={system.particleTexture} onSelectionChangedObservable={this.props.onSelectionChangedObservable}/>
                     <OptionsLineComponent label="Blend mode" options={blendModeOptions} target={system} propertyName="blendMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <Vector3LineComponent label="Gravity" target={system} propertyName="gravity"
@@ -355,20 +357,23 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                 </LineContainerComponent>       
                 <LineContainerComponent globalState={this.props.globalState} title="EMISSION">
                     <FloatLineComponent lockObject={this.props.lockObject} label="Rate" target={system} propertyName="emitRate" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getEmitRateGradients()!} 
-                        label="Velocity gradients"                        
-                        docLink="https://doc.babylonjs.com/babylon101/particles#emit-rate-over-time"
-                        onCreateRequired={() => {
-                            system.addEmitRateGradient(0, 50, 50);
-                            this.props.globalState.onCodeChangedObservable.notifyObservers({
-                                object: system,
-                                code: `TARGET.addEmitRateGradient(0, 50, 50);`
-                            });
-                        }}
-                        mode={GradientGridMode.Factor}
-                        host={system}    
-                        codeRecorderPropertyName="getEmitRateGradients()"
-                        lockObject={this.props.lockObject}/>                  
+                    {
+                        system instanceof ParticleSystem && 
+                        <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getEmitRateGradients()!} 
+                            label="Velocity gradients"                        
+                            docLink="https://doc.babylonjs.com/babylon101/particles#emit-rate-over-time"
+                            onCreateRequired={() => {
+                                system.addEmitRateGradient(0, 50, 50);
+                                this.props.globalState.onCodeChangedObservable.notifyObservers({
+                                    object: system,
+                                    code: `TARGET.addEmitRateGradient(0, 50, 50);`
+                                });
+                            }}
+                            mode={GradientGridMode.Factor}
+                            host={system}    
+                            codeRecorderPropertyName="getEmitRateGradients()"
+                            lockObject={this.props.lockObject}/>                  
+                    }
                     <FloatLineComponent lockObject={this.props.lockObject} label="Min emit power" target={system} propertyName="minEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Max emit power" target={system} propertyName="maxEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />               
                     <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getVelocityGradients()!} 
@@ -421,21 +426,23 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                     <FloatLineComponent lockObject={this.props.lockObject} label="Max scale X" target={system} propertyName="maxScaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Min scale Y" target={system} propertyName="minScaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Max scale Y" target={system} propertyName="maxScaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getStartSizeGradients()!} 
-                        label="Start size gradients"
-                        docLink="https://doc.babylonjs.com/babylon101/particles#start-size-over-time"
-                        onCreateRequired={() => {
-                            system.addStartSizeGradient(0, 1, 1);
-                            this.props.globalState.onCodeChangedObservable.notifyObservers({
-                                object: system,
-                                code: `TARGET.addStartSizeGradient(0, 1, 1);`
-                            });                                
-                        }}       
-                        host={system}    
-                        codeRecorderPropertyName="getStartSizeGradients()"
-                        mode={GradientGridMode.Factor}
-                        lockObject={this.props.lockObject}/>                                    
-               
+                    {
+                        system instanceof ParticleSystem && 
+                        <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getStartSizeGradients()!} 
+                            label="Start size gradients"
+                            docLink="https://doc.babylonjs.com/babylon101/particles#start-size-over-time"
+                            onCreateRequired={() => {
+                                system.addStartSizeGradient(0, 1, 1);
+                                this.props.globalState.onCodeChangedObservable.notifyObservers({
+                                    object: system,
+                                    code: `TARGET.addStartSizeGradient(0, 1, 1);`
+                                });                                
+                            }}       
+                            host={system}    
+                            codeRecorderPropertyName="getStartSizeGradients()"
+                            mode={GradientGridMode.Factor}
+                            lockObject={this.props.lockObject}/>                                    
+                    }
                     <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getSizeGradients()!} 
                         label="Size gradients"
                         docLink="https://doc.babylonjs.com/babylon101/particles#size"
@@ -455,20 +462,23 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                     <FloatLineComponent lockObject={this.props.lockObject} label="Min lifetime" target={system} propertyName="minLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Max lifetime" target={system} propertyName="maxLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                     <FloatLineComponent lockObject={this.props.lockObject} label="Target stop duration" target={system} propertyName="targetStopDuration" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                    <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getLifeTimeGradients()!} 
-                        label="Lifetime gradients"
-                        docLink="https://doc.babylonjs.com/babylon101/particles#lifetime"
-                        onCreateRequired={() => {
-                            system.addLifeTimeGradient(0, 1, 1);
-                            this.props.globalState.onCodeChangedObservable.notifyObservers({
-                                object: system,
-                                code: `TARGET.addLifeTimeGradient(0, 1, 1);`
-                            });                               
-                        }}
-                        host={system}    
-                        codeRecorderPropertyName="getLifeTimeGradients()"                          
-                        mode={GradientGridMode.Factor}                        
-                        lockObject={this.props.lockObject}/>                    
+                    {
+                        system instanceof ParticleSystem &&                     
+                        <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getLifeTimeGradients()!} 
+                            label="Lifetime gradients"
+                            docLink="https://doc.babylonjs.com/babylon101/particles#lifetime"
+                            onCreateRequired={() => {
+                                system.addLifeTimeGradient(0, 1, 1);
+                                this.props.globalState.onCodeChangedObservable.notifyObservers({
+                                    object: system,
+                                    code: `TARGET.addLifeTimeGradient(0, 1, 1);`
+                                });                               
+                            }}
+                            host={system}    
+                            codeRecorderPropertyName="getLifeTimeGradients()"                          
+                            mode={GradientGridMode.Factor}                        
+                            lockObject={this.props.lockObject}/>
+                    }                    
                 </LineContainerComponent>    
                 <LineContainerComponent globalState={this.props.globalState} title="COLORS">
                     <Color4LineComponent label="Color 1" target={system} propertyName="color1" 
@@ -491,51 +501,55 @@ export class ParticleSystemPropertyGridComponent extends React.Component<IPartic
                         codeRecorderPropertyName="getColorGradients()"                              
                         mode={GradientGridMode.Color4}                        
                         lockObject={this.props.lockObject}/>                    
-
-                    <CheckBoxLineComponent label="Use ramp grandients" target={system} propertyName="useRampGradients"/>
-                    <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getRampGradients()!} 
-                        label="Ramp gradients"
-                        docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
-                        onCreateRequired={() => {
-                            system.addRampGradient(0, Color3.White());
-                            this.props.globalState.onCodeChangedObservable.notifyObservers({
-                                object: system,
-                                code: `TARGET.addRampGradient(0, BABYLON.Color3.White());`
-                            });                               
-                        }}
-                        mode={GradientGridMode.Color3}      
-                        host={system}    
-                        codeRecorderPropertyName="getRampGradients()"                                                   
-                        lockObject={this.props.lockObject}/>                    
-                                                               
-                    <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getColorRemapGradients()!} 
-                        label="Color remap gradients"
-                        docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
-                        onCreateRequired={() => {
-                            system.addColorRemapGradient(0, 1, 1);
-                            this.props.globalState.onCodeChangedObservable.notifyObservers({
-                                object: system,
-                                code: `TARGET.addColorRemapGradient(0, 1, 1);`
-                            });
-                        }}
-                        host={system}    
-                        codeRecorderPropertyName="getColorRemapGradients()"      
-                        mode={GradientGridMode.Factor}                        
-                        lockObject={this.props.lockObject}/>                    
-                    <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getAlphaRemapGradients()!} 
-                        label="Alpha remap gradients"
-                        docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
-                        onCreateRequired={() => {
-                            system.addAlphaRemapGradient(0, 1, 1);
-                            this.props.globalState.onCodeChangedObservable.notifyObservers({
-                                object: system,
-                                code: `TARGET.addAlphaRemapGradient(0, 1, 1);`
-                            });                            
-                        }}
-                        host={system}    
-                        codeRecorderPropertyName="getAlphaRemapGradients()"                             
-                        mode={GradientGridMode.Factor}                        
-                        lockObject={this.props.lockObject}/>                                    
+                    {
+                        system instanceof ParticleSystem && 
+                        <>
+                            <CheckBoxLineComponent label="Use ramp grandients" target={system} propertyName="useRampGradients"/>
+                            <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getRampGradients()!} 
+                                label="Ramp gradients"
+                                docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
+                                onCreateRequired={() => {
+                                    system.addRampGradient(0, Color3.White());
+                                    this.props.globalState.onCodeChangedObservable.notifyObservers({
+                                        object: system,
+                                        code: `TARGET.addRampGradient(0, BABYLON.Color3.White());`
+                                    });                               
+                                }}
+                                mode={GradientGridMode.Color3}      
+                                host={system}    
+                                codeRecorderPropertyName="getRampGradients()"                                                   
+                                lockObject={this.props.lockObject}/>                    
+                                                                    
+                            <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getColorRemapGradients()!} 
+                                label="Color remap gradients"
+                                docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
+                                onCreateRequired={() => {
+                                    system.addColorRemapGradient(0, 1, 1);
+                                    this.props.globalState.onCodeChangedObservable.notifyObservers({
+                                        object: system,
+                                        code: `TARGET.addColorRemapGradient(0, 1, 1);`
+                                    });
+                                }}
+                                host={system}    
+                                codeRecorderPropertyName="getColorRemapGradients()"      
+                                mode={GradientGridMode.Factor}                        
+                                lockObject={this.props.lockObject}/>                    
+                            <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getAlphaRemapGradients()!} 
+                                label="Alpha remap gradients"
+                                docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
+                                onCreateRequired={() => {
+                                    system.addAlphaRemapGradient(0, 1, 1);
+                                    this.props.globalState.onCodeChangedObservable.notifyObservers({
+                                        object: system,
+                                        code: `TARGET.addAlphaRemapGradient(0, 1, 1);`
+                                    });                            
+                                }}
+                                host={system}    
+                                codeRecorderPropertyName="getAlphaRemapGradients()"                             
+                                mode={GradientGridMode.Factor}                        
+                                lockObject={this.props.lockObject}/>
+                        </>
+                    }                                   
                 </LineContainerComponent>                     
                 <LineContainerComponent globalState={this.props.globalState} title="ROTATION">
                     <FloatLineComponent lockObject={this.props.lockObject} label="Min angular speed" target={system} propertyName="minAngularSpeed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />

+ 21 - 4
inspector/src/components/actionTabs/tabs/propertyGrids/particleSystems/valueGradientGridComponent.tsx

@@ -9,6 +9,7 @@ import { ColorGradientStepGridComponent } from './colorGradientStepGridComponent
 import { Color4, Color3 } from 'babylonjs/Maths/math.color';
 import { LinkButtonComponent } from '../../../lines/linkButtonComponent';
 import { IParticleSystem } from 'babylonjs/Particles/IParticleSystem';
+import { GPUParticleSystem } from 'babylonjs';
 
 export enum GradientGridMode {
     Factor,
@@ -43,6 +44,10 @@ export class ValueGradientGridComponent extends React.Component<IValueGradientGr
             gradients.splice(index, 1);
             this.forceUpdate();
 
+            if (this.props.host instanceof GPUParticleSystem) {
+                this.props.host.forceRefreshGradients();
+            }
+
             this.props.globalState.onCodeChangedObservable.notifyObservers({
                 object: this.props.host,
                 code: `TARGET.${this.props.codeRecorderPropertyName}.splice(${index}, 1);`
@@ -80,6 +85,10 @@ export class ValueGradientGridComponent extends React.Component<IValueGradientGr
                 break;              
         }
 
+        if (this.props.host instanceof GPUParticleSystem) {
+            this.props.host.forceRefreshGradients();
+        }
+
         this.forceUpdate();
     }
 
@@ -110,11 +119,19 @@ export class ValueGradientGridComponent extends React.Component<IValueGradientGr
     
                 return -1;
             });`
-        });
+        });        
 
         this.forceUpdate();
     }
 
+    updateAndSync() {
+        if (this.props.host instanceof GPUParticleSystem) {
+            this.props.host.forceRefreshGradients();
+        }
+        
+        this.forceUpdate();         
+    }
+
     render() {
         let gradients = this.props.gradients as Nullable<Array<IValueGradient>>;
       
@@ -134,7 +151,7 @@ export class ValueGradientGridComponent extends React.Component<IValueGradientGr
                                             <FactorGradientStepGridComponent globalState={this.props.globalState} 
                                                 lockObject={this.props.lockObject}
                                                 onCheckForReOrder={() => this.checkForReOrder()}
-                                                onUpdateGradient={() => this.forceUpdate()}
+                                                onUpdateGradient={() => this.updateAndSync()}
                                                 host={this.props.host}
                                                 codeRecorderPropertyName={codeRecorderPropertyName}
                                                 key={"step-" + i} lineIndex={i} gradient={g as FactorGradient} onDelete={() => this.deleteStep(g)}/>
@@ -147,7 +164,7 @@ export class ValueGradientGridComponent extends React.Component<IValueGradientGr
                                                 lockObject={this.props.lockObject}
                                                 isColor3={false}
                                                 onCheckForReOrder={() => this.checkForReOrder()}
-                                                onUpdateGradient={() => this.forceUpdate()}
+                                                onUpdateGradient={() => this.updateAndSync()}
                                                 key={"step-" + i} lineIndex={i} gradient={g as ColorGradient} onDelete={() => this.deleteStep(g)}/>
                                         );   
                                     case GradientGridMode.Color3:
@@ -158,7 +175,7 @@ export class ValueGradientGridComponent extends React.Component<IValueGradientGr
                                                 lockObject={this.props.lockObject}
                                                 isColor3={true}
                                                 onCheckForReOrder={() => this.checkForReOrder()}
-                                                onUpdateGradient={() => this.forceUpdate()}
+                                                onUpdateGradient={() => this.updateAndSync()}
                                                 key={"step-" + i} lineIndex={i} gradient={g as Color3Gradient} onDelete={() => this.deleteStep(g)}/>
                                         );                                      
                                 }

+ 60 - 48
src/Particles/gpuParticleSystem.ts

@@ -254,24 +254,43 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         let colorGradient = new ColorGradient(gradient, color1);
         this._colorGradients.push(colorGradient);
 
-        this._colorGradients.sort((a, b) => {
-            if (a.gradient < b.gradient) {
-                return -1;
-            } else if (a.gradient > b.gradient) {
-                return 1;
-            }
+        this._refreshColorGradient();
 
-            return 0;
-        });
+        this._releaseBuffers();
 
-        if (this._colorGradientsTexture) {
-            this._colorGradientsTexture.dispose();
-            (<any>this._colorGradientsTexture) = null;
+        return this;
+    }
+
+    private _refreshColorGradient() {
+        if (this._colorGradients) {
+            this._colorGradients.sort((a, b) => {
+                if (a.gradient < b.gradient) {
+                    return -1;
+                } else if (a.gradient > b.gradient) {
+                    return 1;
+                }
+
+                return 0;
+            });
+
+            if (this._colorGradientsTexture) {
+                this._colorGradientsTexture.dispose();
+                (<any>this._colorGradientsTexture) = null;
+            }
         }
+    }
 
-        this._releaseBuffers();
+    /** Force the system to rebuild all gradients */
+    public forceRefreshGradients() {
+        this._refreshColorGradient();  
+        this._refreshFactorGradient(this._sizeGradients, "_sizeGradientsTexture");
+        this._refreshFactorGradient(this._angularSpeedGradients, "_angularSpeedGradientsTexture");
+        this._refreshFactorGradient(this._velocityGradients, "_velocityGradientsTexture");
+        this._refreshFactorGradient(this._limitVelocityGradients, "_limitVelocityGradientsTexture");
+        this._refreshFactorGradient(this._dragGradients, "_dragGradientsTexture");
 
-        return this;
+        this._releaseBuffers();
+        this.reset();
     }
 
     /**
@@ -294,17 +313,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
 
     private _addFactorGradient(factorGradients: FactorGradient[], gradient: number, factor: number) {
         let valueGradient = new FactorGradient(gradient, factor);
-        factorGradients.push(valueGradient);
-
-        factorGradients.sort((a, b) => {
-            if (a.gradient < b.gradient) {
-                return -1;
-            } else if (a.gradient > b.gradient) {
-                return 1;
-            }
-
-            return 0;
-        });
+        factorGradients.push(valueGradient);      
 
         this._releaseBuffers();
     }
@@ -322,10 +331,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
 
         this._addFactorGradient(this._sizeGradients, gradient, factor);
 
-        if (this._sizeGradientsTexture) {
-            this._sizeGradientsTexture.dispose();
-            (<any>this._sizeGradientsTexture) = null;
-        }
+        this._refreshFactorGradient(this._sizeGradients, "_sizeGradientsTexture");
 
         this._releaseBuffers();
 
@@ -344,6 +350,28 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         return this;
     }
 
+    private _refreshFactorGradient(factorGradients: Nullable<FactorGradient[]>, textureName: string) {
+        if (!factorGradients) {
+            return;
+        }
+
+        factorGradients.sort((a, b) => {
+            if (a.gradient < b.gradient) {
+                return -1;
+            } else if (a.gradient > b.gradient) {
+                return 1;
+            }
+
+            return 0;
+        });
+        
+        let that = this as any;
+        if (that[textureName]) {
+            that[textureName].dispose();
+            that[textureName] = null;
+        }
+    }
+
     /**
      * Adds a new angular speed gradient
      * @param gradient defines the gradient to use (between 0 and 1)
@@ -356,11 +384,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         }
 
         this._addFactorGradient(this._angularSpeedGradients, gradient, factor);
-
-        if (this._angularSpeedGradientsTexture) {
-            this._angularSpeedGradientsTexture.dispose();
-            (<any>this._angularSpeedGradientsTexture) = null;
-        }
+        this._refreshFactorGradient(this._angularSpeedGradients, "_angularSpeedGradientsTexture");
 
         this._releaseBuffers();
 
@@ -391,11 +415,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         }
 
         this._addFactorGradient(this._velocityGradients, gradient, factor);
-
-        if (this._velocityGradientsTexture) {
-            this._velocityGradientsTexture.dispose();
-            (<any>this._velocityGradientsTexture) = null;
-        }
+        this._refreshFactorGradient(this._velocityGradients, "_velocityGradientsTexture");
 
         this._releaseBuffers();
 
@@ -426,11 +446,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         }
 
         this._addFactorGradient(this._limitVelocityGradients, gradient, factor);
-
-        if (this._limitVelocityGradientsTexture) {
-            this._limitVelocityGradientsTexture.dispose();
-            (<any>this._limitVelocityGradientsTexture) = null;
-        }
+        this._refreshFactorGradient(this._limitVelocityGradients, "_limitVelocityGradientsTexture");
 
         this._releaseBuffers();
 
@@ -461,11 +477,7 @@ export class GPUParticleSystem extends BaseParticleSystem implements IDisposable
         }
 
         this._addFactorGradient(this._dragGradients, gradient, factor);
-
-        if (this._dragGradientsTexture) {
-            this._dragGradientsTexture.dispose();
-            (<any>this._dragGradientsTexture) = null;
-        }
+        this._refreshFactorGradient(this._dragGradients, "_dragGradientsTexture");
 
         this._releaseBuffers();
 

+ 3 - 1
src/Particles/particleSystem.ts

@@ -2641,7 +2641,9 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
 
         ParticleSystem._Parse(parsedParticleSystem, particleSystem, scene, rootUrl);
 
-        particleSystem.textureMask = Color4.FromArray(parsedParticleSystem.textureMask);
+        if (parsedParticleSystem.textureMask) {
+            particleSystem.textureMask = Color4.FromArray(parsedParticleSystem.textureMask);
+        }
 
         // Auto start
         if (parsedParticleSystem.preventAutoStart) {