@galacean/engine-core 2.0.0-alpha.35 → 2.0.0-alpha.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -33892,8 +33892,10 @@ var ParticleStopMode = /*#__PURE__*/ function(ParticleStopMode) {
33892
33892
  /**
33893
33893
  * @internal
33894
33894
  */ _proto._onEnable = function _onEnable() {
33895
- if (this.generator.main.playOnEnabled) {
33896
- this.generator.play(false);
33895
+ var generator = this.generator;
33896
+ generator._setTransformFeedback();
33897
+ if (generator.main.playOnEnabled) {
33898
+ generator.play(false);
33897
33899
  }
33898
33900
  };
33899
33901
  /**
@@ -34488,6 +34490,14 @@ ParticleTransformFeedbackSimulator._deltaTimeProperty = ShaderProperty.getByName
34488
34490
  return ParticleGradientMode;
34489
34491
  }({});
34490
34492
 
34493
+ /**
34494
+ * Particle sub emitter trigger type.
34495
+ */ var ParticleSubEmitterType = /*#__PURE__*/ function(ParticleSubEmitterType) {
34496
+ /** Triggered when a parent particle is born. */ ParticleSubEmitterType[ParticleSubEmitterType["Birth"] = 0] = "Birth";
34497
+ /** Triggered when a parent particle dies (lifetime expired). */ ParticleSubEmitterType[ParticleSubEmitterType["Death"] = 1] = "Death";
34498
+ return ParticleSubEmitterType;
34499
+ }({});
34500
+
34491
34501
  /**
34492
34502
  * @internal
34493
34503
  */ var ParticleRandomSubSeeds = /*#__PURE__*/ function(ParticleRandomSubSeeds) {
@@ -34509,6 +34519,7 @@ ParticleTransformFeedbackSimulator._deltaTimeProperty = ShaderProperty.getByName
34509
34519
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["ForceOverLifetime"] = 3875246972] = "ForceOverLifetime";
34510
34520
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["LimitVelocityOverLifetime"] = 3047300990] = "LimitVelocityOverLifetime";
34511
34521
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["Noise"] = 4105357473] = "Noise";
34522
+ ParticleRandomSubSeeds[ParticleRandomSubSeeds["SubEmitter"] = 2622110509] = "SubEmitter";
34512
34523
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["EmissionRate"] = 2625893077] = "EmissionRate";
34513
34524
  return ParticleRandomSubSeeds;
34514
34525
  }({});
@@ -34578,6 +34589,12 @@ ParticleTransformFeedbackSimulator._deltaTimeProperty = ShaderProperty.getByName
34578
34589
  * @param colorKeys - The color keys
34579
34590
  * @param alphaKeys - The alpha keys
34580
34591
  */ _proto.setKeys = function setKeys(colorKeys, alphaKeys) {
34592
+ if (colorKeys.length > 4) {
34593
+ throw new Error("Gradient can only have 4 color keys");
34594
+ }
34595
+ if (alphaKeys.length > 4) {
34596
+ throw new Error("Gradient can only have 4 alpha keys");
34597
+ }
34581
34598
  var currentColorKeys = this._colorKeys;
34582
34599
  var currentAlphaKeys = this._alphaKeys;
34583
34600
  for(var i = 0, n = currentColorKeys.length; i < n; i++){
@@ -34632,6 +34649,60 @@ ParticleTransformFeedbackSimulator._deltaTimeProperty = ShaderProperty.getByName
34632
34649
  }
34633
34650
  return typeArray;
34634
34651
  };
