particleSystemPropertyGridComponent.tsx 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  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 baseUrl = location.href.replace(location.hash, "").replace(location.search, "");
  170. var snippet = JSON.parse(xmlHttp.responseText);
  171. var newUrl = baseUrl + "#" + snippet.id;
  172. system.snippetId = snippet.id;
  173. if (snippet.version && snippet.version != "0") {
  174. newUrl += "#" + snippet.version;
  175. }
  176. this.forceUpdate();
  177. }
  178. else {
  179. alert("Unable to save your particle system");
  180. }
  181. }
  182. }
  183. xmlHttp.open("POST", this._snippetUrl + (system.snippetId ? "/" + system.snippetId : ""), true);
  184. xmlHttp.setRequestHeader("Content-Type", "application/json");
  185. var dataToSend = {
  186. payload : JSON.stringify({
  187. particleSystem: content
  188. }),
  189. name: "",
  190. description: "",
  191. tags: ""
  192. };
  193. xmlHttp.send(JSON.stringify(dataToSend));
  194. }
  195. render() {
  196. const system = this.props.system;
  197. var blendModeOptions = [
  198. { label: "Add", value: ParticleSystem.BLENDMODE_ADD },
  199. { label: "Multiply", value: ParticleSystem.BLENDMODE_MULTIPLY },
  200. { label: "Multiply Add", value: ParticleSystem.BLENDMODE_MULTIPLYADD },
  201. { label: "OneOne", value: ParticleSystem.BLENDMODE_ONEONE },
  202. { label: "Standard", value: ParticleSystem.BLENDMODE_STANDARD },
  203. ];
  204. var particleEmitterTypeOptions = [
  205. { label: "Box", value: 0 },
  206. { label: "Cone", value: 1 },
  207. { label: "Cylinder", value: 2 },
  208. { label: "Hemispheric", value: 3 },
  209. { label: "Mesh", value: 4 },
  210. { label: "Point", value: 5 },
  211. { label: "Sphere", value: 6 },
  212. ];
  213. var meshEmitters = this.props.system.getScene().meshes.filter(m => !!m.name);
  214. var emitterOptions = [
  215. { label: "None", value: -1 },
  216. { label: "Vector3", value: 0 }
  217. ];
  218. meshEmitters.sort((a, b) => a.name.localeCompare(b.name));
  219. emitterOptions.push(...meshEmitters.map((v, i) => {
  220. return {label: v.name, value: i + 1}
  221. }));
  222. return (
  223. <div className="pane">
  224. <CustomPropertyGridComponent globalState={this.props.globalState} target={system}
  225. lockObject={this.props.lockObject}
  226. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  227. <LineContainerComponent globalState={this.props.globalState} title="GENERAL">
  228. <TextLineComponent label="ID" value={system.id} />
  229. <TextInputLineComponent lockObject={this.props.lockObject} label="Name" target={system} propertyName="name" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  230. {
  231. system.snippetId &&
  232. <TextLineComponent label="Snippet ID" value={system.snippetId} />
  233. }
  234. <TextLineComponent label="Class" value={system.getClassName()} />
  235. <TextLineComponent label="Capacity" value={system.getCapacity().toString()} />
  236. <TextLineComponent label="Active count" value={system.getActiveCount().toString()} />
  237. <TextureLinkLineComponent label="Texture" texture={system.particleTexture} onSelectionChangedObservable={this.props.onSelectionChangedObservable}/>
  238. <OptionsLineComponent label="Blend mode" options={blendModeOptions} target={system} propertyName="blendMode" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  239. <Vector3LineComponent label="Gravity" target={system} propertyName="gravity"
  240. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  241. <CheckBoxLineComponent label="Is billboard" target={system} propertyName="isBillboardBased" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  242. <CheckBoxLineComponent label="Is local" target={system} propertyName="isLocal" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  243. <SliderLineComponent label="Update speed" target={system} propertyName="updateSpeed" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  244. </LineContainerComponent>
  245. <LineContainerComponent globalState={this.props.globalState} title="COMMANDS">
  246. {this.renderControls()}
  247. <ButtonLineComponent label={"Dispose"} onClick={() => {
  248. this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
  249. system.dispose();
  250. }} />
  251. </LineContainerComponent>
  252. <LineContainerComponent globalState={this.props.globalState} title="FILE">
  253. <FileButtonLineComponent label="Load" onClick={(file) => this.loadFromFile(file)} accept=".json" />
  254. <ButtonLineComponent label="Save" onClick={() => this.saveToFile()} />
  255. <ButtonLineComponent label="Save to snippet server" onClick={() => this.saveToSnippet()} />
  256. </LineContainerComponent>
  257. <LineContainerComponent globalState={this.props.globalState} title="EMITTER">
  258. <OptionsLineComponent
  259. label="Emitter"
  260. options={emitterOptions}
  261. target={system}
  262. propertyName="emitter"
  263. noDirectUpdate={true}
  264. onSelect={(value: number) => {
  265. switch(value) {
  266. case -1:
  267. this.raiseOnPropertyChanged("emitter", null, system.emitter);
  268. system.emitter = null;
  269. break;
  270. case 0:
  271. this.raiseOnPropertyChanged("emitter", Vector3.Zero(), system.emitter);
  272. system.emitter = Vector3.Zero();
  273. break;
  274. default:
  275. this.raiseOnPropertyChanged("emitter", meshEmitters[value - 1], system.emitter);
  276. system.emitter = meshEmitters[value - 1];
  277. }
  278. this.forceUpdate();
  279. }}
  280. extractValue={() => {
  281. if (!system.emitter) {
  282. return -1;
  283. }
  284. if ((system.emitter as Vector3).x !== undefined) {
  285. return 0;
  286. }
  287. let meshIndex = meshEmitters.indexOf(system.emitter as AbstractMesh)
  288. if (meshIndex > -1) {
  289. return meshIndex + 1;
  290. }
  291. return -1;
  292. }}
  293. />
  294. {
  295. system.emitter && ((system.emitter as Vector3).x === undefined) &&
  296. <TextLineComponent label="Link to emitter" value={(system.emitter as AbstractMesh).name} onLink={() => this.props.globalState.onSelectionChangedObservable.notifyObservers(system.emitter)}/>
  297. }
  298. {
  299. system.emitter && ((system.emitter as Vector3).x !== undefined) &&
  300. <Vector3LineComponent label="Position" target={system} propertyName="emitter" onPropertyChangedObservable={this.props.onPropertyChangedObservable}/>
  301. }
  302. <OptionsLineComponent
  303. label="Type"
  304. options={particleEmitterTypeOptions}
  305. target={system}
  306. propertyName="particleEmitterType"
  307. noDirectUpdate={true}
  308. onSelect={(value: number) => {
  309. const currentType = system.particleEmitterType;
  310. switch(value) {
  311. case 0:
  312. system.particleEmitterType = new BoxParticleEmitter();
  313. break;
  314. case 1:
  315. system.particleEmitterType = new ConeParticleEmitter();
  316. break;
  317. case 2:
  318. system.particleEmitterType = new CylinderParticleEmitter();
  319. break;
  320. case 3:
  321. system.particleEmitterType = new HemisphericParticleEmitter();
  322. break;
  323. case 4:
  324. system.particleEmitterType = new MeshParticleEmitter();
  325. break;
  326. case 5:
  327. system.particleEmitterType = new PointParticleEmitter();
  328. break;
  329. case 6:
  330. system.particleEmitterType = new SphereParticleEmitter();
  331. break;
  332. }
  333. this.raiseOnPropertyChanged("particleEmitterType", system.particleEmitterType, currentType)
  334. this.forceUpdate();
  335. }}
  336. extractValue={() => {
  337. switch(system.particleEmitterType?.getClassName()) {
  338. case "BoxParticleEmitter":
  339. return 0;
  340. case "ConeParticleEmitter":
  341. return 1;
  342. case "CylinderParticleEmitter":
  343. return 2;
  344. case "HemisphericParticleEmitter":
  345. return 3;
  346. case "MeshParticleEmitter":
  347. return 4;
  348. case "PointParticleEmitter":
  349. return 5;
  350. case "SphereParticleEmitter":
  351. return 6;
  352. }
  353. return 0;
  354. }}/>
  355. {
  356. this.renderEmitter()
  357. }
  358. </LineContainerComponent>
  359. <LineContainerComponent globalState={this.props.globalState} title="EMISSION">
  360. <FloatLineComponent lockObject={this.props.lockObject} label="Rate" target={system} propertyName="emitRate" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  361. {
  362. system instanceof ParticleSystem &&
  363. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getEmitRateGradients()!}
  364. label="Velocity gradients"
  365. docLink="https://doc.babylonjs.com/babylon101/particles#emit-rate-over-time"
  366. onCreateRequired={() => {
  367. system.addEmitRateGradient(0, 50, 50);
  368. this.props.globalState.onCodeChangedObservable.notifyObservers({
  369. object: system,
  370. code: `TARGET.addEmitRateGradient(0, 50, 50);`
  371. });
  372. }}
  373. mode={GradientGridMode.Factor}
  374. host={system}
  375. codeRecorderPropertyName="getEmitRateGradients()"
  376. lockObject={this.props.lockObject}/>
  377. }
  378. <FloatLineComponent lockObject={this.props.lockObject} label="Min emit power" target={system} propertyName="minEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  379. <FloatLineComponent lockObject={this.props.lockObject} label="Max emit power" target={system} propertyName="maxEmitPower" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  380. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getVelocityGradients()!}
  381. label="Velocity gradients"
  382. docLink="https://doc.babylonjs.com/babylon101/particles#velocity-over-time"
  383. onCreateRequired={() => {
  384. system.addVelocityGradient(0, 0.1, 0.1);
  385. this.props.globalState.onCodeChangedObservable.notifyObservers({
  386. object: system,
  387. code: `TARGET.addVelocityGradient(0, 0.1, 0.1);`
  388. });
  389. }}
  390. mode={GradientGridMode.Factor}
  391. host={system}
  392. codeRecorderPropertyName="getVelocityGradients()"
  393. lockObject={this.props.lockObject}/>
  394. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getLimitVelocityGradients()!}
  395. label="Limit velocity gradients"
  396. docLink="https://doc.babylonjs.com/babylon101/particles#limit-velocity-over-time"
  397. onCreateRequired={() => {
  398. system.addLimitVelocityGradient(0, 0.1, 0.1);
  399. this.props.globalState.onCodeChangedObservable.notifyObservers({
  400. object: system,
  401. code: `TARGET.addLimitVelocityGradient(0, 0.1, 0.1);`
  402. });
  403. }}
  404. mode={GradientGridMode.Factor}
  405. host={system}
  406. codeRecorderPropertyName="getLimitVelocityGradients()"
  407. lockObject={this.props.lockObject}/>
  408. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getDragGradients()!}
  409. label="Drag gradients"
  410. docLink="https://doc.babylonjs.com/babylon101/particles#drag-factor"
  411. onCreateRequired={() => {
  412. system.addDragGradient(0, 0.1, 0.1);
  413. this.props.globalState.onCodeChangedObservable.notifyObservers({
  414. object: system,
  415. code: `TARGET.addDragGradient(0, 0.1, 0.1);`
  416. });
  417. }}
  418. host={system}
  419. codeRecorderPropertyName="getDragGradients()"
  420. mode={GradientGridMode.Factor}
  421. lockObject={this.props.lockObject}/>
  422. </LineContainerComponent>
  423. <LineContainerComponent globalState={this.props.globalState} title="SIZE">
  424. <FloatLineComponent lockObject={this.props.lockObject} label="Min size" target={system} propertyName="minSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  425. <FloatLineComponent lockObject={this.props.lockObject} label="Max size" target={system} propertyName="maxSize" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  426. <FloatLineComponent lockObject={this.props.lockObject} label="Min scale X" target={system} propertyName="minScaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  427. <FloatLineComponent lockObject={this.props.lockObject} label="Max scale X" target={system} propertyName="maxScaleX" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  428. <FloatLineComponent lockObject={this.props.lockObject} label="Min scale Y" target={system} propertyName="minScaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  429. <FloatLineComponent lockObject={this.props.lockObject} label="Max scale Y" target={system} propertyName="maxScaleY" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  430. {
  431. system instanceof ParticleSystem &&
  432. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getStartSizeGradients()!}
  433. label="Start size gradients"
  434. docLink="https://doc.babylonjs.com/babylon101/particles#start-size-over-time"
  435. onCreateRequired={() => {
  436. system.addStartSizeGradient(0, 1, 1);
  437. this.props.globalState.onCodeChangedObservable.notifyObservers({
  438. object: system,
  439. code: `TARGET.addStartSizeGradient(0, 1, 1);`
  440. });
  441. }}
  442. host={system}
  443. codeRecorderPropertyName="getStartSizeGradients()"
  444. mode={GradientGridMode.Factor}
  445. lockObject={this.props.lockObject}/>
  446. }
  447. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getSizeGradients()!}
  448. label="Size gradients"
  449. docLink="https://doc.babylonjs.com/babylon101/particles#size"
  450. onCreateRequired={() => {
  451. system.addSizeGradient(0, 1, 1);
  452. this.props.globalState.onCodeChangedObservable.notifyObservers({
  453. object: system,
  454. code: `TARGET.addSizeGradient(0, 1, 1);`
  455. });
  456. }}
  457. host={system}
  458. codeRecorderPropertyName="getSizeGradients()"
  459. mode={GradientGridMode.Factor}
  460. lockObject={this.props.lockObject}/>
  461. </LineContainerComponent>
  462. <LineContainerComponent globalState={this.props.globalState} title="LIFETIME">
  463. <FloatLineComponent lockObject={this.props.lockObject} label="Min lifetime" target={system} propertyName="minLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  464. <FloatLineComponent lockObject={this.props.lockObject} label="Max lifetime" target={system} propertyName="maxLifeTime" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  465. <FloatLineComponent lockObject={this.props.lockObject} label="Target stop duration" target={system} propertyName="targetStopDuration" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  466. {
  467. system instanceof ParticleSystem &&
  468. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getLifeTimeGradients()!}
  469. label="Lifetime gradients"
  470. docLink="https://doc.babylonjs.com/babylon101/particles#lifetime"
  471. onCreateRequired={() => {
  472. system.addLifeTimeGradient(0, 1, 1);
  473. this.props.globalState.onCodeChangedObservable.notifyObservers({
  474. object: system,
  475. code: `TARGET.addLifeTimeGradient(0, 1, 1);`
  476. });
  477. }}
  478. host={system}
  479. codeRecorderPropertyName="getLifeTimeGradients()"
  480. mode={GradientGridMode.Factor}
  481. lockObject={this.props.lockObject}/>
  482. }
  483. </LineContainerComponent>
  484. <LineContainerComponent globalState={this.props.globalState} title="COLORS">
  485. <Color4LineComponent label="Color 1" target={system} propertyName="color1"
  486. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  487. <Color4LineComponent label="Color 2" target={system} propertyName="color2"
  488. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  489. <Color4LineComponent label="Color dead" target={system} propertyName="colorDead"
  490. onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  491. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getColorGradients()!}
  492. label="Color gradients"
  493. docLink="https://doc.babylonjs.com/babylon101/particles#particle-colors"
  494. onCreateRequired={() => {
  495. system.addColorGradient(0, new Color4(0, 0, 0, 1), new Color4(1, 1, 1, 1));
  496. this.props.globalState.onCodeChangedObservable.notifyObservers({
  497. object: system,
  498. code: `TARGET.addColorGradient(0, new BABYLON.Color4(0, 0, 0, 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. this.props.globalState.onCodeChangedObservable.notifyObservers({
  515. object: system,
  516. code: `TARGET.addRampGradient(0, BABYLON.Color3.White());`
  517. });
  518. }}
  519. mode={GradientGridMode.Color3}
  520. host={system}
  521. codeRecorderPropertyName="getRampGradients()"
  522. lockObject={this.props.lockObject}/>
  523. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getColorRemapGradients()!}
  524. label="Color remap gradients"
  525. docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
  526. onCreateRequired={() => {
  527. system.addColorRemapGradient(0, 1, 1);
  528. this.props.globalState.onCodeChangedObservable.notifyObservers({
  529. object: system,
  530. code: `TARGET.addColorRemapGradient(0, 1, 1);`
  531. });
  532. }}
  533. host={system}
  534. codeRecorderPropertyName="getColorRemapGradients()"
  535. mode={GradientGridMode.Factor}
  536. lockObject={this.props.lockObject}/>
  537. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getAlphaRemapGradients()!}
  538. label="Alpha remap gradients"
  539. docLink="https://doc.babylonjs.com/babylon101/particles#ramp-gradients"
  540. onCreateRequired={() => {
  541. system.addAlphaRemapGradient(0, 1, 1);
  542. this.props.globalState.onCodeChangedObservable.notifyObservers({
  543. object: system,
  544. code: `TARGET.addAlphaRemapGradient(0, 1, 1);`
  545. });
  546. }}
  547. host={system}
  548. codeRecorderPropertyName="getAlphaRemapGradients()"
  549. mode={GradientGridMode.Factor}
  550. lockObject={this.props.lockObject}/>
  551. </>
  552. }
  553. </LineContainerComponent>
  554. <LineContainerComponent globalState={this.props.globalState} title="ROTATION">
  555. <FloatLineComponent lockObject={this.props.lockObject} label="Min angular speed" target={system} propertyName="minAngularSpeed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  556. <FloatLineComponent lockObject={this.props.lockObject} label="Max angular speed" target={system} propertyName="maxAngularSpeed" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  557. <FloatLineComponent lockObject={this.props.lockObject} label="Min initial rotation" target={system} propertyName="minInitialRotation" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  558. <FloatLineComponent lockObject={this.props.lockObject} label="Max initial rotation" target={system} propertyName="maxInitialRotation" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
  559. <ValueGradientGridComponent globalState={this.props.globalState} gradients={system.getAngularSpeedGradients()!}
  560. label="Angular speed gradients"
  561. docLink="hhttps://doc.babylonjs.com/babylon101/particles#rotation"
  562. onCreateRequired={() => {
  563. system.addAngularSpeedGradient(0, 0.1, 0.1);
  564. this.props.globalState.onCodeChangedObservable.notifyObservers({
  565. object: system,
  566. code: `TARGET.addAngularSpeedGradient(0, 0.1, 0.1);`
  567. });
  568. }}
  569. host={system}
  570. codeRecorderPropertyName="getAngularSpeedGradients()"
  571. mode={GradientGridMode.Factor}
  572. lockObject={this.props.lockObject}/>
  573. </LineContainerComponent>
  574. </div>
  575. );
  576. }
  577. }