@@ -46,9 +46,12 @@ import { UpdateSizeBlock } from "./Blocks/Update/updateSizeBlock";
4646/** Represents blocks or groups of blocks that can be used in multiple places in the graph, so they are stored in this context to be reused */
4747type ConversionContext = {
4848 targetStopDurationBlockOutput : NodeParticleConnectionPoint ;
49+ // Connections that represent calculated ratios values
4950 timeToStopTimeRatioBlockGroupOutput : NodeParticleConnectionPoint ;
50- sizeGradientValue0Output : NodeParticleConnectionPoint ;
5151 ageToLifeTimeRatioBlockGroupOutput : NodeParticleConnectionPoint ;
52+ // Connections for the start value of a gradient. These are stored so they can be reused for the Creation phase and the Update phase of the particle
53+ sizeGradientValue0Output : NodeParticleConnectionPoint ;
54+ colorGradientValue0Output : NodeParticleConnectionPoint ;
5255} ;
5356
5457type RuntimeConversionContext = Partial < ConversionContext > ;
@@ -76,23 +79,19 @@ export async function ConvertToNodeParticleSystemSetAsync(name: string, particle
7679}
7780
7881async function _ExtractDatafromParticleSystemAsync ( newSet : NodeParticleSystemSet , oldSystem : ParticleSystem , context : RuntimeConversionContext ) : Promise < void > {
79- // CreateParticle block
80- const createParticleBlock = _CreateParticleBlockGroup ( oldSystem , context ) ;
82+ // CreateParticle block group
83+ const createParticleOutput = _CreateParticleBlockGroup ( oldSystem , context ) ;
8184
8285 // Emitter Shape block
83- const shapeBlock = _EmitterShapeBlock ( oldSystem ) ;
84- createParticleBlock . particle . connectTo ( shapeBlock . particle ) ;
85-
86- // Update the particle position
87- const positionUpdatedParticle = _UpdateParticleBlockGroup ( shapeBlock . output , oldSystem , context ) ;
86+ const shapeOutput = _EmitterShapeBlock ( oldSystem ) ;
87+ createParticleOutput . particle . connectTo ( shapeOutput . particle ) ;
8888
89- // Color update
90- const colorUpdateBlock = _CreateColorUpdateBlock ( oldSystem , createParticleBlock ) ;
91- positionUpdatedParticle . connectTo ( colorUpdateBlock . particle ) ;
89+ // UpdateParticle block group
90+ const updateParticleOutput = _UpdateParticleBlockGroup ( shapeOutput . output , oldSystem , context ) ;
9291
9392 // System block
9493 const newSystem = _SystemBlockGroup ( oldSystem , context ) ;
95- colorUpdateBlock . output . connectTo ( newSystem . particle ) ;
94+ updateParticleOutput . connectTo ( newSystem . particle ) ;
9695
9796 // Register
9897 newSet . systemBlocks . push ( newSystem ) ;
@@ -145,8 +144,7 @@ function _CreateParticleBlockGroup(oldSystem: ParticleSystem, context: RuntimeCo
145144 _CreateParticleSizeBlockGroup ( oldSystem , context ) . connectTo ( createParticleBlock . size ) ;
146145 _CreateParticleScaleBlockGroup ( oldSystem , context ) . connectTo ( createParticleBlock . scale ) ;
147146 _CreateParticleAngleBlockGroup ( oldSystem ) . connectTo ( createParticleBlock . angle ) ;
148-
149- // Color is handled when we do the color update block to manage gradients
147+ _CreateParticleColorBlockGroup ( oldSystem , context ) . connectTo ( createParticleBlock . color ) ;
150148
151149 // Dead color
152150 _CreateAndConnectInput ( "Dead Color" , oldSystem . colorDead , createParticleBlock . colorDead ) ;
@@ -198,8 +196,8 @@ function _CreateParticleEmitPowerBlockGroup(oldSystem: ParticleSystem): NodePart
198196 */
199197function _CreateParticleSizeBlockGroup ( oldSystem : ParticleSystem , context : RuntimeConversionContext ) : NodeParticleConnectionPoint {
200198 if ( oldSystem . _sizeGradients && oldSystem . _sizeGradients . length > 0 ) {
201- const sizeGradientBlockGroupOutput = _CreateParticleSizeGradientBlockGroup ( oldSystem . _sizeGradients , context ) ;
202- return sizeGradientBlockGroupOutput ;
199+ context . sizeGradientValue0Output = _CreateParticleInitialValueFromGradient ( oldSystem . _sizeGradients ) ;
200+ return context . sizeGradientValue0Output ;
203201 } else {
204202 const randomSizeBlock = new ParticleRandomBlock ( "Random size" ) ;
205203 _CreateAndConnectInput ( "Min size" , oldSystem . minSize , randomSizeBlock . min ) ;
@@ -254,28 +252,44 @@ function _CreateParticleAngleBlockGroup(oldSystem: ParticleSystem): NodeParticle
254252 return randomRotationBlock . output ;
255253}
256254
257- function _CreateParticleSizeGradientBlockGroup ( sizeGradients : Array < FactorGradient > , context : RuntimeConversionContext ) : NodeParticleConnectionPoint {
258- if ( sizeGradients . length === 0 ) {
259- throw new Error ( "No size gradients provided." ) ;
255+ /**
256+ * Creates the group of blocks that represent the particle color
257+ * @param oldSystem The old particle system to convert
258+ * @param context The context of the current conversion
259+ * @returns The output of the group of blocks that represent the particle color
260+ */
261+ function _CreateParticleColorBlockGroup ( oldSystem : ParticleSystem , context : RuntimeConversionContext ) : NodeParticleConnectionPoint {
262+ if ( oldSystem . _colorGradients && oldSystem . _colorGradients . length > 0 ) {
263+ context . colorGradientValue0Output = _CreateParticleInitialValueFromGradient ( oldSystem . _colorGradients ) ;
264+ return context . colorGradientValue0Output ;
265+ } else {
266+ const randomColorBlock = new ParticleRandomBlock ( "Random color" ) ;
267+ _CreateAndConnectInput ( "Color 1" , oldSystem . color1 , randomColorBlock . min ) ;
268+ _CreateAndConnectInput ( "Color 2" , oldSystem . color2 , randomColorBlock . max ) ;
269+ return randomColorBlock . output ;
270+ }
271+ }
272+
273+ function _CreateParticleInitialValueFromGradient ( gradients : Array < FactorGradient > | Array < ColorGradient > ) : NodeParticleConnectionPoint {
274+ if ( gradients . length === 0 ) {
275+ throw new Error ( "No gradients provided." ) ;
260276 }
261277
262- const initialParticleSize = _CreateSizeFromGradientStep ( sizeGradients [ 0 ] , 0 ) ;
263- context . sizeGradientValue0Output = initialParticleSize ;
264- return initialParticleSize ;
265- }
278+ const gradientStep = gradients [ 0 ] ;
279+ const value1 = ( gradientStep as any ) . factor1 ?? ( gradientStep as any ) . color1 ;
280+ const value2 = ( gradientStep as any ) . factor2 ?? ( gradientStep as any ) . color2 ;
266281
267- function _CreateSizeFromGradientStep ( gradientStep : FactorGradient , index : number ) : NodeParticleConnectionPoint {
268- if ( gradientStep . factor2 !== undefined ) {
282+ if ( value2 !== undefined ) {
269283 // Create a random between value1 and value2
270- const randomBlock = new ParticleRandomBlock ( "Random Value " + index ) ;
284+ const randomBlock = new ParticleRandomBlock ( "Random Value 0" ) ;
271285 randomBlock . lockMode = ParticleRandomBlockLocks . OncePerParticle ;
272- _CreateAndConnectInput ( "Value 1" , gradientStep . factor1 , randomBlock . min ) ;
273- _CreateAndConnectInput ( "Value 2" , gradientStep . factor2 , randomBlock . max ) ;
286+ _CreateAndConnectInput ( "Value 1" , value1 , randomBlock . min ) ;
287+ _CreateAndConnectInput ( "Value 2" , value2 , randomBlock . max ) ;
274288 return randomBlock . output ;
275289 } else {
276290 // Single value
277291 const sizeBlock = new ParticleInputBlock ( "Value" ) ;
278- sizeBlock . value = gradientStep . factor1 ;
292+ sizeBlock . value = value1 ;
279293 return sizeBlock . output ;
280294 }
281295}
@@ -437,6 +451,7 @@ function _EmitterShapeBlock(oldSystem: IParticleSystem): IShapeBlock {
437451function _UpdateParticleBlockGroup ( inputParticle : NodeParticleConnectionPoint , oldSystem : ParticleSystem , context : RuntimeConversionContext ) : NodeParticleConnectionPoint {
438452 let updateBlockGroupOutput : NodeParticleConnectionPoint = inputParticle ;
439453
454+ updateBlockGroupOutput = _UpdateParticleColorBlockGroup ( updateBlockGroupOutput , oldSystem . _colorGradients , context ) ;
440455 updateBlockGroupOutput = _UpdateParticleAngleBlockGroup ( updateBlockGroupOutput , oldSystem , context ) ;
441456 updateBlockGroupOutput = _UpdateParticlePositionBlockGroup ( updateBlockGroupOutput , oldSystem . isLocal ) ;
442457
@@ -451,14 +466,41 @@ function _UpdateParticleBlockGroup(inputParticle: NodeParticleConnectionPoint, o
451466 return updateBlockGroupOutput ;
452467}
453468
469+ function _UpdateParticleColorBlockGroup (
470+ inputParticle : NodeParticleConnectionPoint ,
471+ colorGradients : Nullable < Array < ColorGradient > > ,
472+ context : RuntimeConversionContext
473+ ) : NodeParticleConnectionPoint {
474+ let colorCalculation : NodeParticleConnectionPoint | undefined = undefined ;
475+ if ( colorGradients && colorGradients . length > 0 ) {
476+ if ( context . colorGradientValue0Output === undefined ) {
477+ throw new Error ( "Initial color gradient values not found in context." ) ;
478+ }
479+
480+ context . ageToLifeTimeRatioBlockGroupOutput = _CreateAgeToLifeTimeRatioBlockGroup ( context ) ;
481+ colorCalculation = _CreateGradientBlockGroup ( context . ageToLifeTimeRatioBlockGroupOutput , colorGradients , ParticleRandomBlockLocks . OncePerParticle , "Color" , [
482+ context . colorGradientValue0Output ,
483+ ] ) ;
484+ } else {
485+ colorCalculation = _CreateBasicColorUpdate ( ) ;
486+ }
487+
488+ // Create the color update block clamping alpha >= 0
489+ const colorUpdateBlock = new UpdateColorBlock ( "Color update" ) ;
490+ inputParticle . connectTo ( colorUpdateBlock . particle ) ;
491+ _ClampUpdateColorAlpha ( colorCalculation ) . connectTo ( colorUpdateBlock . color ) ;
492+
493+ return colorUpdateBlock . output ;
494+ }
495+
454496function _UpdateParticleAngleBlockGroup ( inputParticle : NodeParticleConnectionPoint , oldSystem : ParticleSystem , context : RuntimeConversionContext ) : NodeParticleConnectionPoint {
455497 // We will try to use gradients if they exist
456498 // If not, we will try to use min/max angular speed
457499 let angularSpeedCalculation = null ;
458500 if ( oldSystem . _angularSpeedGradients && oldSystem . _angularSpeedGradients . length > 0 ) {
459- angularSpeedCalculation = _UpdateParticleAngularSpeedGradientBlockGroup ( inputParticle , oldSystem . _angularSpeedGradients , context ) ;
501+ angularSpeedCalculation = _UpdateParticleAngularSpeedGradientBlockGroup ( oldSystem . _angularSpeedGradients , context ) ;
460502 } else if ( oldSystem . minAngularSpeed !== 0 || oldSystem . maxAngularSpeed !== 0 ) {
461- angularSpeedCalculation = _UpdateParticleAngularSpeedBlockGroup ( inputParticle , oldSystem . minAngularSpeed , oldSystem . maxAngularSpeed ) ;
503+ angularSpeedCalculation = _UpdateParticleAngularSpeedBlockGroup ( oldSystem . minAngularSpeed , oldSystem . maxAngularSpeed ) ;
462504 }
463505
464506 // If we have an angular speed calculation, then update the angle
@@ -483,11 +525,7 @@ function _UpdateParticleAngleBlockGroup(inputParticle: NodeParticleConnectionPoi
483525 }
484526}
485527
486- function _UpdateParticleAngularSpeedGradientBlockGroup (
487- inputParticle : NodeParticleConnectionPoint ,
488- angularSpeedGradients : Array < FactorGradient > ,
489- context : RuntimeConversionContext
490- ) : NodeParticleConnectionPoint {
528+ function _UpdateParticleAngularSpeedGradientBlockGroup ( angularSpeedGradients : Array < FactorGradient > , context : RuntimeConversionContext ) : NodeParticleConnectionPoint {
491529 context . ageToLifeTimeRatioBlockGroupOutput = _CreateAgeToLifeTimeRatioBlockGroup ( context ) ;
492530
493531 // Generate the gradient
@@ -500,7 +538,7 @@ function _UpdateParticleAngularSpeedGradientBlockGroup(
500538 return angularSpeedValueOutput ;
501539}
502540
503- function _UpdateParticleAngularSpeedBlockGroup ( inputParticle : NodeParticleConnectionPoint , minAngularSpeed : number , maxAngularSpeed : number ) : NodeParticleConnectionPoint {
541+ function _UpdateParticleAngularSpeedBlockGroup ( minAngularSpeed : number , maxAngularSpeed : number ) : NodeParticleConnectionPoint {
504542 // Random value between for the angular speed of the particle
505543 const randomAngularSpeedBlock = new ParticleRandomBlock ( "Random Angular Speed" ) ;
506544 randomAngularSpeedBlock . lockMode = ParticleRandomBlockLocks . OncePerParticle ;
@@ -570,110 +608,19 @@ function _UpdateParticleGravityBlockGroup(inputParticle: NodeParticleConnectionP
570608 return updateDirection . output ;
571609}
572610
573- function _CreateColorUpdateBlock ( oldSystem : IParticleSystem , createParticleBlock : CreateParticleBlock ) : UpdateColorBlock {
574- if ( ! oldSystem ) {
575- throw new Error ( "Invalid particle system" ) ;
576- }
577-
578- // Calculate the color
579- const colorGradients = oldSystem . getColorGradients ( ) ;
580- let colorBlock : Nullable < ParticleGradientBlock | ParticleMathBlock > = null ;
581- if ( colorGradients && colorGradients . length > 0 ) {
582- colorBlock = _CreateGradientColorUpdate ( oldSystem , colorGradients , createParticleBlock ) ;
583- } else {
584- colorBlock = _CreateBasicColorUpdate ( oldSystem , createParticleBlock ) ;
585- }
586-
587- // Clamp alpha >= 0
588- const clampedColor = _ClampUpdateColorAlpha ( colorBlock ) ;
589-
590- // Create the color update block
591- const colorUpdateBlock = new UpdateColorBlock ( "Color update" ) ;
592- clampedColor . colorOut . connectTo ( colorUpdateBlock . color ) ;
593-
594- return colorUpdateBlock ;
595- }
596-
597- function _CreateGradientColorUpdate ( oldSystem : IParticleSystem , gradient : Array < ColorGradient > , createParticleBlock : CreateParticleBlock ) : ParticleGradientBlock {
598- const colorGradientBlock = new ParticleGradientBlock ( "Color Gradient" ) ;
599- _CreateAndConnectContextualSource ( "gradient" , NodeParticleContextualSources . Age , colorGradientBlock . gradient ) ;
600-
601- let tempColor : Nullable < ParticleInputBlock | ParticleRandomBlock > = null ;
602- let colorStart : Nullable < ParticleInputBlock | ParticleRandomBlock > = null ;
603- let colorEnd : Nullable < ParticleInputBlock | ParticleRandomBlock > = null ;
604- for ( let i = 0 ; i < gradient . length ; i ++ ) {
605- const gradientStep = gradient [ i ] ;
606- const gradientValueBlock = new ParticleGradientValueBlock ( "Color Gradient Value " + i ) ;
607- gradientValueBlock . reference = gradientStep . gradient ;
608-
609- if ( gradientStep . color2 ) {
610- // Create a random between color1 and color2
611- const randomColorBlock = new ParticleRandomBlock ( "Random Color for Gradient " + i ) ;
612- randomColorBlock . lockMode = ParticleRandomBlockLocks . PerSystem ;
613- _CreateAndConnectInput ( "Color 1" , gradientStep . color1 , randomColorBlock . min ) ;
614- _CreateAndConnectInput ( "Color 2" , gradientStep . color2 , randomColorBlock . max ) ;
615- randomColorBlock . output . connectTo ( gradientValueBlock . value ) ;
616- tempColor = randomColorBlock ;
617- } else {
618- // Single color
619- const input = new ParticleInputBlock ( "Color " + i ) ;
620- input . value = gradientStep . color1 ;
621- input . output . connectTo ( gradientValueBlock . value ) ;
622- tempColor = input ;
623- }
624-
625- if ( gradientStep . gradient === 0 ) {
626- colorStart = tempColor ;
627- } else if ( gradientStep . gradient === 1 ) {
628- colorEnd = tempColor ;
629- }
630-
631- gradientValueBlock . output . connectTo ( colorGradientBlock . inputs [ i + 1 ] ) ;
632- }
633-
634- _UpdateCreateParticleColor ( oldSystem , colorStart , colorEnd , createParticleBlock ) ;
635-
636- return colorGradientBlock ;
637- }
638-
639- function _CreateBasicColorUpdate ( oldSystem : IParticleSystem , createParticleBlock : CreateParticleBlock ) : ParticleMathBlock {
611+ function _CreateBasicColorUpdate ( ) : NodeParticleConnectionPoint {
640612 const addColorBlock = new ParticleMathBlock ( "Add Color" ) ;
641613 addColorBlock . operation = ParticleMathBlockOperations . Add ;
642614 _CreateAndConnectContextualSource ( "Color" , NodeParticleContextualSources . Color , addColorBlock . left ) ;
643615 _CreateAndConnectContextualSource ( "Scaled Color Step" , NodeParticleContextualSources . ScaledColorStep , addColorBlock . right ) ;
644616
645- _UpdateCreateParticleColor ( oldSystem , null , null , createParticleBlock ) ;
646-
647- return addColorBlock ;
617+ return addColorBlock . output ;
648618}
649619
650- function _UpdateCreateParticleColor (
651- oldSystem : IParticleSystem ,
652- colorStart : Nullable < ParticleInputBlock | ParticleRandomBlock > ,
653- colorEnd : Nullable < ParticleInputBlock | ParticleRandomBlock > ,
654- createParticleBlock : CreateParticleBlock
655- ) : void {
656- if ( colorStart === null ) {
657- colorStart = new ParticleInputBlock ( "Color Start" ) ;
658- colorStart . value = oldSystem . color1 ;
659- }
660-
661- if ( colorEnd === null ) {
662- colorEnd = new ParticleInputBlock ( "Color End" ) ;
663- colorEnd . value = oldSystem . color2 ;
664- }
665-
666- const randomColorBlock = new ParticleRandomBlock ( "Random color" ) ;
667- randomColorBlock . lockMode = ParticleRandomBlockLocks . PerParticle ;
668- colorStart . output . connectTo ( randomColorBlock . min ) ;
669- colorEnd . output . connectTo ( randomColorBlock . max ) ;
670- randomColorBlock . output . connectTo ( createParticleBlock . color ) ;
671- }
672-
673- function _ClampUpdateColorAlpha ( colorBlock : ParticleMathBlock | ParticleGradientBlock ) : ParticleConverterBlock {
620+ function _ClampUpdateColorAlpha ( colorCalculationOutput : NodeParticleConnectionPoint ) : NodeParticleConnectionPoint {
674621 // Decompose color to clamp alpha
675622 const decomposeColorBlock = new ParticleConverterBlock ( "Decompose Color" ) ;
676- colorBlock . outputs [ 0 ] . connectTo ( decomposeColorBlock . colorIn ) ;
623+ colorCalculationOutput . connectTo ( decomposeColorBlock . colorIn ) ;
677624
678625 // Clamp alpha to be >= 0
679626 const maxAlphaBlock = new ParticleMathBlock ( "Alpha >= 0" ) ;
@@ -686,7 +633,7 @@ function _ClampUpdateColorAlpha(colorBlock: ParticleMathBlock | ParticleGradient
686633 decomposeColorBlock . xyzOut . connectTo ( composeColorBlock . xyzIn ) ;
687634 maxAlphaBlock . output . connectTo ( composeColorBlock . wIn ) ;
688635
689- return composeColorBlock ;
636+ return composeColorBlock . colorOut ;
690637}
691638
692639// ------------- UTILITY FUNCTIONS -------------
@@ -816,7 +763,7 @@ function _CreateAgeToLifeTimeRatioBlockGroup(context: RuntimeConversionContext):
816763 */
817764function _CreateGradientBlockGroup (
818765 gradientSelector : NodeParticleConnectionPoint ,
819- gradientValues : Array < FactorGradient > ,
766+ gradientValues : Array < FactorGradient > | Array < ColorGradient > ,
820767 randomLockMode : ParticleRandomBlockLocks ,
821768 prefix : string ,
822769 initialValues : NodeParticleConnectionPoint [ ] = [ ]
@@ -853,20 +800,28 @@ function _CreateGradientBlockGroup(
853800 * @param index The index of the gradient step
854801 * @returns The output connection point of the gradient value block
855802 */
856- function _CreateGradientValueBlockGroup ( gradientStep : FactorGradient , randomLockMode : ParticleRandomBlockLocks , prefix : string , index : number ) : NodeParticleConnectionPoint {
803+ function _CreateGradientValueBlockGroup (
804+ gradientStep : FactorGradient | ColorGradient ,
805+ randomLockMode : ParticleRandomBlockLocks ,
806+ prefix : string ,
807+ index : number
808+ ) : NodeParticleConnectionPoint {
857809 const gradientValueBlock = new ParticleGradientValueBlock ( prefix + " Gradient Value " + index ) ;
858810 gradientValueBlock . reference = gradientStep . gradient ;
859811
860- if ( gradientStep . factor2 !== undefined ) {
812+ const value1 = ( gradientStep as any ) . factor1 ?? ( gradientStep as any ) . color1 ;
813+ const value2 = ( gradientStep as any ) . factor2 ?? ( gradientStep as any ) . color2 ;
814+
815+ if ( value2 !== undefined ) {
861816 // Create a random between value1 and value2
862817 const randomBlock = new ParticleRandomBlock ( "Random Value " + index ) ;
863818 randomBlock . lockMode = randomLockMode ;
864- _CreateAndConnectInput ( "Value 1" , gradientStep . factor1 , randomBlock . min ) ;
865- _CreateAndConnectInput ( "Value 2" , gradientStep . factor2 , randomBlock . max ) ;
819+ _CreateAndConnectInput ( "Value 1" , value1 , randomBlock . min ) ;
820+ _CreateAndConnectInput ( "Value 2" , value2 , randomBlock . max ) ;
866821 randomBlock . output . connectTo ( gradientValueBlock . value ) ;
867822 } else {
868823 // Single value
869- _CreateAndConnectInput ( "Value" , gradientStep . factor1 , gradientValueBlock . value ) ;
824+ _CreateAndConnectInput ( "Value" , value1 , gradientValueBlock . value ) ;
870825 }
871826
872827 return gradientValueBlock . output ;
0 commit comments