particleSystemPropertyGridComponent.tsx 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
  4. import { LineContainerComponent } from "../../../lineContainerComponent";
  5. import { TextLineComponent } from "../../../lines/textLineComponent";
  6. import { LockObject } from "../lockObject";
  7. import { GlobalState } from '../../../../globalState';
  8. import { CustomPropertyGridComponent } from '../customPropertyGridComponent';
  9. import { IParticleSystem } from 'babylonjs/Particles/IParticleSystem';
  10. import { FloatLineComponent } from '../../../lines/floatLineComponent';
  11. import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
  12. import { TextureLinkLineComponent } from '../../../lines/textureLinkLineComponent';
  13. import { OptionsLineComponent } from '../../../lines/optionsLineComponent';
  14. import { ParticleSystem } from 'babylonjs/Particles/particleSystem';
  15. import { Color4LineComponent } from '../../../lines/color4LineComponent';
  16. import { Vector3LineComponent } from '../../../lines/vector3LineComponent';
  17. import { CheckBoxLineComponent } from '../../../lines/checkBoxLineComponent';
  18. import { SliderLineComponent } from '../../../lines/sliderLineComponent';
  19. import { BoxParticleEmitter } from 'babylonjs/Particles/EmitterTypes/boxParticleEmitter';
  20. import { ConeParticleEmitter } from 'babylonjs/Particles/EmitterTypes/coneParticleEmitter';
  21. import { CylinderParticleEmitter } from 'babylonjs/Particles/EmitterTypes/cylinderParticleEmitter';
  22. import { HemisphericParticleEmitter } from 'babylonjs/Particles/EmitterTypes/hemisphericParticleEmitter';
  23. import { PointParticleEmitter } from 'babylonjs/Particles/EmitterTypes/pointParticleEmitter';
  24. import { SphereParticleEmitter } from 'babylonjs/Particles/EmitterTypes/sphereParticleEmitter';
  25. import { BoxEmitterGridComponent } from './boxEmitterGridComponent';
  26. import { ConeEmitterGridComponent } from './coneEmitterGridComponent';
  27. import { CylinderEmitterGridComponent } from './cylinderEmitterGridComponent';
  28. import { HemisphericEmitterGridComponent } from './hemisphericEmitterGridComponent';
  29. import { PointEmitterGridComponent } from './pointEmitterGridComponent';
  30. import { SphereEmitterGridComponent } from './sphereEmitterGridComponent';
  31. import { Vector3 } from 'babylonjs/Maths/math.vector';
  32. import { AbstractMesh } from 'babylonjs/Meshes/abstractMesh';
  33. import { MeshParticleEmitter } from 'babylonjs/Particles/EmitterTypes/meshParticleEmitter';
  34. import { MeshEmitterGridComponent } from './meshEmitterGridComponent';
  35. import { ValueGradientGridComponent, GradientGridMode } from './valueGradientGridComponent';
  36. import { Color3, Color4 } from 'babylonjs/Maths/math.color';
  37. import { GPUParticleSystem } from 'babylonjs/Particles/gpuParticleSystem';
  38. import { Tools } from 'babylonjs/Misc/tools';
  39. import { FileButtonLineComponent } from '../../../lines/fileButtonLineComponent';
  40. import { TextInputLineComponent } from '../../../lines/textInputLineComponent';
  41. interface IParticleSystemPropertyGridComponentProps {
  42. globalState: GlobalState;
  43. system: IParticleSystem,
  44. lockObject: LockObject,
  45. onSelectionChangedObservable?: Observable<any>,
  46. onPropertyChangedObservable?: Observable<PropertyChangedEvent>
  47. }
  48. export class ParticleSystemPropertyGridComponent extends React.Component<IParticleSystemPropertyGridComponentProps> {
  49. private _snippetUrl = "https://snippet.babylonjs.com";
  50. constructor(props: IParticleSystemPropertyGridComponentProps) {
  51. super(props);
  52. }
  53. renderEmitter() {
  54. const system = this.props.system;
  55. const replaySource = "particlesystem.particleEmitterType";
  56. switch(system.particleEmitterType?.getClassName()) {
  57. case "BoxParticleEmitter":
  58. return (
  59. <BoxEmitterGridComponent replaySourceReplacement={replaySource}
  60. globalState={this.props.globalState} emitter={system.particleEmitterType as BoxParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  61. );
  62. case "ConeParticleEmitter":
  63. return (
  64. <ConeEmitterGridComponent replaySourceReplacement={replaySource}
  65. globalState={this.props.globalState} emitter={system.particleEmitterType as ConeParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  66. );
  67. case "CylinderParticleEmitter":
  68. return (
  69. <CylinderEmitterGridComponent replaySourceReplacement={replaySource}
  70. lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as CylinderParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  71. );
  72. case "HemisphericParticleEmitter":
  73. return (
  74. <HemisphericEmitterGridComponent replaySourceReplacement={replaySource}
  75. lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as HemisphericParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  76. );
  77. case "MeshParticleEmitter":
  78. return (
  79. <MeshEmitterGridComponent replaySourceReplacement={replaySource}
  80. lockObject={this.props.lockObject} scene={system.getScene()} globalState={this.props.globalState} emitter={system.particleEmitterType as MeshParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  81. );
  82. case "PointParticleEmitter":
  83. return (
  84. <PointEmitterGridComponent replaySourceReplacement={replaySource}
  85. lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as PointParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  86. );
  87. case "SphereParticleEmitter":
  88. return (
  89. <SphereEmitterGridComponent replaySourceReplacement={replaySource}
  90. lockObject={this.props.lockObject} globalState={this.props.globalState} emitter={system.particleEmitterType as SphereParticleEmitter} onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  91. );
  92. }
  93. return null;
  94. }
  95. raiseOnPropertyChanged(property: string, newValue: any, previousValue: any) {
  96. if (!this.props.onPropertyChangedObservable) {
  97. return;
  98. }
  99. const system = this.props.system;
  100. this.props.onPropertyChangedObservable.notifyObservers({
  101. object: system,
  102. property: property,
  103. value: newValue,
  104. initialValue: previousValue
  105. });
  106. }
  107. renderControls() {
  108. const system = this.props.system;
  109. if (system instanceof GPUParticleSystem) {
  110. let isStarted = system.isStarted() && !system.isStopped();
  111. return (
  112. <ButtonLineComponent label={isStarted ? "Stop" : "Start"} onClick={() => {
  113. if (isStarted) {
  114. system.stop();
  115. system.reset();
  116. } else {
  117. system.start();
  118. }
  119. this.forceUpdate();
  120. }} />
  121. );
  122. }
  123. let isStarted = system.isStarted();
  124. return (
  125. <>
  126. {
  127. !system.isStopping() &&
  128. <ButtonLineComponent label={isStarted ? "Stop" : "Start"} onClick={() => {
  129. if (isStarted) {
  130. system.stop();
  131. } else {
  132. system.start();
  133. }
  134. this.forceUpdate();
  135. }} />
  136. }
  137. {
  138. system.isStopping() &&
  139. <TextLineComponent label="System is stoppping..." ignoreValue={true}/>
  140. }
  141. </>
  142. )
  143. }
  144. saveToFile() {
  145. const system = this.props.system;
  146. let content = JSON.stringify(system.serialize());
  147. Tools.Download(new Blob([content]), "particleSystem.json");
  148. }
  149. loadFromFile(file: File) {
  150. const system = this.props.system;
  151. const scene = system.getScene();
  152. Tools.ReadFile(file, (data) => {
  153. let decoder = new TextDecoder("utf-8");
  154. let jsonObject = JSON.parse(decoder.decode(data));
  155. let isGpu = system instanceof GPUParticleSystem
  156. system.dispose();
  157. this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
  158. let newSystem = isGpu ? GPUParticleSystem.Parse(jsonObject, scene, "") : ParticleSystem.Parse(jsonObject, scene, "");
  159. this.props.globalState.onSelectionChangedObservable.notifyObservers(newSystem);
  160. }, undefined, true);
  161. }
  162. saveToSnippet() {
  163. const system = this.props.system;
  164. let content = JSON.stringify(system.serialize());
  165. var xmlHttp = new XMLHttpRequest();
  166. xmlHttp.onreadystatechange = () => {
  167. if (xmlHttp.readyState == 4) {
  168. if (xmlHttp.status == 200) {
  169. var snippet = JSON.parse(xmlHttp.responseText);
  170. system.snippetId = snippet.id;
  171. this.forceUpdate();
  172. }
  173. else {
  174. alert("Unable to save your particle system");
  175. }
  176. }
  177. }
  178. xmlHttp.open("POST", this._snippetUrl + (system.snippetId ? "/" + system.snippetId : ""), true);
  179. xmlHttp.setRequestHeader("Content-Type", "application/json");
  180. var dataToSend = {
  181. payload : JSON.stringify({
  182. particleSystem: content
  183. }),
  184. name: "",
  185. description: "",
  186. tags: ""
  187. };
  188. xmlHttp.send(JSON.stringify(dataToSend));
  189. }
  190. render() {
  191. const system = this.props.system;
  192. var blendModeOptions = [
  193. { label: "Add", value: ParticleSystem.BLENDMODE_ADD },
  194. { label: "Multiply", value: ParticleSystem.BLENDMODE_MULTIPLY },
  195. { label: "Multiply Add", value: ParticleSystem.BLENDMODE_MULTIPLYADD },
  196. { label: "OneOne", value: ParticleSystem.BLENDMODE_ONEONE },
  197. { label: "Standard", value: ParticleSystem.BLENDMODE_STANDARD },
  198. ];
  199. var particleEmitterTypeOptions = [
  200. { label: "Box", value: 0 },
  201. { label: "Cone", value: 1 },
  202. { label: "Cylinder", value: 2 },
  203. { label: "Hemispheric", value: 3 },
  204. { label: "Mesh", value: 4 },
  205. { label: "Point", value: 5 },
  206. { label: "Sphere", value: 6 },
  207. ];
  208. var meshEmitters = this.props.system.getScene().meshes.filter(m => !!m.name);
  209. var emitterOptions = [
  210. { label: "None", value: -1 },
  211. { label: "Vector3", value: 0 }
  212. ];
  213. meshEmitters.sort((a, b) => a.name.localeCompare(b.name));
  214. emitterOptions.push(...meshEmitters.map((v, i) => {
  215. return {label: v.name, value: i + 1}
  216. }));
  217. return (
  218. <div className="pane">
  219. <CustomPropertyGridComponent globalState={this.props.globalState} target={system}
  220. lockObject={this.props.lockObject}
  221. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  222. <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
  223. <TextLineComponent label="ID" value={system.id} />
  224. <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={system} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  225. <TextLineComponent label="Class" value={system.getClassName()} />
  226. <TextLineComponent label="Capacity" value={system.getCapacity().toString()} />
  227. <TextLineComponent label="Active count" value={system.getActiveCount().toString()} />
  228. <TextureLinkLineComponent label="Texture" texture={system.particleTexture} onSelectionChangedObservable={this.props.onSelectionChangedObservable}/>
  229. <OptionsLineComponent label="Blend mode" options={blendModeOptions} target={system} propertyName="blendMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  230. <Vector3LineComponent label="Gravity" target={system} propertyName="gravity"
  231. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  232. <CheckBoxLineComponent label="Is billboard" target={system} propertyName="isBillboardBased" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  233. <CheckBoxLineComponent label="Is local" target={system} propertyName="isLocal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  234. <SliderLineComponent label="Update speed" target={system} propertyName="updateSpeed" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  235. </LineContainerComponent>
  236. <LineContainerComponent globalState={this.props.globalState} title="COMMANDS">
  237. {this.renderControls()}
  238. <ButtonLineComponent label={"Dispose"} onClick={() => {
  239. this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
  240. system.dispose();
  241. }} />
  242. </LineContainerComponent>
  243. <LineContainerComponent globalState={this.props.globalState} title="FILE">
  244. <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
  245. <ButtonLineComponent label="Save" onClick={() => this.saveToFile()} />
  246. {
  247. system.snippetId &&
  248. <TextLineComponent label="Snippet ID" value={system.snippetId} />
  249. }
  250. <ButtonLineComponent label="Save to snippet server" onClick={() => this.saveToSnippet()} />
  251. </LineContainerComponent>
  252. <LineContainerComponent globalState={this.props.globalState} title="EMITTER">
  253. <OptionsLineComponent
  254. label="Emitter"
  255. options={emitterOptions}
  256. target={system}
  257. propertyName="emitter"
  258. noDirectUpdate={true}
  259. onSelect={(value: number) => {
  260. switch(value) {
  261. case -1:
  262. this.raiseOnPropertyChanged("emitter", null, system.emitter);
  263. system.emitter = null;
  264. break;
  265. case 0:
  266. this.raiseOnPropertyChanged("emitter", Vector3.Zero(), system.emitter);
  267. system.emitter = Vector3.Zero();
  268. break;
  269. default:
  270. this.raiseOnPropertyChanged("emitter", meshEmitters[value - 1], system.emitter);
  271. system.emitter = meshEmitters[value - 1];
  272. }
  273. this.forceUpdate();
  274. }}
  275. extractValue={() => {
  276. if (!system.emitter) {
  277. return -1;
  278. }
  279. if ((system.emitter as Vector3).x !== undefined) {
  280. return 0;
  281. }
  282. let meshIndex = meshEmitters.indexOf(system.emitter as AbstractMesh)
  283. if (meshIndex > -1) {
  284. return meshIndex + 1;
  285. }
  286. return -1;
  287. }}
  288. />
  289. {
  290. system.emitter && ((system.emitter as Vector3).x === undefined) &&
  291. <TextLineComponent label="Link to emitter" value={(system.emitter as AbstractMesh).name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(system.emitter)}/>
  292. }
  293. {
  294. system.emitter && ((system.emitter as Vector3).x !== undefined) &&
  295. <Vector3LineComponent label="Position" target={system} propertyName="emitter" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  296. }
  297. <OptionsLineComponent
  298. label="Type"
  299. options={particleEmitterTypeOptions}
  300. target={system}
  301. propertyName="particleEmitterType"
  302. noDirectUpdate={true}
  303. onSelect={(value: number) => {
  304. const currentType = system.particleEmitterType;
  305. switch(value) {
  306. case 0:
  307. system.particleEmitterType = new BoxParticleEmitter();
  308. break;
  309. case 1:
  310. system.particleEmitterType = new ConeParticleEmitter();
  311. break;
  312. case 2:
  313. system.particleEmitterType = new CylinderParticleEmitter();
  314. break;
  315. case 3:
  316. system.particleEmitterType = new HemisphericParticleEmitter();
  317. break;
  318. case 4:
  319. system.particleEmitterType = new MeshParticleEmitter();
  320. break;
  321. case 5:
  322. system.particleEmitterType = new PointParticleEmitter();
  323. break;
  324. case 6:
  325. system.particleEmitterType = new SphereParticleEmitter();
  326. break;
  327. }
  328. this.raiseOnPropertyChanged("particleEmitterType", system.particleEmitterType, currentType)
  329. this.forceUpdate();
  330. }}
  331. extractValue={() => {
  332. switch(system.particleEmitterType?.getClassName()) {
  333. case "BoxParticleEmitter":
  334. return 0;
  335. case "ConeParticleEmitter":
  336. return 1;
  337. case "CylinderParticleEmitter":
  338. return 2;
  339. case "HemisphericParticleEmitter":
  340. return 3;
  341. case "MeshParticleEmitter":
  342. return 4;
  343. case "PointParticleEmitter":
  344. return 5;
  345. case "SphereParticleEmitter":
  346. return 6;
  347. }
  348. return 0;
  349. }}/>
  350. {
  351. this.renderEmitter()
  352. }
  353. </LineContainerComponent>
  354. <LineContainerComponent globalState={this.props.globalState} title="EMISSION">
  355. <FloatLineComponent lockObject={this.props.lockObject} label="Rate" target={system} propertyName="emitRate" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  356. {
  357. system instanceof ParticleSystem &&
  358. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getEmitRateGradients()!}
  359. label="Velocity gradients"
  360. docLink="https://doc.babylonjs.com/babylon101/particles#emit-rate-over-time"
  361. onCreateRequired={() => {
  362. system.addEmitRateGradient(0, 50, 50);
  363. this.props.globalState.onCodeChangedObservable.notifyObservers({
  364. object: system,
  365. code: `TARGET.addEmitRateGradient(0, 50, 50);`
  366. });
  367. }}
  368. mode={GradientGridMode.Factor}
  369. host={system}
  370. codeRecorderPropertyName="getEmitRateGradients()"
  371. lockObject={this.props.lockObject}/>
  372. }
  373. <FloatLineComponent lockObject={this.props.lockObject} label="Min emit power" target={system} propertyName="minEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  374. <FloatLineComponent lockObject={this.props.lockObject} label="Max emit power" target={system} propertyName="maxEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  375. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getVelocityGradients()!}
  376. label="Velocity gradients"
  377. docLink="https://doc.babylonjs.com/babylon101/particles#velocity-over-time"
  378. onCreateRequired={() => {
  379. system.addVelocityGradient(0, 0.1, 0.1);
  380. this.props.globalState.onCodeChangedObservable.notifyObservers({
  381. object: system,
  382. code: `TARGET.addVelocityGradient(0, 0.1, 0.1);`
  383. });
  384. }}
  385. mode={GradientGridMode.Factor}
  386. host={system}
  387. codeRecorderPropertyName="getVelocityGradients()"
  388. lockObject={this.props.lockObject}/>
  389. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getLimitVelocityGradients()!}
  390. label="Limit velocity gradients"
  391. docLink="https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time"
  392. onCreateRequired={() => {
  393. system.addLimitVelocityGradient(0, 0.1, 0.1);
  394. this.props.globalState.onCodeChangedObservable.notifyObservers({
  395. object: system,
  396. code: `TARGET.addLimitVelocityGradient(0, 0.1, 0.1);`
  397. });
  398. }}
  399. mode={GradientGridMode.Factor}
  400. host={system}
  401. codeRecorderPropertyName="getLimitVelocityGradients()"
  402. lockObject={this.props.lockObject}/>
  403. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getDragGradients()!}
  404. label="Drag gradients"
  405. docLink="https://doc.babylonjs.com/babylon101/particles#drag-factor"
  406. onCreateRequired={() => {
  407. system.addDragGradient(0, 0.1, 0.1);
  408. this.props.globalState.onCodeChangedObservable.notifyObservers({
  409. object: system,
  410. code: `TARGET.addDragGradient(0, 0.1, 0.1);`
  411. });
  412. }}
  413. host={system}
  414. codeRecorderPropertyName="getDragGradients()"
  415. mode={GradientGridMode.Factor}
  416. lockObject={this.props.lockObject}/>
  417. </LineContainerComponent>
  418. <LineContainerComponent globalState={this.props.globalState} title="SIZE">
  419. <FloatLineComponent lockObject={this.props.lockObject} label="Min size" target={system} propertyName="minSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  420. <FloatLineComponent lockObject={this.props.lockObject} label="Max size" target={system} propertyName="maxSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  421. <FloatLineComponent lockObject={this.props.lockObject} label="Min scale X" target={system} propertyName="minScaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  422. <FloatLineComponent lockObject={this.props.lockObject} label="Max scale X" target={system} propertyName="maxScaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  423. <FloatLineComponent lockObject={this.props.lockObject} label="Min scale Y" target={system} propertyName="minScaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  424. <FloatLineComponent lockObject={this.props.lockObject} label="Max scale Y" target={system} propertyName="maxScaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  425. {
  426. system instanceof ParticleSystem &&
  427. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getStartSizeGradients()!}
  428. label="Start size gradients"
  429. docLink="https://doc.babylonjs.com/babylon101/particles#start-size-over-time"
  430. onCreateRequired={() => {
  431. system.addStartSizeGradient(0, 1, 1);
  432. this.props.globalState.onCodeChangedObservable.notifyObservers({
  433. object: system,
  434. code: `TARGET.addStartSizeGradient(0, 1, 1);`
  435. });
  436. }}
  437. host={system}
  438. codeRecorderPropertyName="getStartSizeGradients()"
  439. mode={GradientGridMode.Factor}
  440. lockObject={this.props.lockObject}/>
  441. }
  442. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getSizeGradients()!}
  443. label="Size gradients"
  444. docLink="https://doc.babylonjs.com/babylon101/particles#size"
  445. onCreateRequired={() => {
  446. system.addSizeGradient(0, 1, 1);
  447. this.props.globalState.onCodeChangedObservable.notifyObservers({
  448. object: system,
  449. code: `TARGET.addSizeGradient(0, 1, 1);`
  450. });
  451. }}
  452. host={system}
  453. codeRecorderPropertyName="getSizeGradients()"
  454. mode={GradientGridMode.Factor}
  455. lockObject={this.props.lockObject}/>
  456. </LineContainerComponent>
  457. <LineContainerComponent globalState={this.props.globalState} title="LIFETIME">
  458. <FloatLineComponent lockObject={this.props.lockObject} label="Min lifetime" target={system} propertyName="minLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  459. <FloatLineComponent lockObject={this.props.lockObject} label="Max lifetime" target={system} propertyName="maxLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  460. <FloatLineComponent lockObject={this.props.lockObject} label="Target stop duration" target={system} propertyName="targetStopDuration" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  461. {
  462. system instanceof ParticleSystem &&
  463. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getLifeTimeGradients()!}
  464. label="Lifetime gradients"
  465. docLink="https://doc.babylonjs.com/babylon101/particles#lifetime"
  466. onCreateRequired={() => {
  467. system.addLifeTimeGradient(0, 1, 1);
  468. this.props.globalState.onCodeChangedObservable.notifyObservers({
  469. object: system,
  470. code: `TARGET.addLifeTimeGradient(0, 1, 1);`
  471. });
  472. }}
  473. host={system}
  474. codeRecorderPropertyName="getLifeTimeGradients()"
  475. mode={GradientGridMode.Factor}
  476. lockObject={this.props.lockObject}/>
  477. }
  478. </LineContainerComponent>
  479. <LineContainerComponent globalState={this.props.globalState} title="COLORS">
  480. <Color4LineComponent label="Color 1" target={system} propertyName="color1"
  481. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  482. <Color4LineComponent label="Color 2" target={system} propertyName="color2"
  483. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  484. <Color4LineComponent label="Color dead" target={system} propertyName="colorDead"
  485. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  486. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getColorGradients()!}
  487. label="Color gradients"
  488. docLink="https://doc.babylonjs.com/babylon101/particles#particle-colors"
  489. onCreateRequired={() => {
  490. system.addColorGradient(0, new Color4(0, 0, 0, 1), new Color4(0, 0, 0, 1));
  491. system.addColorGradient(1, new Color4(1, 1, 1, 1), new Color4(1, 1, 1, 1));
  492. this.props.globalState.onCodeChangedObservable.notifyObservers({
  493. object: system,
  494. code: `TARGET.addColorGradient(0, new BABYLON.Color4(0, 0, 0, 1), new BABYLON.Color4(0, 0, 0, 1));`
  495. });
  496. this.props.globalState.onCodeChangedObservable.notifyObservers({
  497. object: system,
  498. code: `TARGET.addColorGradient(1, new BABYLON.Color4(1, 1, 1, 1), new BABYLON.Color4(1, 1, 1, 1));`
  499. });
  500. }}
  501. host={system}
  502. codeRecorderPropertyName="getColorGradients()"
  503. mode={GradientGridMode.Color4}
  504. lockObject={this.props.lockObject}/>
  505. {
  506. system instanceof ParticleSystem &&
  507. <>
  508. <CheckBoxLineComponent label="Use ramp grandients" target={system} propertyName="useRampGradients"/>
  509. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getRampGradients()!}
  510. label="Ramp gradients"
  511. docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
  512. onCreateRequired={() => {
  513. system.addRampGradient(0, Color3.White());
  514. system.addRampGradient(1, Color3.Black());
  515. this.props.globalState.onCodeChangedObservable.notifyObservers({
  516. object: system,
  517. code: `TARGET.addRampGradient(0, BABYLON.Color3.White());`
  518. });
  519. this.props.globalState.onCodeChangedObservable.notifyObservers({
  520. object: system,
  521. code: `TARGET.addRampGradient(1, BABYLON.Color3.Black());`
  522. });
  523. }}
  524. mode={GradientGridMode.Color3}
  525. host={system}
  526. codeRecorderPropertyName="getRampGradients()"
  527. lockObject={this.props.lockObject}/>
  528. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getColorRemapGradients()!}
  529. label="Color remap gradients"
  530. docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
  531. onCreateRequired={() => {
  532. system.addColorRemapGradient(0, 1, 1);
  533. this.props.globalState.onCodeChangedObservable.notifyObservers({
  534. object: system,
  535. code: `TARGET.addColorRemapGradient(0, 1, 1);`
  536. });
  537. }}
  538. host={system}
  539. codeRecorderPropertyName="getColorRemapGradients()"
  540. mode={GradientGridMode.Factor}
  541. lockObject={this.props.lockObject}/>
  542. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getAlphaRemapGradients()!}
  543. label="Alpha remap gradients"
  544. docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
  545. onCreateRequired={() => {
  546. system.addAlphaRemapGradient(0, 1, 1);
  547. this.props.globalState.onCodeChangedObservable.notifyObservers({
  548. object: system,
  549. code: `TARGET.addAlphaRemapGradient(0, 1, 1);`
  550. });
  551. }}
  552. host={system}
  553. codeRecorderPropertyName="getAlphaRemapGradients()"
  554. mode={GradientGridMode.Factor}
  555. lockObject={this.props.lockObject}/>
  556. </>
  557. }
  558. </LineContainerComponent>
  559. <LineContainerComponent globalState={this.props.globalState} title="ROTATION">
  560. <FloatLineComponent lockObject={this.props.lockObject} label="Min angular speed" target={system} propertyName="minAngularSpeed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  561. <FloatLineComponent lockObject={this.props.lockObject} label="Max angular speed" target={system} propertyName="maxAngularSpeed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  562. <FloatLineComponent lockObject={this.props.lockObject} label="Min initial rotation" target={system} propertyName="minInitialRotation" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  563. <FloatLineComponent lockObject={this.props.lockObject} label="Max initial rotation" target={system} propertyName="maxInitialRotation" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  564. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getAngularSpeedGradients()!}
  565. label="Angular speed gradients"
  566. docLink="hhttps://doc.babylonjs.com/babylon101/particles#rotation"
  567. onCreateRequired={() => {
  568. system.addAngularSpeedGradient(0, 0.1, 0.1);
  569. this.props.globalState.onCodeChangedObservable.notifyObservers({
  570. object: system,
  571. code: `TARGET.addAngularSpeedGradient(0, 0.1, 0.1);`
  572. });
  573. }}
  574. host={system}
  575. codeRecorderPropertyName="getAngularSpeedGradients()"
  576. mode={GradientGridMode.Factor}
  577. lockObject={this.props.lockObject}/>
  578. </LineContainerComponent>
  579. </div>
  580. );
  581. }
  582. }