Prechádzať zdrojové kódy

Add some particle systems to the preview list

Popov72 5 rokov pred
rodič
commit
8d889ab47f

+ 84 - 31
nodeEditor/src/components/preview/previewManager.ts

@@ -23,7 +23,11 @@ import { Constants } from 'babylonjs/Engines/constants';
 import { CurrentScreenBlock } from 'babylonjs/Materials/Node/Blocks/Dual/currentScreenBlock';
 import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
 import { ParticleSystem } from 'babylonjs/Particles/particleSystem';
+import { ParticleHelper } from 'babylonjs/Particles/particleHelper';
 import { Texture } from 'babylonjs/Materials/Textures/texture';
+import { ParticleTextureBlock } from 'babylonjs/Materials/Node/Blocks/Particle/particleTextureBlock';
+import { Effect } from 'babylonjs/Materials/effect';
+import { FileTools } from 'babylonjs/Misc/fileTools';
 
 export class PreviewManager {
     private _nodeMaterial: NodeMaterial;
@@ -45,10 +49,12 @@ export class PreviewManager {
     private _lightParent: TransformNode;
     private _postprocess: Nullable<PostProcess>;
     private _particleSystem: Nullable<ParticleSystem>;
+    private _particleSystemDrawObserver: Nullable<Observer<Effect>>;
 
     public constructor(targetCanvas: HTMLCanvasElement, globalState: GlobalState) {
         this._nodeMaterial = globalState.nodeMaterial;
         this._globalState = globalState;
+        this._particleSystemDrawObserver = null;
 
         this._onBuildObserver = this._nodeMaterial.onBuildObservable.add((nodeMaterial) => {
             let serializationObject = nodeMaterial.serialize();
@@ -233,7 +239,7 @@ export class PreviewManager {
     }
 
     private _refreshPreviewMesh() {
-
+        console.log("_refreshPreviewMesh", this._currentType, this._globalState.previewMeshType)
         if (this._currentType !== this._globalState.previewMeshType || this._currentType === PreviewMeshType.Custom) {
             this._currentType = this._globalState.previewMeshType;
             if (this._meshes && this._meshes.length) {
@@ -250,6 +256,17 @@ export class PreviewManager {
 
             this._engine.releaseEffects();
 
+            if (this._particleSystem) {
+                if (this._particleSystemDrawObserver) {
+                    this._particleSystem.onBeforeDrawParticlesObservable.remove(this._particleSystemDrawObserver);
+                }
+                this._particleSystem.customEffect = null;
+                this._particleSystem.stop();
+                this._particleSystem.dispose();
+                this._particleSystem = null;
+                this._particleSystemDrawObserver = null;
+            }
+
             SceneLoader.ShowLoadingScreen = false;
 
             this._globalState.onIsLoadingChanged.notifyObservers(true);
@@ -293,17 +310,72 @@ export class PreviewManager {
                         });
                         return;
                 }
+            } else if (this._globalState.mode === NodeMaterialModes.Particle) {
+                switch (this._globalState.previewMeshType) {
+                    case PreviewMeshType.DefaultParticle:
+                        this._particleSystem = new ParticleSystem("particles", 4000, this._scene);
+                        this._particleSystem.particleTexture = new Texture("https://assets.babylonjs.com/particles/textures/explosion/Flare.png", this._scene);
+                        this._particleSystem.minSize = 0.1;
+                        this._particleSystem.maxSize = 1.0;
+                        this._particleSystem.minLifeTime = 0.5;
+                        this._particleSystem.maxLifeTime = 5.0;
+                        this._particleSystem.minEmitPower = 0.5;
+                        this._particleSystem.maxEmitPower = 3.0;
+                        this._particleSystem.createBoxEmitter(new Vector3(-1, 1, -1), new Vector3(1, 1, 1), new Vector3(-0.1, -0.1, -0.1), new Vector3(0.1, 0.1, 0.1));
+                        this._particleSystem.emitRate = 100;
+                        this._particleSystem.blendMode = ParticleSystem.BLENDMODE_ONEONE;
+                        this._particleSystem.color1 = new Color4(1, 1, 0, 1);
+                        this._particleSystem.color2 = new Color4(1, 0.5, 0, 1);
+                        this._particleSystem.gravity = new Vector3(0, -1.0, 0);
+                        this._particleSystem.start();
+
+                        console.log(JSON.stringify(this._particleSystem.serialize(false)));
+                        break;
+                    case PreviewMeshType.Explosion:
+                        this._loadParticleSystem("explosion");
+                        return;
+                    case PreviewMeshType.Fire:
+                        this._loadParticleSystem("fire");
+                        return;
+                    case PreviewMeshType.Rain:
+                        this._loadParticleSystem("rain");
+                        return;
+                    case PreviewMeshType.Smoke:
+                        this._loadParticleSystem("smoke");
+                        return;
+                    case PreviewMeshType.Custom:
+                        FileTools.ReadFile(this._globalState.previewMeshFile, (json) =>  {
+                            this._particleSystem = ParticleSystem.Parse(JSON.parse(json), this._scene, "");
+                            this._particleSystem.start();
+                            this._prepareMeshes();
+                        }, undefined, false, (error) => {
+                            console.log(error);
+                        });
+                        return;
+                }
             }
 
             this._prepareMeshes();
         }
     }
 
+    private _loadParticleSystem(name: string) {
+        ParticleHelper.CreateAsync(name, this._scene).then((set) => {
+            for (let i = 1; i < set.systems.length; ++i) {
+                set.systems[i].dispose();
+            }
+            this._particleSystem = set.systems[0] as ParticleSystem;
+            this._particleSystem.start();
+            this._prepareMeshes();
+        });
+    }
+
     private _forceCompilationAsync(material: NodeMaterial, mesh: AbstractMesh): Promise<void> {
         return material.forceCompilationAsync(mesh);
     }
 
     private _updatePreview(serializationObject: any) {
+        console.log("_updatePreview", this._currentType, this._globalState.previewMeshType, this._globalState.mode);
         try {
             let tempMaterial = NodeMaterial.Parse(serializationObject, this._scene);
 
@@ -315,12 +387,6 @@ export class PreviewManager {
                 this._postprocess = null;
             }
 
-            if (this._particleSystem) {
-                this._particleSystem.stop();
-                this._particleSystem.dispose();
-                this._particleSystem = null;
-            }
-
             switch (this._globalState.mode) {
                 case NodeMaterialModes.PostProcess: {
                     this._globalState.onIsLoadingChanged.notifyObservers(false);
@@ -345,32 +411,19 @@ export class PreviewManager {
                     this._globalState.onIsLoadingChanged.notifyObservers(false);
 
                     (window as any).ss = this._scene;
+                    (window as any).ps = this._particleSystem;
 
-                    // Effect
-                    this._particleSystem = new ParticleSystem("particles", 4000, this._scene);
-
-                    const emitter0 = Mesh.CreateBox("emitter0", 0.1, this._scene);
-                    emitter0.isVisible = false;
-
-                    this._meshes.push(emitter0);
-
-                    this._particleSystem.particleTexture = new Texture("https://assets.babylonjs.com/particles/textures/explosion/Flare.png", this._scene);
-                    this._particleSystem.minSize = 0.1;
-                    this._particleSystem.maxSize = 1.0;
-                    this._particleSystem.minLifeTime = 0.5;
-                    this._particleSystem.maxLifeTime = 5.0;
-                    this._particleSystem.minEmitPower = 0.5;
-                    this._particleSystem.maxEmitPower = 3.0;
-                    this._particleSystem.emitter = emitter0;
-                    this._particleSystem.emitRate = 100;
-                    this._particleSystem.blendMode = ParticleSystem.BLENDMODE_ONEONE;
-                    this._particleSystem.direction1 = new Vector3(-1, 1, -1);
-                    this._particleSystem.direction2 = new Vector3(1, 1, 1);
-                    this._particleSystem.color1 = new Color4(1, 1, 0, 1);
-                    this._particleSystem.color2 = new Color4(1, 0.5, 0, 1);
-                    this._particleSystem.gravity = new Vector3(0, -1.0, 0);
-                    this._particleSystem.start();
+                    if (this._particleSystemDrawObserver) {
+                        this._particleSystem.onBeforeDrawParticlesObservable.remove(this._particleSystemDrawObserver);
+                    }
 
+                    this._particleSystemDrawObserver = this._particleSystem.onBeforeDrawParticlesObservable.add((effect) => {
+                        const textureBlock = tempMaterial.getBlockByPredicate((block) => block instanceof ParticleTextureBlock);
+                        if (textureBlock && (textureBlock as ParticleTextureBlock).texture) {
+                            effect.setTexture("diffuseSampler", (textureBlock as ParticleTextureBlock).texture);
+                        }
+                    });
+                    console.log("create effect for particles", tempMaterial);
                     tempMaterial.createEffectForParticles(this._particleSystem);
                     break;
                 }

+ 21 - 3
nodeEditor/src/components/preview/previewMeshControlComponent.tsx

@@ -104,16 +104,32 @@ export class PreviewMeshControlComponent extends React.Component<IPreviewMeshCon
             { label: "Load...", value: PreviewMeshType.Custom + 1 }
         ];
 
+        var particleTypeOptions = [
+            { label: "Default particle system", value: PreviewMeshType.DefaultParticle },
+            { label: "Explosion", value: PreviewMeshType.Explosion },
+            { label: "Fire", value: PreviewMeshType.Fire },
+            { label: "Rain", value: PreviewMeshType.Rain },
+            { label: "Smoke", value: PreviewMeshType.Smoke },
+            { label: "Load...", value: PreviewMeshType.Custom + 1 }
+        ];
+
         if (this.props.globalState.listOfCustomPreviewMeshFiles.length > 0) {
             meshTypeOptions.splice(0, 0, {
                 label: "Custom", value: PreviewMeshType.Custom
             });
+
+            particleTypeOptions.splice(0, 0, {
+                label: "Custom", value: PreviewMeshType.Custom
+            });
         }
 
+        var options = this.props.globalState.mode === NodeMaterialModes.Particle ? particleTypeOptions : meshTypeOptions;
+        var accept = this.props.globalState.mode === NodeMaterialModes.Particle ? ".json" : ".gltf, .glb, .babylon, .obj";
+
         return (
             <div id="preview-mesh-bar">
-                { this.props.globalState.mode === NodeMaterialModes.Material && <>
-                    <OptionsLineComponent label="" options={meshTypeOptions} target={this.props.globalState}
+                { (this.props.globalState.mode === NodeMaterialModes.Material || this.props.globalState.mode === NodeMaterialModes.Particle) && <>
+                    <OptionsLineComponent label="" options={options} target={this.props.globalState}
                                 propertyName="previewMeshType"
                                 noDirectUpdate={true}
                                 onSelect={(value: any) => {
@@ -126,8 +142,10 @@ export class PreviewMeshControlComponent extends React.Component<IPreviewMeshCon
                     <div style={{
                         display: "none"
                     }} title="Preview with a custom mesh" >
-                        <input ref={this.filePickerRef} id="file-picker" type="file" onChange={(evt) => this.useCustomMesh(evt)} accept=".gltf, .glb, .babylon, .obj"/>
+                        <input ref={this.filePickerRef} id="file-picker" type="file" onChange={(evt) => this.useCustomMesh(evt)} accept={accept}/>
                     </div>
+                </> }
+                { this.props.globalState.mode === NodeMaterialModes.Material && <>
                     <div
                         title="Turn-table animation"
                         onClick={() => this.changeAnimation()} className="button" id="play-button">

+ 6 - 1
nodeEditor/src/components/preview/previewMeshType.ts

@@ -5,5 +5,10 @@ export enum PreviewMeshType {
     Cylinder,
     Plane,
     ShaderBall,
-    Custom
+    DefaultParticle,
+    Smoke,
+    Rain,
+    Explosion,
+    Fire,
+    Custom,
 }

+ 10 - 2
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -33,6 +33,7 @@ import { NodePort } from '../../diagram/nodePort';
 import { isFramePortData } from '../../diagram/graphCanvas';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
+import { PreviewMeshType } from '../preview/previewMeshType';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
@@ -263,22 +264,29 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             this._modeSelect.current?.setValue(value);
         }
 
-        this.props.globalState.mode = value as NodeMaterialModes;
-
         if (loadDefault) {
             switch (value) {
                 case NodeMaterialModes.Material:
+                    this.props.globalState.previewMeshType = PreviewMeshType.Sphere;
                     this.props.globalState.nodeMaterial!.setToDefault();
                     break;
                 case NodeMaterialModes.PostProcess:
                     this.props.globalState.nodeMaterial!.setToDefaultPostProcess();
                     break;
                 case NodeMaterialModes.Particle:
+                    this.props.globalState.previewMeshType = PreviewMeshType.DefaultParticle;
                     this.props.globalState.nodeMaterial!.setToDefaultParticle();
                     break;
             }
+
+            this.props.globalState.listOfCustomPreviewMeshFiles = [];
+            (this.props.globalState.previewMeshFile as any) = undefined;
+
+            DataStorage.WriteNumber("PreviewMeshType", this.props.globalState.previewMeshType);
         }
 
+        this.props.globalState.mode = value as NodeMaterialModes;
+
         this.props.globalState.onResetRequiredObservable.notifyObservers();
     }
 

+ 2 - 1
nodeEditor/src/nodeEditor.ts

@@ -8,6 +8,7 @@ import { SerializationTools } from './serializationTools';
 import { Observable } from 'babylonjs/Misc/observable';
 import { PreviewMeshType } from './components/preview/previewMeshType';
 import { DataStorage } from 'babylonjs/Misc/dataStorage';
+import { NodeMaterialModes } from 'babylonjs/Materials/Node/Enums/nodeMaterialModes';
 /**
  * Interface used to specify creation options for the node editor
  */
@@ -83,7 +84,7 @@ export class NodeEditor {
         }
         window.addEventListener('beforeunload', () => {
             if(DataStorage.ReadNumber("PreviewMeshType", PreviewMeshType.Box) === PreviewMeshType.Custom){
-                DataStorage.WriteNumber("PreviewMeshType", PreviewMeshType.Box)
+                DataStorage.WriteNumber("PreviewMeshType", globalState.mode === NodeMaterialModes.Material ? PreviewMeshType.Box : PreviewMeshType.DefaultParticle);
             }
         });
     }