34652
+ /**
34653
+ * @internal
34654
+ */ _proto._evaluate = function _evaluate(time, out) {
34655
+ var alphaKeys = this._alphaKeys;
34656
+ var alphaCount = alphaKeys.length;
34657
+ if (alphaCount === 0) {
34658
+ out.a = 0;
34659
+ } else {
34660
+ var alphaMaxTime = alphaKeys[alphaCount - 1].time;
34661
+ var alphaT = Math.min(time, alphaMaxTime);
34662
+ for(var i = 0; i < alphaCount; i++){
34663
+ var key = alphaKeys[i];
34664
+ if (alphaT <= key.time) {
34665
+ if (i === 0) {
34666
+ out.a = key.alpha;
34667
+ } else {
34668
+ var lastKey = alphaKeys[i - 1];
34669
+ var age = (alphaT - lastKey.time) / (key.time - lastKey.time);
34670
+ out.a = lastKey.alpha + (key.alpha - lastKey.alpha) * age;
34671
+ }
34672
+ break;
34673
+ }
34674
+ }
34675
+ }
34676
+ var colorKeys = this._colorKeys;
34677
+ var colorCount = colorKeys.length;
34678
+ if (colorCount === 0) {
34679
+ out.r = 0;
34680
+ out.g = 0;
34681
+ out.b = 0;
34682
+ } else {
34683
+ var colorMaxTime = colorKeys[colorCount - 1].time;
34684
+ var colorT = Math.min(time, colorMaxTime);
34685
+ for(var i1 = 0; i1 < colorCount; i1++){
34686
+ var key1 = colorKeys[i1];
34687
+ if (colorT <= key1.time) {
34688
+ var c = key1.color;
34689
+ if (i1 === 0) {
34690
+ out.r = c.r;
34691
+ out.g = c.g;
34692
+ out.b = c.b;
34693
+ } else {
34694
+ var lastKey1 = colorKeys[i1 - 1];
34695
+ var last = lastKey1.color;
34696
+ var age1 = (colorT - lastKey1.time) / (key1.time - lastKey1.time);
34697
+ out.r = last.r + (c.r - last.r) * age1;
34698
+ out.g = last.g + (c.g - last.g) * age1;
34699
+ out.b = last.b + (c.b - last.b) * age1;
34700
+ }
34701
+ break;
34702
+ }
34703
+ }
34704
+ }
34705
+ };
34635
34706
  _proto._addKey = function _addKey(keys, key) {
34636
34707
  var time = key.time;
34637
34708
  var count = keys.length;
@@ -34811,6 +34882,17 @@ __decorate([
34811
34882
  case ParticleGradientMode.TwoConstants:
34812
34883
  engineMath.Color.lerp(this.constantMin, this.constantMax, lerpFactor, out);
34813
34884
  break;
34885
+ case ParticleGradientMode.Gradient:
34886
+ this.gradientMax._evaluate(time, out);
34887
+ break;
34888
+ case ParticleGradientMode.TwoGradients:
34889
+ {
34890
+ var tmp = ParticleCompositeGradient._tempColor;
34891
+ this.gradientMin._evaluate(time, tmp);
34892
+ this.gradientMax._evaluate(time, out);
34893
+ engineMath.Color.lerp(tmp, out, lerpFactor, out);
34894
+ break;
34895
+ }
34814
34896
  }
34815
34897
  };
34816
34898
  _create_class(ParticleCompositeGradient, [
@@ -34839,6 +34921,7 @@ __decorate([
34839
34921
  ]);
34840
34922
  return ParticleCompositeGradient;
34841
34923
  }();
34924
+ ParticleCompositeGradient._tempColor = new engineMath.Color();
34842
34925
  __decorate([
34843
34926
  deepClone
34844
34927
  ], ParticleCompositeGradient.prototype, "constantMin", void 0);
@@ -35016,6 +35099,31 @@ __decorate([
35016
35099
  };
35017
35100
  /**
35018
35101
  * @internal
35102
+ */ _proto._evaluateCumulative = function _evaluateCumulative(normalizedAge, lerpFactor) {
35103
+ switch(this.mode){
35104
+ case ParticleCurveMode.Constant:
35105
+ return this.constantMax * normalizedAge;
35106
+ case ParticleCurveMode.TwoConstants:
35107
+ return (this.constantMin + (this.constantMax - this.constantMin) * lerpFactor) * normalizedAge;
35108
+ case ParticleCurveMode.Curve:
35109
+ var _this_curveMax;
35110
+ var _this_curveMax__evaluateCumulative;
35111
+ return (_this_curveMax__evaluateCumulative = (_this_curveMax = this.curveMax) == null ? void 0 : _this_curveMax._evaluateCumulative(normalizedAge)) != null ? _this_curveMax__evaluateCumulative : 0;
35112
+ case ParticleCurveMode.TwoCurves:
35113
+ {
35114
+ var _this_curveMin, _this_curveMax1;
35115
+ var _this_curveMin__evaluateCumulative;
35116
+ var min = (_this_curveMin__evaluateCumulative = (_this_curveMin = this.curveMin) == null ? void 0 : _this_curveMin._evaluateCumulative(normalizedAge)) != null ? _this_curveMin__evaluateCumulative : 0;
35117
+ var _this_curveMax__evaluateCumulative1;
35118
+ var max = (_this_curveMax__evaluateCumulative1 = (_this_curveMax1 = this.curveMax) == null ? void 0 : _this_curveMax1._evaluateCumulative(normalizedAge)) != null ? _this_curveMax__evaluateCumulative1 : 0;
35119
+ return min + (max - min) * lerpFactor;
35120
+ }
35121
+ default:
35122
+ return 0;
35123
+ }
35124
+ };
35125
+ /**
35126
+ * @internal
35019
35127
  */ _proto._getMax = function _getMax() {
35020
35128
  switch(this.mode){
35021
35129
  case ParticleCurveMode.Constant:
@@ -36860,6 +36968,34 @@ __decorate([
36860
36968
  };
36861
36969
  /**
36862
36970
  * @internal
36971
+ */ _proto._evaluateCumulative = function _evaluateCumulative(normalizedAge) {
36972
+ var keys = this.keys;
36973
+ var length = keys.length;
36974
+ if (length === 0) return 0;
36975
+ // Single key is a constant curve (matches `_evaluate`); its integral is value × age.
36976
+ if (length === 1) return keys[0].value * normalizedAge;
36977
+ var firstKey = keys[0];
36978
+ if (normalizedAge <= firstKey.time) return firstKey.value * normalizedAge;
36979
+ var cumulative = firstKey.value * firstKey.time;
36980
+ for(var i = 1; i < length; i++){
36981
+ var key = keys[i];
36982
+ var lastKey = keys[i - 1];
36983
+ var segmentTime = key.time - lastKey.time;
36984
+ if (segmentTime <= 0) continue;
36985
+ if (key.time >= normalizedAge) {
36986
+ var offsetTime = normalizedAge - lastKey.time;
36987
+ var t = offsetTime / segmentTime;
36988
+ var currentValue = lastKey.value + (key.value - lastKey.value) * t;
36989
+ cumulative += (lastKey.value + currentValue) * 0.5 * offsetTime;
36990
+ return cumulative;
36991
+ }
36992
+ cumulative += (lastKey.value + key.value) * 0.5 * segmentTime;
36993
+ }
36994
+ var lastKey1 = keys[length - 1];
36995
+ return cumulative + lastKey1.value * (normalizedAge - lastKey1.time);
36996
+ };
36997
+ /**
36998
+ * @internal
36863
36999
  */ _proto._getTypeArray = function _getTypeArray() {
36864
37000
  var typeArray = this._typeArray || (this._typeArray = new Float32Array(4 * 2));
36865
37001
  if (this._typeArrayDirty) {
@@ -37670,6 +37806,221 @@ __decorate([
37670
37806
  deepClone
37671
37807
  ], VelocityOverLifetimeModule.prototype, "_velocityZ", void 0);
37672
37808
 
37809
+ /**
37810
+ * Optional parent properties a sub-emitter inherits
37811
+ * Sub particles are always emitted at the parent particle's position; these flags only select
37812
+ * which additional properties are inherited on top of that.
37813
+ */ var ParticleSubEmitterInheritProperty = /*#__PURE__*/ function(ParticleSubEmitterInheritProperty) {
37814
+ /** Inherit no additional properties; sub particles are still emitted at the parent's position. */ ParticleSubEmitterInheritProperty[ParticleSubEmitterInheritProperty["None"] = 0] = "None";
37815
+ /** Multiply parent's current color into the sub particle's start color. */ ParticleSubEmitterInheritProperty[ParticleSubEmitterInheritProperty["Color"] = 1] = "Color";
37816
+ /** Multiply parent's current size into the sub particle's start size. */ ParticleSubEmitterInheritProperty[ParticleSubEmitterInheritProperty["Size"] = 2] = "Size";
37817
+ /** Add parent's current rotation onto the sub particle's start rotation. */ ParticleSubEmitterInheritProperty[ParticleSubEmitterInheritProperty["Rotation"] = 4] = "Rotation";
37818
+ /** Emit the sub particle along the parent's velocity direction. */ ParticleSubEmitterInheritProperty[ParticleSubEmitterInheritProperty["Velocity"] = 8] = "Velocity";
37819
+ return ParticleSubEmitterInheritProperty;
37820
+ }({});
37821
+
37822
+ /**
37823
+ * One slot in `SubEmittersModule.subEmitters`. Configures which sub-emitter
37824
+ * fires, on which parent event, with what inheritance, probability, and count.
37825
+ */ var SubEmitter = /*#__PURE__*/ function() {
37826
+ function SubEmitter() {
37827
+ /** Bitmask of properties inherited from the parent particle. */ this.inheritProperties = ParticleSubEmitterInheritProperty.None;
37828
+ /** Probability (0..1) the sub-emitter fires for any given event. */ this.emitProbability = 1;
37829
+ /** Number of sub particles emitted per parent event. */ this.emitCount = 1;
37830
+ /** @internal */ this._module = null;
37831
+ this._emitter = null;
37832
+ this._type = ParticleSubEmitterType.Birth;
37833
+ }
37834
+ _create_class(SubEmitter, [
37835
+ {
37836
+ key: "emitter",
37837
+ get: /**
37838
+ * Target particle renderer the sub particles emit into.
37839
+ */ function get() {
37840
+ return this._emitter;
37841
+ },
37842
+ set: function set(value) {
37843
+ var _this__module;
37844
+ if (value === this._emitter) return;
37845
+ (_this__module = this._module) == null ? void 0 : _this__module._validateEmitter(value);
37846
+ this._emitter = value;
37847
+ }
37848
+ },
37849
+ {
37850
+ key: "type",
37851
+ get: /**
37852
+ * Which parent-particle event drives this slot.
37853
+ */ function get() {
37854
+ return this._type;
37855
+ },
37856
+ set: function set(value) {
37857
+ var _this__module;
37858
+ if (value === this._type) return;
37859
+ this._type = value;
37860
+ (_this__module = this._module) == null ? void 0 : _this__module._generator._setTransformFeedback();
37861
+ }
37862
+ }
37863
+ ]);
37864
+ return SubEmitter;
37865
+ }();
37866
+ __decorate([
37867
+ ignoreClone
37868
+ ], SubEmitter.prototype, "_module", void 0);
37869
+
37870
+ /**
37871
+ * Fires sub-emitters on parent particle lifecycle events (Birth / Death).
37872
+ * @remarks Requires WebGL2; the module stays inactive on WebGL1.
37873
+ */ var SubEmittersModule = /*#__PURE__*/ function(ParticleGeneratorModule) {
37874
+ _inherits(SubEmittersModule, ParticleGeneratorModule);
37875
+ function SubEmittersModule() {
37876
+ var _this;
37877
+ _this = ParticleGeneratorModule.apply(this, arguments) || this, _this._subEmitters = [], _this._probabilityRand = new engineMath.Rand(0, ParticleRandomSubSeeds.SubEmitter);
37878
+ return _this;
37879
+ }
37880
+ var _proto = SubEmittersModule.prototype;
37881
+ /**
37882
+ * Add a sub-emitter slot.
37883
+ * @param emitter - Target particle renderer
37884
+ * @param type - Trigger event (`Birth` / `Death`)
37885
+ * @param inheritProperties - Bitmask of properties inherited from the parent particle
37886
+ * @param emitProbability - Per-event fire probability [0, 1]
37887
+ * @param emitCount - Number of sub particles emitted per parent event
37888
+ */ _proto.addSubEmitter = function addSubEmitter(emitter, type, inheritProperties, emitProbability, emitCount) {
37889
+ if (inheritProperties === void 0) inheritProperties = ParticleSubEmitterInheritProperty.None;
37890
+ if (emitProbability === void 0) emitProbability = 1;
37891
+ if (emitCount === void 0) emitCount = 1;
37892
+ if (SubEmittersModule._wouldCreateCycle(emitter, this._generator)) {
37893
+ throw new Error("Sub-emitter would create a cycle");
37894
+ }
37895
+ var sub = new SubEmitter();
37896
+ sub.emitter = emitter;
37897
+ sub.type = type;
37898
+ sub.inheritProperties = inheritProperties;
37899
+ sub.emitProbability = emitProbability;
37900
+ sub.emitCount = emitCount;
37901
+ sub._module = this;
37902
+ this._subEmitters.push(sub);
37903
+ this._generator._setTransformFeedback();
37904
+ };
37905
+ /**
37906
+ * Remove the sub-emitter at the given index.
37907
+ * @param index - Index of the sub-emitter to remove
37908
+ */ _proto.removeSubEmitterByIndex = function removeSubEmitterByIndex(index) {
37909
+ this._subEmitters.splice(index, 1);
37910
+ this._generator._setTransformFeedback();
37911
+ };
37912
+ /**
37913
+ * @internal
37914
+ */ _proto._dispatchEvent = function _dispatchEvent(type, worldPosition, parentColor, parentSize, parentRotation, worldDirection) {
37915
+ var subEmitters = this.subEmitters;
37916
+ for(var i = 0, n = subEmitters.length; i < n; i++){
37917
+ var sub = subEmitters[i];
37918
+ if (sub.type !== type) continue;
37919
+ var target = sub.emitter;
37920
+ if (target === null || target.destroyed) continue;
37921
+ var count = sub.emitCount;
37922
+ if (count <= 0) continue;
37923
+ if (sub.emitProbability < 1.0 && this._probabilityRand.random() >= sub.emitProbability) {
37924
+ continue;
37925
+ }
37926
+ var inherit = sub.inheritProperties;
37927
+ var colorOverride = (inherit & ParticleSubEmitterInheritProperty.Color) !== 0 ? parentColor : null;
37928
+ var sizeOverride = (inherit & ParticleSubEmitterInheritProperty.Size) !== 0 ? parentSize : null;
37929
+ var rotationOverride = (inherit & ParticleSubEmitterInheritProperty.Rotation) !== 0 ? parentRotation : null;
37930
+ var directionOverride = (inherit & ParticleSubEmitterInheritProperty.Velocity) !== 0 ? worldDirection : null;
37931
+ target.generator._emitFromSubEmitter(count, worldPosition, colorOverride, sizeOverride, rotationOverride, directionOverride);
37932
+ }
37933
+ };
37934
+ /**
37935
+ * @internal
37936
+ */ _proto._resetRandomSeed = function _resetRandomSeed(seed) {
37937
+ this._probabilityRand.reset(seed, ParticleRandomSubSeeds.SubEmitter);
37938
+ };
37939
+ /**
37940
+ * @internal
37941
+ */ _proto._hasSubEmitterOfType = function _hasSubEmitterOfType(type) {
37942
+ if (!this.enabled) return false;
37943
+ var subEmitters = this.subEmitters;
37944
+ for(var i = 0, n = subEmitters.length; i < n; i++){
37945
+ if (subEmitters[i].type === type) return true;
37946
+ }
37947
+ return false;
37948
+ };
37949
+ /**
37950
+ * @internal
37951
+ */ _proto._cloneTo = function _cloneTo(target) {
37952
+ // _module is @ignoreClone, so re-link each cloned slot back to its new module
37953
+ var subEmitters = target._subEmitters;
37954
+ for(var i = 0, n = subEmitters.length; i < n; i++){
37955
+ subEmitters[i]._module = target;
37956
+ }
37957
+ };
37958
+ /**
37959
+ * @internal
37960
+ */ _proto._validateEmitter = function _validateEmitter(emitter) {
37961
+ if (emitter && SubEmittersModule._wouldCreateCycle(emitter, this._generator)) {
37962
+ throw new Error("Sub-emitter would create a cycle");
37963
+ }
37964
+ };
37965
+ SubEmittersModule._wouldCreateCycle = function _wouldCreateCycle(target, root) {
37966
+ var visited = SubEmittersModule._cycleVisited;
37967
+ var stack = SubEmittersModule._cycleStack;
37968
+ visited.clear();
37969
+ stack.length = 0;
37970
+ stack.push(target.generator);
37971
+ var found = false;
37972
+ while(stack.length > 0){
37973
+ var cur = stack.pop();
37974
+ if (cur === root) {
37975
+ found = true;
37976
+ break;
37977
+ }
37978
+ if (visited.has(cur)) continue;
37979
+ visited.add(cur);
37980
+ var slots = cur.subEmitters.subEmitters;
37981
+ for(var i = 0, n = slots.length; i < n; i++){
37982
+ var _slots_i_emitter;
37983
+ var child = (_slots_i_emitter = slots[i].emitter) == null ? void 0 : _slots_i_emitter.generator;
37984
+ if (child && !visited.has(child)) stack.push(child);
37985
+ }
37986
+ }
37987
+ visited.clear();
37988
+ stack.length = 0;
37989
+ return found;
37990
+ };
37991
+ _create_class(SubEmittersModule, [
37992
+ {
37993
+ key: "subEmitters",
37994
+ get: /**
37995
+ * The configured sub-emitters.
37996
+ */ function get() {
37997
+ return this._subEmitters;
37998
+ }
37999
+ },
38000
+ {
38001
+ key: "enabled",
38002
+ get: function get() {
38003
+ return this._enabled && this._generator._renderer.engine._hardwareRenderer.isWebGL2;
38004
+ },
38005
+ set: function set(value) {
38006
+ if (value !== this._enabled) {
38007
+ this._enabled = value;
38008
+ this._generator._setTransformFeedback();
38009
+ }
38010
+ }
38011
+ }
38012
+ ]);
38013
+ return SubEmittersModule;
38014
+ }(ParticleGeneratorModule);
38015
+ SubEmittersModule._cycleVisited = new Set();
38016
+ SubEmittersModule._cycleStack = [];
38017
+ __decorate([
38018
+ deepClone
38019
+ ], SubEmittersModule.prototype, "_subEmitters", void 0);
38020
+ __decorate([
38021
+ ignoreClone
38022
+ ], SubEmittersModule.prototype, "_probabilityRand", void 0);
38023
+
37673
38024
  /**
37674
38025
  * Particle Generator.
37675
38026
  */ var ParticleGenerator = /*#__PURE__*/ function() {
@@ -37689,6 +38040,7 @@ __decorate([
37689
38040
  /** @internal */ this._subPrimitive = new SubMesh(0, 0, MeshTopology.Triangles);
37690
38041
  /** @internal */ this._useTransformFeedback = false;
37691
38042
  /** @internal */ this._feedbackBindingIndex = -1;
38043
+ this._feedbackReadback = null;
37692
38044
  this._isPlaying = false;
37693
38045
  this._instanceBufferResized = false;
37694
38046
  this._waitProcessRetiredElementCount = 0;
@@ -37697,6 +38049,13 @@ __decorate([
37697
38049
  this._firstActiveTransformedBoundingBox = 0;
37698
38050
  this._firstFreeTransformedBoundingBox = 0;
37699
38051
  this._playStartDelay = 0;
38052
+ this._eventPos = new engineMath.Vector3();
38053
+ this._eventColor = new engineMath.Color();
38054
+ this._eventSize = new engineMath.Vector3();
38055
+ this._eventRotation = new engineMath.Vector3();
38056
+ this._eventDir = new engineMath.Vector3();
38057
+ this._emitLocalPos = new engineMath.Vector3();
38058
+ this._emitDirection = new engineMath.Vector3();
37700
38059
  this._renderer = renderer;
37701
38060
  var subPrimitive = new SubPrimitive();
37702
38061
  subPrimitive.start = 0;
@@ -37709,6 +38068,7 @@ __decorate([
37709
38068
  this.sizeOverLifetime = new SizeOverLifetimeModule(this);
37710
38069
  this.limitVelocityOverLifetime = new LimitVelocityOverLifetimeModule(this);
37711
38070
  this.noise = new NoiseModule(this);
38071
+ this.subEmitters = new SubEmittersModule(this);
37712
38072
  this.customData = new CustomDataModule(this);
37713
38073
  this.emission.enabled = true;
37714
38074
  }
@@ -38040,11 +38400,12 @@ __decorate([
38040
38400
  this.rotationOverLifetime._resetRandomSeed(seed);
38041
38401
  this.colorOverLifetime._resetRandomSeed(seed);
38042
38402
  this.noise._resetRandomSeed(seed);
38403
+ this.subEmitters._resetRandomSeed(seed);
38043
38404
  };
38044
38405
  /**
38045
38406
  * @internal
38046
38407
  */ _proto._setTransformFeedback = function _setTransformFeedback() {
38047
- var needed = this.limitVelocityOverLifetime.enabled || this.noise.enabled;
38408
+ var needed = this._renderer.engine._hardwareRenderer.isWebGL2 && (this.limitVelocityOverLifetime.enabled || this.noise.enabled || this.subEmitters._hasSubEmitterOfType(ParticleSubEmitterType.Death));
38048
38409
  if (needed === this._useTransformFeedback) return;
38049
38410
  this._useTransformFeedback = needed;
38050
38411
  // Switching TF mode invalidates all active particle state: feedback buffers and instance
@@ -38205,7 +38566,7 @@ __decorate([
38205
38566
  this._transformedBoundsArray[previousFreeElement * ParticleBufferUtils.boundsFloatStride + boundsTimeOffset] = this._playTime;
38206
38567
  }
38207
38568
  };
38208
- _proto._addNewParticle = function _addNewParticle(position, direction, transform, playTime, emitWorldPositionOverride) {
38569
+ _proto._addNewParticle = function _addNewParticle(position, direction, transform, playTime, emitWorldPositionOverride, inheritColor, inheritSize, inheritRotation) {
38209
38570
  var firstFreeElement = this._firstFreeElement;
38210
38571
  var nextFreeElement = firstFreeElement + 1;
38211
38572
  if (nextFreeElement >= this._currentParticleCount) {
@@ -38243,7 +38604,7 @@ __decorate([
38243
38604
  // Time
38244
38605
  instanceVertices[offset + ParticleBufferUtils.timeOffset] = playTime;
38245
38606
  // Color
38246
- var startColor = ParticleGenerator._tempColor0;
38607
+ var startColor = ParticleGenerator._tempColor;
38247
38608
  main.startColor.evaluate(undefined, main._startColorRand.random(), startColor);
38248
38609
  startColor.copyToArray(instanceVertices, offset + 8);
38249
38610
  var duration = this.main.duration;
@@ -38344,11 +38705,79 @@ __decorate([
38344
38705
  if (limitVelocityOverLifetime.enabled && (limitVelocityOverLifetime._isSpeedRandomMode() || limitVelocityOverLifetime._isDragRandomMode())) {
38345
38706
  instanceVertices[offset + 41] = limitVelocityOverLifetime._speedRand.random();
38346
38707
  }
38708
+ // Apply sub-emit inherit: multiply color/size, add rotation
38709
+ if (inheritColor) {
38710
+ instanceVertices[offset + 8] *= inheritColor.r;
38711
+ instanceVertices[offset + 9] *= inheritColor.g;
38712
+ instanceVertices[offset + 10] *= inheritColor.b;
38713
+ instanceVertices[offset + 11] *= inheritColor.a;
38714
+ }
38715
+ if (inheritSize) {
38716
+ instanceVertices[offset + 12] *= inheritSize.x;
38717
+ instanceVertices[offset + 13] *= inheritSize.y;
38718
+ instanceVertices[offset + 14] *= inheritSize.z;
38719
+ }
38720
+ if (inheritRotation) {
38721
+ instanceVertices[offset + 15] += inheritRotation.x;
38722
+ instanceVertices[offset + 16] += inheritRotation.y;
38723
+ instanceVertices[offset + 17] += inheritRotation.z;
38724
+ }
38347
38725
  // Initialize feedback buffer for this particle
38348
38726
  if (this._useTransformFeedback) {
38349
38727
  this._addFeedbackParticle(firstFreeElement, position, direction, startSpeed, transform, pos);
38350
38728
  }
38351
38729
  this._firstFreeElement = nextFreeElement;
38730
+ if (this.subEmitters._hasSubEmitterOfType(ParticleSubEmitterType.Birth)) {
38731
+ this._onParticleBirth(offset, position, direction, transform);
38732
+ }
38733
+ };
38734
+ _proto._onParticleBirth = function _onParticleBirth(offset, position, direction, transform) {
38735
+ var worldRotation = transform.worldRotationQuaternion;
38736
+ var birthPos = this._eventPos;
38737
+ engineMath.Vector3.transformByQuat(position, worldRotation, birthPos);
38738
+ birthPos.add(transform.worldPosition);
38739
+ // Birth emission direction is known directly; Death reads it back from the feedback buffer
38740
+ var worldDirection = this._eventDir;
38741
+ engineMath.Vector3.transformByQuat(direction, worldRotation, worldDirection);
38742
+ var parentColor = this._eventColor;
38743
+ var parentSize = this._eventSize;
38744
+ var parentRotation = this._eventRotation;
38745
+ this._evaluateOverLifetime(offset, 0, parentColor, parentSize, parentRotation);
38746
+ this.subEmitters._dispatchEvent(ParticleSubEmitterType.Birth, birthPos, parentColor, parentSize, parentRotation, worldDirection);
38747
+ };
38748
+ /**
38749
+ * @internal
38750
+ */ _proto._emitFromSubEmitter = function _emitFromSubEmitter(count, worldPosition, inheritColor, inheritSize, inheritRotation, worldDirection) {
38751
+ if (count <= 0) return;
38752
+ var main = this.main;
38753
+ var notRetired = this._getNotRetiredParticleCount();
38754
+ var available = main.maxParticles - notRetired;
38755
+ if (available <= 0) return;
38756
+ if (count > available) count = available;
38757
+ var transform = this._renderer.entity.transform;
38758
+ var emitterWorldPosition = transform.worldPosition, emitterWorldRotation = transform.worldRotationQuaternion;
38759
+ // Convert event world position into local emission space for a_ShapePos
38760
+ var localPos = this._emitLocalPos;
38761
+ engineMath.Vector3.subtract(worldPosition, emitterWorldPosition, localPos);
38762
+ var invRot = ParticleGenerator._tempQuat0;
38763
+ engineMath.Quaternion.invert(emitterWorldRotation, invRot);
38764
+ engineMath.Vector3.transformByQuat(localPos, invRot, localPos);
38765
+ var direction = this._emitDirection;
38766
+ if (worldDirection) {
38767
+ engineMath.Vector3.transformByQuat(worldDirection, invRot, direction);
38768
+ var len = Math.sqrt(direction.x * direction.x + direction.y * direction.y + direction.z * direction.z);
38769
+ if (len > engineMath.MathUtil.zeroTolerance) {
38770
+ direction.set(direction.x / len, direction.y / len, direction.z / len);
38771
+ } else {
38772
+ direction.set(0, 0, -1);
38773
+ }
38774
+ } else {
38775
+ direction.set(0, 0, -1);
38776
+ }
38777
+ var playTime = this._playTime;
38778
+ for(var i = 0; i < count; i++){
38779
+ this._addNewParticle(localPos, direction, transform, playTime, undefined, inheritColor, inheritSize, inheritRotation);
38780
+ }
38352
38781
  };
38353
38782
  _proto._addFeedbackParticle = function _addFeedbackParticle(index, shapePosition, direction, startSpeed, transform, emitWorldPosition) {
38354
38783
  var position;
@@ -38372,7 +38801,10 @@ __decorate([
38372
38801
  var engine = this._renderer.engine;
38373
38802
  var frameCount = engine.time.frameCount;
38374
38803
  var instanceVertices = this._instanceVertices;
38375
- while(this._firstActiveElement !== this._firstNewElement){
38804
+ var hasDeathSlot = this.subEmitters._hasSubEmitterOfType(ParticleSubEmitterType.Death);
38805
+ var firstNewElement = this._firstNewElement;
38806
+ var feedbackLoaded = false;
38807
+ while(this._firstActiveElement !== firstNewElement){
38376
38808
  var activeParticleOffset = this._firstActiveElement * ParticleBufferUtils.instanceVertexFloatStride;
38377
38809
  var activeParticleTimeOffset = activeParticleOffset + ParticleBufferUtils.timeOffset;
38378
38810
  var particleAge = this._playTime - instanceVertices[activeParticleTimeOffset];
@@ -38380,6 +38812,13 @@ __decorate([
38380
38812
  if (Math.fround(particleAge) < instanceVertices[activeParticleOffset + ParticleBufferUtils.startLifeTimeOffset]) {
38381
38813
  break;
38382
38814
  }
38815
+ if (hasDeathSlot) {
38816
+ if (this._feedbackSimulator && !feedbackLoaded) {
38817
+ this._readbackFeedback(this._firstActiveElement, firstNewElement);
38818
+ feedbackLoaded = true;
38819
+ }
38820
+ this._onParticleDeath(activeParticleOffset);
38821
+ }
38383
38822
  // Store frame count in time offset to free retired particle
38384
38823
  instanceVertices[activeParticleTimeOffset] = frameCount;
38385
38824
  if (++this._firstActiveElement >= this._currentParticleCount) {
@@ -38389,6 +38828,110 @@ __decorate([
38389
38828
  this._waitProcessRetiredElementCount++;
38390
38829
  }
38391
38830
  };
38831
+ _proto._readbackFeedback = function _readbackFeedback(firstActiveElement, firstNewElement) {
38832
+ var stride = ParticleBufferUtils.feedbackVertexStride;
38833
+ var floatStride = stride / 4;
38834
+ var totalFloatCount = this._currentParticleCount * floatStride;
38835
+ var readback = this._feedbackReadback;
38836
+ if (!readback || readback.length < totalFloatCount) {
38837
+ readback = this._feedbackReadback = new Float32Array(totalFloatCount);
38838
+ }
38839
+ var buffer = this._feedbackSimulator.readBinding.buffer;
38840
+ var wrapped = firstActiveElement >= firstNewElement;
38841
+ var firstSegmentEnd = wrapped ? this._currentParticleCount : firstNewElement;
38842
+ buffer.getData(readback, firstActiveElement * stride, firstActiveElement * floatStride, (firstSegmentEnd - firstActiveElement) * floatStride);
38843
+ if (wrapped && firstNewElement > 0) {
38844
+ buffer.getData(readback, 0, 0, firstNewElement * floatStride);
38845
+ }
38846
+ };
38847
+ _proto._onParticleDeath = function _onParticleDeath(particleOffset) {
38848
+ var instanceVertices = this._instanceVertices;
38849
+ var transform = this._renderer.entity.transform;
38850
+ var simSpaceLocal = this.main.simulationSpace === ParticleSimulationSpace.Local;
38851
+ var worldRotation = transform.worldRotationQuaternion;
38852
+ var ringIndex = particleOffset / ParticleBufferUtils.instanceVertexFloatStride;
38853
+ var feedbackData = this._feedbackReadback;
38854
+ var feedbackOffset = ringIndex * ParticleBufferUtils.feedbackVertexStride / 4;
38855
+ var local = this._eventPos;
38856
+ local.set(feedbackData[feedbackOffset], feedbackData[feedbackOffset + 1], feedbackData[feedbackOffset + 2]);
38857
+ if (simSpaceLocal) {
38858
+ engineMath.Vector3.transformByQuat(local, worldRotation, local);
38859
+ local.add(transform.worldPosition);
38860
+ }
38861
+ var worldDirection = this._eventDir;
38862
+ worldDirection.set(feedbackData[feedbackOffset + 3], feedbackData[feedbackOffset + 4], feedbackData[feedbackOffset + 5]);
38863
+ if (simSpaceLocal) {
38864
+ engineMath.Vector3.transformByQuat(worldDirection, worldRotation, worldDirection);
38865
+ } else {
38866
+ var spawnRotation = ParticleGenerator._tempQuat0;
38867
+ spawnRotation.set(instanceVertices[particleOffset + 30], instanceVertices[particleOffset + 31], instanceVertices[particleOffset + 32], instanceVertices[particleOffset + 33]);
38868
+ engineMath.Vector3.transformByQuat(worldDirection, spawnRotation, worldDirection);
38869
+ }
38870
+ // Evaluate at the parent's normalizedAge so children inherit its visible appearance at death.
38871
+ var lifetime = instanceVertices[particleOffset + 3];
38872
+ var bornTime = instanceVertices[particleOffset + 7];
38873
+ var parentColor = this._eventColor;
38874
+ var parentSize = this._eventSize;
38875
+ var parentRotation = this._eventRotation;
38876
+ var normalizedAge = Math.min(Math.max((this._playTime - bornTime) / lifetime, 0), 1);
38877
+ this._evaluateOverLifetime(particleOffset, normalizedAge, parentColor, parentSize, parentRotation);
38878
+ this.subEmitters._dispatchEvent(ParticleSubEmitterType.Death, local, parentColor, parentSize, parentRotation, worldDirection);
38879
+ };
38880
+ _proto._evaluateOverLifetime = function _evaluateOverLifetime(particleOffset, normalizedAge, parentColor, parentSize, parentRotation) {
38881
+ var instanceVertices = this._instanceVertices;
38882
+ var r = instanceVertices[particleOffset + 8];
38883
+ var g = instanceVertices[particleOffset + 9];
38884
+ var b = instanceVertices[particleOffset + 10];
38885
+ var a = instanceVertices[particleOffset + 11];
38886
+ var col = this.colorOverLifetime;
38887
+ if (col.enabled) {
38888
+ var colorFactor = ParticleGenerator._tempColor;
38889
+ col.color.evaluate(normalizedAge, instanceVertices[particleOffset + 20], colorFactor);
38890
+ r *= colorFactor.r;
38891
+ g *= colorFactor.g;
38892
+ b *= colorFactor.b;
38893
+ a *= colorFactor.a;
38894
+ }
38895
+ parentColor.set(r, g, b, a);
38896
+ var sx = instanceVertices[particleOffset + 12];
38897
+ var sy = instanceVertices[particleOffset + 13];
38898
+ var sz = instanceVertices[particleOffset + 14];
38899
+ var sol = this.sizeOverLifetime;
38900
+ // SOL only contributes in Curve / TwoCurves modes (shader gates on RENDERER_SOL_CURVE_MODE)
38901
+ if (sol.enabled && (sol.sizeX.mode === ParticleCurveMode.Curve || sol.sizeX.mode === ParticleCurveMode.TwoCurves)) {
38902
+ var sizeRand = instanceVertices[particleOffset + 21];
38903
+ if (sol.separateAxes) {
38904
+ sx *= sol.sizeX.evaluate(normalizedAge, sizeRand);
38905
+ sy *= sol.sizeY.evaluate(normalizedAge, sizeRand);
38906
+ sz *= sol.sizeZ.evaluate(normalizedAge, sizeRand);
38907
+ } else {
38908
+ var factor = sol.sizeX.evaluate(normalizedAge, sizeRand);
38909
+ sx *= factor;
38910
+ sy *= factor;
38911
+ sz *= factor;
38912
+ }
38913
+ }
38914
+ parentSize.set(sx, sy, sz);
38915
+ var rx = instanceVertices[particleOffset + 15];
38916
+ var ry = instanceVertices[particleOffset + 16];
38917
+ var rz = instanceVertices[particleOffset + 17];
38918
+ var rol = this.rotationOverLifetime;
38919
+ if (rol.enabled) {
38920
+ var rotRand = instanceVertices[particleOffset + 22];
38921
+ var lifetime = instanceVertices[particleOffset + 3];
38922
+ var rolZ = rol.rotationZ._evaluateCumulative(normalizedAge, rotRand) * lifetime;
38923
+ if (rol.separateAxes) {
38924
+ rx += rol.rotationX._evaluateCumulative(normalizedAge, rotRand) * lifetime;
38925
+ ry += rol.rotationY._evaluateCumulative(normalizedAge, rotRand) * lifetime;
38926
+ rz += rolZ;
38927
+ } else if (this.main.startRotation3D) {
38928
+ rz += rolZ;
38929
+ } else {
38930
+ rx += rolZ; // 2D rotation: shader stores the Z angle in a_StartRotation0.x
38931
+ }
38932
+ }
38933
+ parentRotation.set(rx, ry, rz);
38934
+ };
38392
38935
  _proto._freeRetiredParticles = function _freeRetiredParticles() {
38393
38936
  var frameCount = this._renderer.engine.time.frameCount;
38394
38937
  while(this._firstRetiredElement !== this._firstActiveElement){
@@ -38658,7 +39201,8 @@ ParticleGenerator._tempVector30 = new engineMath.Vector3();
38658
39201
  ParticleGenerator._tempVector31 = new engineMath.Vector3();
38659
39202
  ParticleGenerator._tempVector32 = new engineMath.Vector3();
38660
39203
  ParticleGenerator._tempMat = new engineMath.Matrix();
38661
- ParticleGenerator._tempColor0 = new engineMath.Color();
39204
+ ParticleGenerator._tempColor = new engineMath.Color();
39205
+ ParticleGenerator._tempQuat0 = new engineMath.Quaternion();
38662
39206
  ParticleGenerator._tempParticleRenderers = new Array();
38663
39207
  ParticleGenerator._particleIncreaseCount = 128;
38664
39208
  ParticleGenerator._transformedBoundsIncreaseCount = 16;
@@ -38693,6 +39237,9 @@ __decorate([
38693
39237
  __decorate([
38694
39238
  deepClone
38695
39239
  ], ParticleGenerator.prototype, "noise", void 0);
39240
+ __decorate([
39241
+ deepClone
39242
+ ], ParticleGenerator.prototype, "subEmitters", void 0);
38696
39243
  __decorate([
38697
39244
  deepClone
38698
39245
  ], ParticleGenerator.prototype, "customData", void 0);
@@ -38732,6 +39279,9 @@ __decorate([
38732
39279
  __decorate([
38733
39280
  ignoreClone
38734
39281
  ], ParticleGenerator.prototype, "_feedbackBindingIndex", void 0);
39282
+ __decorate([
39283
+ ignoreClone
39284
+ ], ParticleGenerator.prototype, "_feedbackReadback", void 0);
38735
39285
  __decorate([
38736
39286
  ignoreClone
38737
39287
  ], ParticleGenerator.prototype, "_isPlaying", void 0);
@@ -38762,6 +39312,27 @@ __decorate([
38762
39312
  __decorate([
38763
39313
  ignoreClone
38764
39314
  ], ParticleGenerator.prototype, "_playStartDelay", void 0);
39315
+ __decorate([
39316
+ ignoreClone
39317
+ ], ParticleGenerator.prototype, "_eventPos", void 0);
39318
+ __decorate([
39319
+ ignoreClone
39320
+ ], ParticleGenerator.prototype, "_eventColor", void 0);
39321
+ __decorate([
39322
+ ignoreClone
39323
+ ], ParticleGenerator.prototype, "_eventSize", void 0);
39324
+ __decorate([
39325
+ ignoreClone
39326
+ ], ParticleGenerator.prototype, "_eventRotation", void 0);
39327
+ __decorate([
39328
+ ignoreClone
39329
+ ], ParticleGenerator.prototype, "_eventDir", void 0);
39330
+ __decorate([
39331
+ ignoreClone
39332
+ ], ParticleGenerator.prototype, "_emitLocalPos", void 0);
39333
+ __decorate([
39334
+ ignoreClone
39335
+ ], ParticleGenerator.prototype, "_emitDirection", void 0);
38765
39336
 
38766
39337
  /**
38767
39338
  * Base material for visual effects like particles and trails.
@@ -41075,6 +41646,8 @@ exports.ParticleShapeArcMode = ParticleShapeArcMode;
41075
41646
  exports.ParticleShapeType = ParticleShapeType;
41076
41647
  exports.ParticleSimulationSpace = ParticleSimulationSpace;
41077
41648
  exports.ParticleStopMode = ParticleStopMode;
41649
+ exports.ParticleSubEmitterInheritProperty = ParticleSubEmitterInheritProperty;
41650
+ exports.ParticleSubEmitterType = ParticleSubEmitterType;
41078
41651
  exports.PhysicsMaterial = PhysicsMaterial;
41079
41652
  exports.PhysicsMaterialCombineMode = PhysicsMaterialCombineMode;
41080
41653
  exports.PhysicsScene = PhysicsScene;
@@ -41164,6 +41737,8 @@ exports.SpriteTileMode = SpriteTileMode;
41164
41737
  exports.StateMachineScript = StateMachineScript;
41165
41738
  exports.StaticCollider = StaticCollider;
41166
41739
  exports.StencilOperation = StencilOperation;
41740
+ exports.SubEmitter = SubEmitter;
41741
+ exports.SubEmittersModule = SubEmittersModule;
41167
41742
  exports.SubFont = SubFont;
41168
41743
  exports.SubMesh = SubMesh;
41169
41744
  exports.SubPrimitive = SubPrimitive;