@galacean/engine-core 2.0.0-alpha.16 → 2.0.0-alpha.18

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
@@ -4902,7 +4902,7 @@ var ShadowLib = {
4902
4902
  ShadowVertex: ShadowVertex
4903
4903
  };
4904
4904
 
4905
- var particle_common = "vec3 rotationByQuaternions(in vec3 v, in vec4 q) {\n return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);\n}\n\nvec3 rotationByEuler(in vec3 vector, in vec3 rot) {\n float halfRoll = rot.z * 0.5;\n float halfPitch = rot.x * 0.5;\n float halfYaw = rot.y * 0.5;\n\n float sinRoll = sin(halfRoll);\n float cosRoll = cos(halfRoll);\n float sinPitch = sin(halfPitch);\n float cosPitch = cos(halfPitch);\n float sinYaw = sin(halfYaw);\n float cosYaw = cos(halfYaw);\n\n float cosYawPitch = cosYaw * cosPitch;\n float sinYawPitch = sinYaw * sinPitch;\n\n float quaX = (cosYaw * sinPitch * cosRoll) + (sinYaw * cosPitch * sinRoll);\n float quaY = (sinYaw * cosPitch * cosRoll) - (cosYaw * sinPitch * sinRoll);\n float quaZ = (cosYawPitch * sinRoll) - (sinYawPitch * cosRoll);\n float quaW = (cosYawPitch * cosRoll) + (sinYawPitch * sinRoll);\n\n return rotationByQuaternions(vector, vec4(quaX, quaY, quaZ, quaW));\n}\n\n// Assume axis is normalized\nvec3 rotationByAxis(in vec3 vector, in vec3 axis, in float angle) {\n float halfAngle = angle * 0.5;\n float s = sin(halfAngle);\n\n return rotationByQuaternions(vector, vec4(axis * s, cos(halfAngle)));\n}\n\n\nfloat evaluateParticleCurve(in vec2 keys[4], in float normalizedAge) {\n float value;\n for (int i = 1; i < 4; i++) {\n vec2 key = keys[i];\n float time = key.x;\n if (time >= normalizedAge) {\n vec2 lastKey = keys[i - 1];\n float lastTime = lastKey.x;\n float age = (normalizedAge - lastTime) / (time - lastTime);\n value = mix(lastKey.y, key.y, age);\n break;\n }\n }\n return value;\n}\n\nfloat evaluateParticleCurveCumulative(in vec2 keys[4], in float normalizedAge, out float currentValue){\n float cumulativeValue = 0.0;\n for (int i = 1; i < 4; i++){\n\t vec2 key = keys[i];\n\t float time = key.x;\n\t vec2 lastKey = keys[i - 1];\n\t float lastValue = lastKey.y;\n\n\t if (time >= normalizedAge){\n\t\t float lastTime = lastKey.x;\n float offsetTime = normalizedAge - lastTime;\n\t\t float age = offsetTime / (time - lastTime);\n currentValue = mix(lastValue, key.y, age);\n\t\t cumulativeValue += (lastValue + currentValue) * 0.5 * offsetTime;\n\t\t break;\n\t\t}\n\t else{\n\t\t cumulativeValue += (lastValue + key.y) * 0.5 * (time - lastKey.x);\n\t\t}\n\t}\n return cumulativeValue;\n}\n\nvec4 evaluateParticleGradient(in vec4 colorKeys[4], in float colorMaxTime, in vec2 alphaKeys[4], in float alphaMaxTime, in float t) {\n vec4 value;\n\n float alphaT = min(t, alphaMaxTime);\n for (int i = 0; i < 4; i++) {\n vec2 key = alphaKeys[i];\n if (alphaT <= key.x) {\n if (i == 0) {\n value.a = alphaKeys[0].y;\n } else {\n vec2 lastKey = alphaKeys[i - 1];\n float age = (alphaT - lastKey.x) / (key.x - lastKey.x);\n value.a = mix(lastKey.y, key.y, age);\n }\n break;\n }\n }\n\n float colorT = min(t, colorMaxTime);\n for (int i = 0; i < 4; i++) {\n vec4 key = colorKeys[i];\n if (colorT <= key.x) {\n if (i == 0) {\n value.rgb = colorKeys[0].yzw;\n } else {\n vec4 lastKey = colorKeys[i - 1];\n float age = (colorT - lastKey.x) / (key.x - lastKey.x);\n value.rgb = mix(lastKey.yzw, key.yzw, age);\n }\n break;\n }\n }\n\n return value;\n}"; // eslint-disable-line
4905
+ var particle_common = "vec3 rotationByQuaternions(in vec3 v, in vec4 q) {\n return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);\n}\n\nvec4 quaternionConjugate(in vec4 q) {\n return vec4(-q.xyz, q.w);\n}\n\nvec3 rotationByEuler(in vec3 vector, in vec3 rot) {\n float halfRoll = rot.z * 0.5;\n float halfPitch = rot.x * 0.5;\n float halfYaw = rot.y * 0.5;\n\n float sinRoll = sin(halfRoll);\n float cosRoll = cos(halfRoll);\n float sinPitch = sin(halfPitch);\n float cosPitch = cos(halfPitch);\n float sinYaw = sin(halfYaw);\n float cosYaw = cos(halfYaw);\n\n float cosYawPitch = cosYaw * cosPitch;\n float sinYawPitch = sinYaw * sinPitch;\n\n float quaX = (cosYaw * sinPitch * cosRoll) + (sinYaw * cosPitch * sinRoll);\n float quaY = (sinYaw * cosPitch * cosRoll) - (cosYaw * sinPitch * sinRoll);\n float quaZ = (cosYawPitch * sinRoll) - (sinYawPitch * cosRoll);\n float quaW = (cosYawPitch * cosRoll) + (sinYawPitch * sinRoll);\n\n return rotationByQuaternions(vector, vec4(quaX, quaY, quaZ, quaW));\n}\n\n// Assume axis is normalized\nvec3 rotationByAxis(in vec3 vector, in vec3 axis, in float angle) {\n float halfAngle = angle * 0.5;\n float s = sin(halfAngle);\n\n return rotationByQuaternions(vector, vec4(axis * s, cos(halfAngle)));\n}\n\n\nfloat evaluateParticleCurve(in vec2 keys[4], in float normalizedAge) {\n float value;\n for (int i = 1; i < 4; i++) {\n vec2 key = keys[i];\n float time = key.x;\n if (time >= normalizedAge) {\n vec2 lastKey = keys[i - 1];\n float lastTime = lastKey.x;\n float age = (normalizedAge - lastTime) / (time - lastTime);\n value = mix(lastKey.y, key.y, age);\n break;\n }\n }\n return value;\n}\n\nfloat evaluateParticleCurveCumulative(in vec2 keys[4], in float normalizedAge, out float currentValue){\n float cumulativeValue = 0.0;\n for (int i = 1; i < 4; i++){\n\t vec2 key = keys[i];\n\t float time = key.x;\n\t vec2 lastKey = keys[i - 1];\n\t float lastValue = lastKey.y;\n\n\t if (time >= normalizedAge){\n\t\t float lastTime = lastKey.x;\n float offsetTime = normalizedAge - lastTime;\n\t\t float age = offsetTime / (time - lastTime);\n currentValue = mix(lastValue, key.y, age);\n\t\t cumulativeValue += (lastValue + currentValue) * 0.5 * offsetTime;\n\t\t break;\n\t\t}\n\t else{\n\t\t cumulativeValue += (lastValue + key.y) * 0.5 * (time - lastKey.x);\n\t\t}\n\t}\n return cumulativeValue;\n}\n\nvec4 evaluateParticleGradient(in vec4 colorKeys[4], in float colorMaxTime, in vec2 alphaKeys[4], in float alphaMaxTime, in float t) {\n vec4 value;\n\n float alphaT = min(t, alphaMaxTime);\n for (int i = 0; i < 4; i++) {\n vec2 key = alphaKeys[i];\n if (alphaT <= key.x) {\n if (i == 0) {\n value.a = alphaKeys[0].y;\n } else {\n vec2 lastKey = alphaKeys[i - 1];\n float age = (alphaT - lastKey.x) / (key.x - lastKey.x);\n value.a = mix(lastKey.y, key.y, age);\n }\n break;\n }\n }\n\n float colorT = min(t, colorMaxTime);\n for (int i = 0; i < 4; i++) {\n vec4 key = colorKeys[i];\n if (colorT <= key.x) {\n if (i == 0) {\n value.rgb = colorKeys[0].yzw;\n } else {\n vec4 lastKey = colorKeys[i - 1];\n float age = (colorT - lastKey.x) / (key.x - lastKey.x);\n value.rgb = mix(lastKey.yzw, key.yzw, age);\n }\n break;\n }\n }\n\n return value;\n}"; // eslint-disable-line
4906
4906
 
4907
4907
  var velocity_over_lifetime_module = "#if defined(RENDERER_VOL_CONSTANT_MODE) || defined(RENDERER_VOL_CURVE_MODE)\n #define _VOL_MODULE_ENABLED\n#endif\n\n#ifdef _VOL_MODULE_ENABLED\n uniform int renderer_VOLSpace;\n\n #ifdef RENDERER_VOL_CONSTANT_MODE\n uniform vec3 renderer_VOLMaxConst;\n\n #ifdef RENDERER_VOL_IS_RANDOM_TWO\n uniform vec3 renderer_VOLMinConst;\n #endif\n #endif\n\n #ifdef RENDERER_VOL_CURVE_MODE\n uniform vec2 renderer_VOLMaxGradientX[4]; // x:time y:value\n uniform vec2 renderer_VOLMaxGradientY[4]; // x:time y:value\n uniform vec2 renderer_VOLMaxGradientZ[4]; // x:time y:value\n\n #ifdef RENDERER_VOL_IS_RANDOM_TWO\n uniform vec2 renderer_VOLMinGradientX[4]; // x:time y:value\n uniform vec2 renderer_VOLMinGradientY[4]; // x:time y:value\n uniform vec2 renderer_VOLMinGradientZ[4]; // x:time y:value\n #endif\n #endif\n\n\n vec3 computeVelocityPositionOffset(in float normalizedAge, in float age, out vec3 currentVelocity) {\n vec3 velocityPosition;\n\n #ifdef RENDERER_VOL_CONSTANT_MODE\n currentVelocity = renderer_VOLMaxConst;\n #ifdef RENDERER_VOL_IS_RANDOM_TWO\n currentVelocity = mix(renderer_VOLMinConst, currentVelocity, a_Random1.yzw);\n #endif\n\n velocityPosition = currentVelocity * age;\n #endif\n\n #ifdef RENDERER_VOL_CURVE_MODE\n velocityPosition = vec3(\n evaluateParticleCurveCumulative(renderer_VOLMaxGradientX, normalizedAge, currentVelocity.x),\n evaluateParticleCurveCumulative(renderer_VOLMaxGradientY, normalizedAge, currentVelocity.y),\n evaluateParticleCurveCumulative(renderer_VOLMaxGradientZ, normalizedAge, currentVelocity.z));\n\n #ifdef RENDERER_VOL_IS_RANDOM_TWO\n vec3 minCurrentVelocity;\n vec3 minVelocityPosition = vec3(\n evaluateParticleCurveCumulative(renderer_VOLMinGradientX, normalizedAge, minCurrentVelocity.x),\n evaluateParticleCurveCumulative(renderer_VOLMinGradientY, normalizedAge, minCurrentVelocity.y),\n evaluateParticleCurveCumulative(renderer_VOLMinGradientZ, normalizedAge, minCurrentVelocity.z));\n\n currentVelocity = mix(minCurrentVelocity, currentVelocity, a_Random1.yzw);\n velocityPosition = mix(minVelocityPosition, velocityPosition, a_Random1.yzw);\n #endif\n\n velocityPosition *= vec3(a_ShapePositionStartLifeTime.w);\n #endif\n return velocityPosition;\n }\n#endif\n"; // eslint-disable-line
4908
4908
 
@@ -4914,7 +4914,11 @@ var color_over_lifetime_module = "#if defined(RENDERER_COL_GRADIENT) || defined(
4914
4914
 
4915
4915
  var texture_sheet_animation_module = "#if defined(RENDERER_TSA_FRAME_CURVE) || defined(RENDERER_TSA_FRAME_RANDOM_CURVES)\n uniform float renderer_TSACycles;\n uniform vec3 renderer_TSATillingParams; // x:subU y:subV z:tileCount\n uniform vec2 renderer_TSAFrameMaxCurve[4]; // x:time y:value\n\n #ifdef RENDERER_TSA_FRAME_RANDOM_CURVES\n uniform vec2 renderer_TSAFrameMinCurve[4]; // x:time y:value\n #endif\n#endif\n\nvec2 computeParticleUV(in vec2 uv, in float normalizedAge) {\n #if defined(RENDERER_TSA_FRAME_CURVE) || defined(RENDERER_TSA_FRAME_RANDOM_CURVES)\n float scaledNormalizedAge = normalizedAge * renderer_TSACycles;\n float cycleNormalizedAge = scaledNormalizedAge - floor(scaledNormalizedAge);\n float normalizedFrame = evaluateParticleCurve(renderer_TSAFrameMaxCurve, cycleNormalizedAge);\n #ifdef RENDERER_TSA_FRAME_RANDOM_CURVES\n normalizedFrame = mix(evaluateParticleCurve(renderer_TSAFrameMinCurve, cycleNormalizedAge), normalizedFrame, a_Random1.x);\n #endif\n\n float frame = floor(normalizedFrame * renderer_TSATillingParams.z);\n\n float tileRow = frame * renderer_TSATillingParams.x;\n float tileRowIndex = floor(tileRow);\n uv.x += tileRow - tileRowIndex;\n uv.y += tileRowIndex * renderer_TSATillingParams.y;\n #endif\n \n return uv;\n}\n"; // eslint-disable-line
4916
4916
 
4917
- var force_over_lifetime_module = "#if defined(RENDERER_FOL_CONSTANT_MODE) || defined(RENDERER_FOL_CURVE_MODE)\n #define _FOL_MODULE_ENABLED\n#endif\n\n#ifdef _FOL_MODULE_ENABLED\n attribute vec4 a_Random2;\n\n uniform int renderer_FOLSpace;\n\n #ifdef RENDERER_FOL_CONSTANT_MODE\n uniform vec3 renderer_FOLMaxConst;\n\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n uniform vec3 renderer_FOLMinConst;\n #endif\n\n #endif\n\n #ifdef RENDERER_FOL_CURVE_MODE\n uniform vec2 renderer_FOLMaxGradientX[4];\n uniform vec2 renderer_FOLMaxGradientY[4];\n uniform vec2 renderer_FOLMaxGradientZ[4];\n\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n uniform vec2 renderer_FOLMinGradientX[4];\n uniform vec2 renderer_FOLMinGradientY[4];\n uniform vec2 renderer_FOLMinGradientZ[4];\n #endif\n #endif\n\n // (tHat - t1) * (tHat - t1) * (tHat - t1) * (a2 - a1) / ((t2 - t1) * 6.0) + a1 * (tHat - t1) * (tHat - t1) * 0.5 + v1 * (tHat - t1);\n // to = tHat - t1; tr = t2 - t1\n float computeDisplacementIntegral(in float to, in float tr, in float a1, in float a2, in float v1) {\n return to * to * to * (a2 - a1) / (tr * 6.0) + a1 * to * to * 0.5 + v1 * to;\n }\n\n float evaluateForceParticleCurveCumulative(in vec2 keys[4], in float normalizedAge, out float velocityCumulative) {\n float cumulativeValue = 0.0;\n velocityCumulative = 0.0;\n\n for (int i = 1; i < 4; i++){\n vec2 key = keys[i];\n vec2 lastKey = keys[i - 1];\n float timeRange = (key.x - lastKey.x) * a_ShapePositionStartLifeTime.w;\n\n if (key.x >= normalizedAge){\n float timeOffset = (normalizedAge - lastKey.x) * a_ShapePositionStartLifeTime.w;\n cumulativeValue += computeDisplacementIntegral(timeOffset, timeRange, lastKey.y, key.y, velocityCumulative);\n\n float finalAcceleration = mix(lastKey.y, key.y, timeOffset / timeRange);\n velocityCumulative += 0.5 * timeOffset * (finalAcceleration + lastKey.y);\n break;\n } else { \n cumulativeValue += computeDisplacementIntegral(timeRange, timeRange, lastKey.y, key.y, velocityCumulative);\n velocityCumulative += 0.5 * timeRange * (lastKey.y + key.y);\n }\n }\n return cumulativeValue;\n }\n\n vec3 computeForcePositionOffset(in float normalizedAge, in float age, out vec3 velocityOffset) {\n vec3 forcePosition;\n\n #if defined(RENDERER_FOL_CONSTANT_MODE)\n vec3 forceAcceleration = renderer_FOLMaxConst;\n\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n forceAcceleration = mix(renderer_FOLMinConst, forceAcceleration, vec3(a_Random2.x, a_Random2.y, a_Random2.z));\n #endif\n\n velocityOffset = forceAcceleration * age;\n\n forcePosition = 0.5 * forceAcceleration * age * age;\n #elif defined(RENDERER_FOL_CURVE_MODE)\n forcePosition = vec3(\n evaluateForceParticleCurveCumulative(renderer_FOLMaxGradientX, normalizedAge, velocityOffset.x),\n evaluateForceParticleCurveCumulative(renderer_FOLMaxGradientY, normalizedAge, velocityOffset.y),\n evaluateForceParticleCurveCumulative(renderer_FOLMaxGradientZ, normalizedAge, velocityOffset.z)\n );\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n vec3 minVelocityOffset;\n\n forcePosition = vec3(\n mix(evaluateForceParticleCurveCumulative(renderer_FOLMinGradientX, normalizedAge, minVelocityOffset.x), forcePosition.x, a_Random2.x),\n mix(evaluateForceParticleCurveCumulative(renderer_FOLMinGradientY, normalizedAge, minVelocityOffset.y), forcePosition.y, a_Random2.y),\n mix(evaluateForceParticleCurveCumulative(renderer_FOLMinGradientZ, normalizedAge, minVelocityOffset.z), forcePosition.z, a_Random2.z)\n );\n\n velocityOffset = mix(minVelocityOffset, velocityOffset, vec3(a_Random2.x, a_Random2.y, a_Random2.z));\n #endif\n #endif\n return forcePosition;\n }\n#endif"; // eslint-disable-line
4917
+ var force_over_lifetime_module = "#if defined(RENDERER_FOL_CONSTANT_MODE) || defined(RENDERER_FOL_CURVE_MODE)\n #define _FOL_MODULE_ENABLED\n#endif\n\n#ifdef _FOL_MODULE_ENABLED\n uniform int renderer_FOLSpace;\n\n #ifdef RENDERER_FOL_CONSTANT_MODE\n uniform vec3 renderer_FOLMaxConst;\n\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n uniform vec3 renderer_FOLMinConst;\n #endif\n\n #endif\n\n #ifdef RENDERER_FOL_CURVE_MODE\n uniform vec2 renderer_FOLMaxGradientX[4];\n uniform vec2 renderer_FOLMaxGradientY[4];\n uniform vec2 renderer_FOLMaxGradientZ[4];\n\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n uniform vec2 renderer_FOLMinGradientX[4];\n uniform vec2 renderer_FOLMinGradientY[4];\n uniform vec2 renderer_FOLMinGradientZ[4];\n #endif\n #endif\n\n // (tHat - t1) * (tHat - t1) * (tHat - t1) * (a2 - a1) / ((t2 - t1) * 6.0) + a1 * (tHat - t1) * (tHat - t1) * 0.5 + v1 * (tHat - t1);\n // to = tHat - t1; tr = t2 - t1\n float computeDisplacementIntegral(in float to, in float tr, in float a1, in float a2, in float v1) {\n return to * to * to * (a2 - a1) / (tr * 6.0) + a1 * to * to * 0.5 + v1 * to;\n }\n\n float evaluateForceParticleCurveCumulative(in vec2 keys[4], in float normalizedAge, out float velocityCumulative) {\n float cumulativeValue = 0.0;\n velocityCumulative = 0.0;\n\n for (int i = 1; i < 4; i++){\n vec2 key = keys[i];\n vec2 lastKey = keys[i - 1];\n float timeRange = (key.x - lastKey.x) * a_ShapePositionStartLifeTime.w;\n\n if (key.x >= normalizedAge){\n float timeOffset = (normalizedAge - lastKey.x) * a_ShapePositionStartLifeTime.w;\n cumulativeValue += computeDisplacementIntegral(timeOffset, timeRange, lastKey.y, key.y, velocityCumulative);\n\n float finalAcceleration = mix(lastKey.y, key.y, timeOffset / timeRange);\n velocityCumulative += 0.5 * timeOffset * (finalAcceleration + lastKey.y);\n break;\n } else { \n cumulativeValue += computeDisplacementIntegral(timeRange, timeRange, lastKey.y, key.y, velocityCumulative);\n velocityCumulative += 0.5 * timeRange * (lastKey.y + key.y);\n }\n }\n return cumulativeValue;\n }\n\n vec3 computeForcePositionOffset(in float normalizedAge, in float age, out vec3 velocityOffset) {\n vec3 forcePosition;\n\n #if defined(RENDERER_FOL_CONSTANT_MODE)\n vec3 forceAcceleration = renderer_FOLMaxConst;\n\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n forceAcceleration = mix(renderer_FOLMinConst, forceAcceleration, vec3(a_Random2.x, a_Random2.y, a_Random2.z));\n #endif\n\n velocityOffset = forceAcceleration * age;\n\n forcePosition = 0.5 * forceAcceleration * age * age;\n #elif defined(RENDERER_FOL_CURVE_MODE)\n forcePosition = vec3(\n evaluateForceParticleCurveCumulative(renderer_FOLMaxGradientX, normalizedAge, velocityOffset.x),\n evaluateForceParticleCurveCumulative(renderer_FOLMaxGradientY, normalizedAge, velocityOffset.y),\n evaluateForceParticleCurveCumulative(renderer_FOLMaxGradientZ, normalizedAge, velocityOffset.z)\n );\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n vec3 minVelocityOffset;\n\n forcePosition = vec3(\n mix(evaluateForceParticleCurveCumulative(renderer_FOLMinGradientX, normalizedAge, minVelocityOffset.x), forcePosition.x, a_Random2.x),\n mix(evaluateForceParticleCurveCumulative(renderer_FOLMinGradientY, normalizedAge, minVelocityOffset.y), forcePosition.y, a_Random2.y),\n mix(evaluateForceParticleCurveCumulative(renderer_FOLMinGradientZ, normalizedAge, minVelocityOffset.z), forcePosition.z, a_Random2.z)\n );\n\n velocityOffset = mix(minVelocityOffset, velocityOffset, vec3(a_Random2.x, a_Random2.y, a_Random2.z));\n #endif\n #endif\n return forcePosition;\n }\n#endif"; // eslint-disable-line
4918
+
4919
+ var limit_velocity_over_lifetime_module = "#ifdef RENDERER_LVL_MODULE_ENABLED\n uniform int renderer_LVLSpace;\n uniform float renderer_LVLDampen;\n\n // Scalar limit\n #ifndef RENDERER_LVL_SEPARATE_AXES\n #ifdef RENDERER_LVL_SPEED_CONSTANT_MODE\n uniform float renderer_LVLSpeedMaxConst;\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n uniform float renderer_LVLSpeedMinConst;\n #endif\n #endif\n #ifdef RENDERER_LVL_SPEED_CURVE_MODE\n uniform vec2 renderer_LVLSpeedMaxCurve[4];\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n uniform vec2 renderer_LVLSpeedMinCurve[4];\n #endif\n #endif\n #endif\n\n // Per-axis limit\n #ifdef RENDERER_LVL_SEPARATE_AXES\n #ifdef RENDERER_LVL_SPEED_CONSTANT_MODE\n uniform vec3 renderer_LVLSpeedMaxConstVector;\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n uniform vec3 renderer_LVLSpeedMinConstVector;\n #endif\n #endif\n #ifdef RENDERER_LVL_SPEED_CURVE_MODE\n uniform vec2 renderer_LVLSpeedXMaxCurve[4];\n uniform vec2 renderer_LVLSpeedYMaxCurve[4];\n uniform vec2 renderer_LVLSpeedZMaxCurve[4];\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n uniform vec2 renderer_LVLSpeedXMinCurve[4];\n uniform vec2 renderer_LVLSpeedYMinCurve[4];\n uniform vec2 renderer_LVLSpeedZMinCurve[4];\n #endif\n #endif\n #endif\n\n // Drag curve\n #ifdef RENDERER_LVL_DRAG_CURVE_MODE\n uniform vec2 renderer_LVLDragMaxCurve[4];\n #ifdef RENDERER_LVL_DRAG_IS_RANDOM_TWO\n uniform vec2 renderer_LVLDragMinCurve[4];\n #endif\n #endif\n\n float evaluateLVLDrag(float normalizedAge, float dragRand) {\n #ifdef RENDERER_LVL_DRAG_CURVE_MODE\n float dragMax = evaluateParticleCurve(renderer_LVLDragMaxCurve, normalizedAge);\n #ifdef RENDERER_LVL_DRAG_IS_RANDOM_TWO\n float dragMin = evaluateParticleCurve(renderer_LVLDragMinCurve, normalizedAge);\n return mix(dragMin, dragMax, dragRand);\n #else\n return dragMax;\n #endif\n #else\n return mix(renderer_LVLDragConstant.x, renderer_LVLDragConstant.y, dragRand);\n #endif\n }\n\n vec3 applyLVLSpeedLimitTF(vec3 velocity, float normalizedAge, float limitRand, float effectiveDampen) {\n #ifdef RENDERER_LVL_SEPARATE_AXES\n vec3 limitSpeed;\n #ifdef RENDERER_LVL_SPEED_CONSTANT_MODE\n limitSpeed = renderer_LVLSpeedMaxConstVector;\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n limitSpeed = mix(renderer_LVLSpeedMinConstVector, limitSpeed, limitRand);\n #endif\n #endif\n #ifdef RENDERER_LVL_SPEED_CURVE_MODE\n limitSpeed = vec3(\n evaluateParticleCurve(renderer_LVLSpeedXMaxCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLSpeedYMaxCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLSpeedZMaxCurve, normalizedAge)\n );\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n vec3 minLimitSpeed = vec3(\n evaluateParticleCurve(renderer_LVLSpeedXMinCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLSpeedYMinCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLSpeedZMinCurve, normalizedAge)\n );\n limitSpeed = mix(minLimitSpeed, limitSpeed, limitRand);\n #endif\n #endif\n\n vec3 absVel = abs(velocity);\n vec3 excess = max(absVel - limitSpeed, vec3(0.0));\n velocity = sign(velocity) * (absVel - excess * effectiveDampen);\n #else\n float limitSpeed;\n #ifdef RENDERER_LVL_SPEED_CONSTANT_MODE\n limitSpeed = renderer_LVLSpeedMaxConst;\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n limitSpeed = mix(renderer_LVLSpeedMinConst, limitSpeed, limitRand);\n #endif\n #endif\n #ifdef RENDERER_LVL_SPEED_CURVE_MODE\n limitSpeed = evaluateParticleCurve(renderer_LVLSpeedMaxCurve, normalizedAge);\n #ifdef RENDERER_LVL_SPEED_IS_RANDOM_TWO\n float minLimitSpeed = evaluateParticleCurve(renderer_LVLSpeedMinCurve, normalizedAge);\n limitSpeed = mix(minLimitSpeed, limitSpeed, limitRand);\n #endif\n #endif\n\n float speed = length(velocity);\n if (speed > limitSpeed && speed > 0.0) {\n float excess = speed - limitSpeed;\n velocity = velocity * ((speed - excess * effectiveDampen) / speed);\n }\n #endif\n return velocity;\n }\n\n#endif\n"; // eslint-disable-line
4920
+
4921
+ var particle_feedback_simulation = "// Transform Feedback update shader for particle simulation.\n// Update order: VOL/FOL → Dampen → Drag → Position.\n// Runs once per particle per frame (no rasterization).\n\n// Previous frame TF data\nattribute vec3 a_FeedbackPosition;\nattribute vec3 a_FeedbackVelocity;\n\n// Per-particle instance data\nattribute vec4 a_ShapePositionStartLifeTime;\nattribute vec4 a_DirectionTime;\nattribute vec3 a_StartSize;\nattribute float a_StartSpeed;\nattribute vec4 a_Random0;\nattribute vec4 a_Random1;\nattribute vec3 a_SimulationWorldPosition;\nattribute vec4 a_SimulationWorldRotation;\nattribute vec4 a_Random2;\n\n// Uniforms\nuniform float renderer_CurrentTime;\nuniform float renderer_DeltaTime;\nuniform vec3 renderer_Gravity;\nuniform vec2 renderer_LVLDragConstant;\nuniform vec3 renderer_WorldPosition;\nuniform vec4 renderer_WorldRotation;\nuniform int renderer_SimulationSpace;\n\n// TF outputs\nvarying vec3 v_FeedbackPosition;\nvarying vec3 v_FeedbackVelocity;\n\n#include <particle_common>\n#include <velocity_over_lifetime_module>\n#include <force_over_lifetime_module>\n#include <limit_velocity_over_lifetime_module>\n\n// Get VOL instantaneous velocity at normalizedAge\nvec3 getVOLVelocity(float normalizedAge) {\n vec3 vel = vec3(0.0);\n #ifdef _VOL_MODULE_ENABLED\n #ifdef RENDERER_VOL_CONSTANT_MODE\n vel = renderer_VOLMaxConst;\n #ifdef RENDERER_VOL_IS_RANDOM_TWO\n vel = mix(renderer_VOLMinConst, vel, a_Random1.yzw);\n #endif\n #endif\n #ifdef RENDERER_VOL_CURVE_MODE\n vel = vec3(\n evaluateParticleCurve(renderer_VOLMaxGradientX, normalizedAge),\n evaluateParticleCurve(renderer_VOLMaxGradientY, normalizedAge),\n evaluateParticleCurve(renderer_VOLMaxGradientZ, normalizedAge)\n );\n #ifdef RENDERER_VOL_IS_RANDOM_TWO\n vec3 minVel = vec3(\n evaluateParticleCurve(renderer_VOLMinGradientX, normalizedAge),\n evaluateParticleCurve(renderer_VOLMinGradientY, normalizedAge),\n evaluateParticleCurve(renderer_VOLMinGradientZ, normalizedAge)\n );\n vel = mix(minVel, vel, a_Random1.yzw);\n #endif\n #endif\n #endif\n return vel;\n}\n\n// Get FOL instantaneous acceleration at normalizedAge\nvec3 getFOLAcceleration(float normalizedAge) {\n vec3 acc = vec3(0.0);\n #ifdef _FOL_MODULE_ENABLED\n #ifdef RENDERER_FOL_CONSTANT_MODE\n acc = renderer_FOLMaxConst;\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n acc = mix(renderer_FOLMinConst, acc, vec3(a_Random2.x, a_Random2.y, a_Random2.z));\n #endif\n #endif\n #ifdef RENDERER_FOL_CURVE_MODE\n acc = vec3(\n evaluateParticleCurve(renderer_FOLMaxGradientX, normalizedAge),\n evaluateParticleCurve(renderer_FOLMaxGradientY, normalizedAge),\n evaluateParticleCurve(renderer_FOLMaxGradientZ, normalizedAge)\n );\n #ifdef RENDERER_FOL_IS_RANDOM_TWO\n vec3 minAcc = vec3(\n evaluateParticleCurve(renderer_FOLMinGradientX, normalizedAge),\n evaluateParticleCurve(renderer_FOLMinGradientY, normalizedAge),\n evaluateParticleCurve(renderer_FOLMinGradientZ, normalizedAge)\n );\n acc = mix(minAcc, acc, vec3(a_Random2.x, a_Random2.y, a_Random2.z));\n #endif\n #endif\n #endif\n return acc;\n}\n\nvoid main() {\n float age = renderer_CurrentTime - a_DirectionTime.w;\n float lifetime = a_ShapePositionStartLifeTime.w;\n float normalizedAge = age / lifetime;\n // Clamp to age on the first TF pass: particles emitted mid-frame have age < dt,\n // so using the full dt would over-integrate. Subsequent passes are unaffected (age >= dt).\n float dt = min(renderer_DeltaTime, age);\n\n // normalizedAge < 0.0: stale TF slot whose startTime is from a previous playback (e.g. after StopEmittingAndClear).\n if (normalizedAge >= 1.0 || normalizedAge < 0.0) {\n v_FeedbackPosition = a_FeedbackPosition;\n v_FeedbackVelocity = a_FeedbackVelocity;\n gl_Position = vec4(0.0);\n return;\n }\n\n vec4 worldRotation;\n if (renderer_SimulationSpace == 0) {\n worldRotation = renderer_WorldRotation;\n } else {\n worldRotation = a_SimulationWorldRotation;\n }\n vec4 invWorldRotation = quaternionConjugate(worldRotation);\n\n // Read previous frame state (initialized by CPU on particle birth)\n vec3 localVelocity = a_FeedbackVelocity;\n\n // =====================================================\n // Step 1: Apply velocity module deltas (VOL + FOL + Gravity)\n // =====================================================\n\n // Gravity (world space)\n vec3 gravityDelta = renderer_Gravity * a_Random0.x * dt;\n\n // VOL instantaneous velocity (animated velocity, not persisted)\n vec3 volLocal = vec3(0.0);\n vec3 volWorld = vec3(0.0);\n #ifdef _VOL_MODULE_ENABLED\n vec3 vol = getVOLVelocity(normalizedAge);\n if (renderer_VOLSpace == 0) {\n volLocal = vol;\n } else {\n volWorld = vol;\n }\n #endif\n\n // FOL acceleration → velocity delta (always persisted, like gravity)\n vec3 folDeltaLocal = vec3(0.0);\n #ifdef _FOL_MODULE_ENABLED\n vec3 folAcc = getFOLAcceleration(normalizedAge);\n vec3 folVelDelta = folAcc * dt;\n if (renderer_FOLSpace == 0) {\n folDeltaLocal = folVelDelta;\n } else {\n // World FOL: convert to local and persist, same as gravity\n folDeltaLocal = rotationByQuaternions(folVelDelta, invWorldRotation);\n }\n #endif\n\n // Gravity and FOL contribute to base velocity (persisted, subject to dampen/drag).\n vec3 gravityLocal = rotationByQuaternions(gravityDelta, invWorldRotation);\n localVelocity += folDeltaLocal + gravityLocal;\n\n // =====================================================\n // Step 2 & 3: Dampen (Limit Velocity) + Drag\n // VOL must be projected into the LVL target space so that\n // limit/drag see the full velocity regardless of VOL.space vs LVL.space.\n // =====================================================\n #ifdef RENDERER_LVL_MODULE_ENABLED\n // Precompute VOL in both spaces\n vec3 volAsLocal = volLocal + rotationByQuaternions(volWorld, invWorldRotation);\n vec3 volAsWorld = rotationByQuaternions(volLocal, worldRotation) + volWorld;\n\n float limitRand = a_Random2.w;\n float dampen = renderer_LVLDampen;\n // Frame-rate independent dampen (30fps as reference)\n float effectiveDampen = 1.0 - pow(1.0 - dampen, dt * 30.0);\n\n if (renderer_LVLSpace == 0) {\n // Local space: total = base + all VOL projected to local\n vec3 totalLocal = localVelocity + volAsLocal;\n vec3 dampenedTotal = applyLVLSpeedLimitTF(totalLocal, normalizedAge, limitRand, effectiveDampen);\n localVelocity = dampenedTotal - volAsLocal;\n } else {\n // World space: total = rotated base + all VOL projected to world\n vec3 totalWorld = rotationByQuaternions(localVelocity, worldRotation) + volAsWorld;\n vec3 dampenedTotal = applyLVLSpeedLimitTF(totalWorld, normalizedAge, limitRand, effectiveDampen);\n localVelocity = rotationByQuaternions(dampenedTotal - volAsWorld, invWorldRotation);\n }\n\n // Drag: same space as dampen\n {\n float dragCoeff = evaluateLVLDrag(normalizedAge, a_Random2.w);\n if (dragCoeff > 0.0) {\n vec3 totalVel;\n if (renderer_LVLSpace == 0) {\n totalVel = localVelocity + volAsLocal;\n } else {\n totalVel = rotationByQuaternions(localVelocity, worldRotation) + volAsWorld;\n }\n float velMagSqr = dot(totalVel, totalVel);\n float velMag = sqrt(velMagSqr);\n\n float drag = dragCoeff;\n\n #ifdef RENDERER_LVL_DRAG_MULTIPLY_SIZE\n float maxDim = max(a_StartSize.x, max(a_StartSize.y, a_StartSize.z));\n float radius = maxDim * 0.5;\n drag *= 3.14159265 * radius * radius;\n #endif\n\n #ifdef RENDERER_LVL_DRAG_MULTIPLY_VELOCITY\n drag *= velMagSqr;\n #endif\n\n if (velMag > 0.0) {\n float newVelMag = max(0.0, velMag - drag * dt);\n vec3 draggedTotal = totalVel * (newVelMag / velMag);\n if (renderer_LVLSpace == 0) {\n localVelocity = draggedTotal - volAsLocal;\n } else {\n localVelocity = rotationByQuaternions(draggedTotal - volAsWorld, invWorldRotation);\n }\n }\n }\n }\n #endif\n\n // =====================================================\n // Step 4: Integrate position in simulation space\n // Local mode: position in local space, velocity rotated to local\n // World mode: position in world space, velocity rotated to world\n // =====================================================\n // FOL is now fully in localVelocity (both local and world-space FOL).\n // Only VOL overlay needs to be added here.\n vec3 totalVelocity;\n if (renderer_SimulationSpace == 0) {\n // Local: integrate in local space\n totalVelocity = localVelocity + volLocal\n + rotationByQuaternions(volWorld, invWorldRotation);\n } else {\n // World: integrate in world space\n totalVelocity = rotationByQuaternions(localVelocity + volLocal, worldRotation) + volWorld;\n }\n vec3 position = a_FeedbackPosition + totalVelocity * dt;\n\n v_FeedbackPosition = position;\n v_FeedbackVelocity = localVelocity;\n gl_Position = vec4(0.0);\n}\n"; // eslint-disable-line
4918
4922
 
4919
4923
  var sphere_billboard = "#ifdef RENDERER_MODE_SPHERE_BILLBOARD\n\tvec2 corner = a_CornerTextureCoordinate.xy + renderer_PivotOffset.xy;\n\tvec3 sideVector = normalize(cross(camera_Forward, camera_Up));\n\tvec3 upVector = normalize(cross(sideVector, camera_Forward));\n\tcorner *= computeParticleSizeBillboard(a_StartSize.xy, normalizedAge);\n #if defined(RENDERER_ROL_CONSTANT_MODE) || defined(RENDERER_ROL_CURVE_MODE)\n if (renderer_ThreeDStartRotation) {\n vec3 rotation = radians(vec3(a_StartRotation0.xy, computeParticleRotationFloat(a_StartRotation0.z, age, normalizedAge)));\n center += renderer_SizeScale.xzy * rotationByEuler(corner.x * sideVector + corner.y * upVector, rotation);\n } else {\n float rot = radians(computeParticleRotationFloat(a_StartRotation0.x, age, normalizedAge));\n float c = cos(rot);\n float s = sin(rot);\n mat2 rotation = mat2(c, -s, s, c);\n corner = rotation * corner;\n center += renderer_SizeScale.xzy * (corner.x * sideVector + corner.y * upVector);\n }\n #else\n if (renderer_ThreeDStartRotation) {\n center += renderer_SizeScale.xzy * rotationByEuler(corner.x * sideVector + corner.y * upVector, radians(a_StartRotation0));\n } else {\n float c = cos(radians(a_StartRotation0.x));\n float s = sin(radians(a_StartRotation0.x));\n mat2 rotation = mat2(c, -s, s, c);\n corner = rotation * corner;\n center += renderer_SizeScale.xzy * (corner.x * sideVector + corner.y * upVector);\n }\n #endif\n#endif"; // eslint-disable-line
4920
4924
 
@@ -4934,6 +4938,8 @@ var ParticleShaderLib = {
4934
4938
  color_over_lifetime_module: color_over_lifetime_module,
4935
4939
  texture_sheet_animation_module: texture_sheet_animation_module,
4936
4940
  force_over_lifetime_module: force_over_lifetime_module,
4941
+ limit_velocity_over_lifetime_module: limit_velocity_over_lifetime_module,
4942
+ particle_feedback_simulation: particle_feedback_simulation,
4937
4943
  sphere_billboard: sphere_billboard,
4938
4944
  stretched_billboard: stretched_billboard,
4939
4945
  vertical_billboard: vertical_billboard,
@@ -5000,6 +5006,41 @@ var ShaderFactory = /*#__PURE__*/ function() {
5000
5006
  return "#define " + (m.value ? m.name + " " + m.value : m.name) + "\n";
5001
5007
  }).join("");
5002
5008
  };
5009
+ /**
5010
+ * @internal
5011
+ * Compile vertex and fragment source with standard macros, includes, and version header.
5012
+ * @param engine - Engine instance
5013
+ * @param macroCollection - Current macro collection
5014
+ * @param vertexSource - Raw vertex shader source (may contain #include)
5015
+ * @param fragmentSource - Raw fragment shader source
5016
+ * @returns Compiled { vertexSource, fragmentSource } ready for ShaderProgram
5017
+ */ ShaderFactory.compilePlatformSource = function compilePlatformSource(engine, macroCollection, vertexSource, fragmentSource) {
5018
+ var isWebGL2 = engine._hardwareRenderer.isWebGL2;
5019
+ var shaderMacroList = new Array();
5020
+ ShaderMacro._getMacrosElements(macroCollection, shaderMacroList);
5021
+ shaderMacroList.push(ShaderMacro.getByName(isWebGL2 ? "GRAPHICS_API_WEBGL2" : "GRAPHICS_API_WEBGL1"));
5022
+ if (engine._hardwareRenderer.canIUse(GLCapabilityType.shaderTextureLod)) {
5023
+ shaderMacroList.push(ShaderMacro.getByName("HAS_TEX_LOD"));
5024
+ }
5025
+ if (engine._hardwareRenderer.canIUse(GLCapabilityType.standardDerivatives)) {
5026
+ shaderMacroList.push(ShaderMacro.getByName("HAS_DERIVATIVES"));
5027
+ }
5028
+ var noIncludeVertex = ShaderFactory.parseIncludes(vertexSource);
5029
+ var noIncludeFrag = ShaderFactory.parseIncludes(fragmentSource);
5030
+ var macroStr = ShaderFactory.parseCustomMacros(shaderMacroList);
5031
+ noIncludeVertex = macroStr + noIncludeVertex;
5032
+ noIncludeFrag = macroStr + noIncludeFrag;
5033
+ if (isWebGL2) {
5034
+ noIncludeVertex = ShaderFactory.convertTo300(noIncludeVertex);
5035
+ noIncludeFrag = ShaderFactory.convertTo300(noIncludeFrag, true);
5036
+ }
5037
+ var versionStr = isWebGL2 ? "#version 300 es" : "#version 100";
5038
+ var precisionStr = "\n#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n precision highp int;\n#else\n precision mediump float;\n precision mediump int;\n#endif\n";
5039
+ return {
5040
+ vertexSource: versionStr + "\nprecision highp float;\n" + noIncludeVertex,
5041
+ fragmentSource: versionStr + "\n" + (isWebGL2 ? "" : ShaderFactory._shaderExtension) + precisionStr + noIncludeFrag
5042
+ };
5043
+ };
5003
5044
  ShaderFactory.registerInclude = function registerInclude(includeName, includeSource) {
5004
5045
  if (ShaderLib[includeName]) {
5005
5046
  throw 'The "' + includeName + '" shader include already exist';
@@ -5332,7 +5373,7 @@ ShaderTagKey._nameMap = Object.create(null);
5332
5373
  * Shader program, corresponding to the GPU shader program.
5333
5374
  * @internal
5334
5375
  */ var ShaderProgram = /*#__PURE__*/ function() {
5335
- function ShaderProgram(engine, vertexSource, fragmentSource) {
5376
+ function ShaderProgram(engine, vertexSource, fragmentSource, transformFeedbackVaryings) {
5336
5377
  this.sceneUniformBlock = new ShaderUniformBlock();
5337
5378
  this.cameraUniformBlock = new ShaderUniformBlock();
5338
5379
  this.rendererUniformBlock = new ShaderUniformBlock();
@@ -5348,7 +5389,7 @@ ShaderTagKey._nameMap = Object.create(null);
5348
5389
  this._activeTextureUint = 0;
5349
5390
  this._engine = engine;
5350
5391
  this._gl = engine._hardwareRenderer.gl;
5351
- this._glProgram = this._createProgram(vertexSource, fragmentSource);
5392
+ this._glProgram = this._createProgram(vertexSource, fragmentSource, transformFeedbackVaryings);
5352
5393
  if (this._glProgram) {
5353
5394
  this._isValid = true;
5354
5395
  this._recordLocation();
@@ -5494,7 +5535,7 @@ ShaderTagKey._nameMap = Object.create(null);
5494
5535
  };
5495
5536
  /**
5496
5537
  * Init and link program with shader.
5497
- */ _proto._createProgram = function _createProgram(vertexSource, fragmentSource) {
5538
+ */ _proto._createProgram = function _createProgram(vertexSource, fragmentSource, transformFeedbackVaryings) {
5498
5539
  var gl = this._gl;
5499
5540
  // Create and compile shader
5500
5541
  var vertexShader = this._createShader(gl.VERTEX_SHADER, vertexSource);
@@ -5512,6 +5553,10 @@ ShaderTagKey._nameMap = Object.create(null);
5512
5553
  }
5513
5554
  gl.attachShader(program, vertexShader);
5514
5555
  gl.attachShader(program, fragmentShader);
5556
+ // Set Transform Feedback varyings before linking (WebGL2 only)
5557
+ if (transformFeedbackVaryings == null ? void 0 : transformFeedbackVaryings.length) {
5558
+ gl.transformFeedbackVaryings(program, transformFeedbackVaryings, gl.INTERLEAVED_ATTRIBS);
5559
+ }
5515
5560
  gl.linkProgram(program);
5516
5561
  gl.validateProgram(program);
5517
5562
  gl.deleteShader(vertexShader);
@@ -5775,7 +5820,7 @@ var precisionStr = "\n #ifdef GL_FRAGMENT_PRECISION_HIGH\n precision hig
5775
5820
  /**
5776
5821
  * @internal
5777
5822
  */ _proto._getShaderProgram = function _getShaderProgram(engine, macroCollection) {
5778
- var shaderProgramPool = engine._getShaderProgramPool(this);
5823
+ var shaderProgramPool = engine._getShaderProgramPool(this._shaderPassId, this._shaderProgramPools);
5779
5824
  var shaderProgram = shaderProgramPool.get(macroCollection);
5780
5825
  if (shaderProgram) {
5781
5826
  return shaderProgram;
@@ -5797,6 +5842,13 @@ var precisionStr = "\n #ifdef GL_FRAGMENT_PRECISION_HIGH\n precision hig
5797
5842
  shaderProgramPools.length = 0;
5798
5843
  };
5799
5844
  _proto._getCanonicalShaderProgram = function _getCanonicalShaderProgram(engine, macroCollection) {
5845
+ if (this._platformTarget != undefined) {
5846
+ return this._getShaderLabProgram(engine, macroCollection);
5847
+ }
5848
+ var _ShaderFactory_compilePlatformSource = ShaderFactory.compilePlatformSource(engine, macroCollection, this._vertexSource, this._fragmentSource), vertexSource = _ShaderFactory_compilePlatformSource.vertexSource, fragmentSource = _ShaderFactory_compilePlatformSource.fragmentSource;
5849
+ return new ShaderProgram(engine, vertexSource, fragmentSource);
5850
+ };
5851
+ _proto._getShaderLabProgram = function _getShaderLabProgram(engine, macroCollection) {
5800
5852
  var isWebGL2 = engine._hardwareRenderer.isWebGL2;
5801
5853
  var shaderMacroList = new Array();
5802
5854
  ShaderMacro._getMacrosElements(macroCollection, shaderMacroList);
@@ -5807,32 +5859,22 @@ var precisionStr = "\n #ifdef GL_FRAGMENT_PRECISION_HIGH\n precision hig
5807
5859
  if (engine._hardwareRenderer.canIUse(GLCapabilityType.standardDerivatives)) {
5808
5860
  shaderMacroList.push(ShaderMacro.getByName("HAS_DERIVATIVES"));
5809
5861
  }
5810
- // Compatible with non-shaderlab syntax
5811
5862
  var noIncludeVertex = ShaderFactory.parseIncludes(this._vertexSource);
5812
5863
  var noIncludeFrag = ShaderFactory.parseIncludes(this._fragmentSource);
5813
- // Parse macros when use shaderlab
5814
- if (this._platformTarget != undefined) {
5815
- noIncludeVertex = Shader._shaderLab._parseMacros(noIncludeVertex, shaderMacroList);
5816
- noIncludeFrag = Shader._shaderLab._parseMacros(noIncludeFrag, shaderMacroList);
5817
- } else {
5818
- var macroNameStr = ShaderFactory.parseCustomMacros(shaderMacroList);
5819
- noIncludeVertex = macroNameStr + noIncludeVertex;
5820
- noIncludeFrag = macroNameStr + noIncludeFrag;
5821
- }
5822
- // Need to convert to 300 es when the target is GLSL ES 100 or unkdown
5823
- if (isWebGL2 && (this._platformTarget == undefined || this._platformTarget === ShaderLanguage.GLSLES100)) {
5864
+ noIncludeVertex = Shader._shaderLab._parseMacros(noIncludeVertex, shaderMacroList);
5865
+ noIncludeFrag = Shader._shaderLab._parseMacros(noIncludeFrag, shaderMacroList);
5866
+ if (isWebGL2 && this._platformTarget === ShaderLanguage.GLSLES100) {
5824
5867
  noIncludeVertex = ShaderFactory.convertTo300(noIncludeVertex);
5825
5868
  noIncludeFrag = ShaderFactory.convertTo300(noIncludeFrag, true);
5826
5869
  }
5827
5870
  var versionStr = isWebGL2 ? "#version 300 es" : "#version 100";
5828
- var vertexSource = " " + versionStr + " \n " + noIncludeVertex + "\n ";
5871
+ var vertexSource = " " + versionStr + "\n " + noIncludeVertex + "\n ";
5829
5872
  var fragmentSource = " " + versionStr + "\n " + (isWebGL2 ? "" : ShaderFactory._shaderExtension) + "\n " + precisionStr + "\n " + noIncludeFrag + "\n ";
5830
- var shaderProgram = new ShaderProgram(engine, vertexSource, fragmentSource);
5831
- return shaderProgram;
5873
+ return new ShaderProgram(engine, vertexSource, fragmentSource);
5832
5874
  };
5833
5875
  return ShaderPass;
5834
5876
  }(ShaderPart);
5835
- ShaderPass._shaderPassCounter = 0;
5877
+ /** @internal */ ShaderPass._shaderPassCounter = 0;
5836
5878
  /** @internal */ ShaderPass._shaderRootPath = "shaders://root/";
5837
5879
 
5838
5880
  /**
@@ -18471,6 +18513,15 @@ var TextChunk = function TextChunk() {
18471
18513
  this._platformBuffer.getData(data, bufferByteOffset, dataOffset, dataLength);
18472
18514
  };
18473
18515
  /**
18516
+ * Copy data from another buffer on the GPU.
18517
+ * @param srcBuffer - Source buffer
18518
+ * @param srcByteOffset - Byte offset in the source buffer
18519
+ * @param dstByteOffset - Byte offset in this buffer
18520
+ * @param byteLength - Number of bytes to copy
18521
+ */ _proto.copyFromBuffer = function copyFromBuffer(srcBuffer, srcByteOffset, dstByteOffset, byteLength) {
18522
+ this._platformBuffer.copyFromBuffer(srcBuffer._platformBuffer, srcByteOffset, dstByteOffset, byteLength);
18523
+ };
18524
+ /**
18474
18525
  * Mark buffer as readable, the `data` property will be not accessible anymore.
18475
18526
  */ _proto.markAsUnreadable = function markAsUnreadable() {
18476
18527
  this._data = null;
@@ -18765,8 +18816,8 @@ var BufferUtil = /*#__PURE__*/ function() {
18765
18816
  /**
18766
18817
  * Buffer binding flag.
18767
18818
  */ var BufferBindFlag = /*#__PURE__*/ function(BufferBindFlag) {
18768
- /** Vertex buffer binding flag */ BufferBindFlag[BufferBindFlag["VertexBuffer"] = 0] = "VertexBuffer";
18769
- /** Index buffer binding flag */ BufferBindFlag[BufferBindFlag["IndexBuffer"] = 1] = "IndexBuffer";
18819
+ /** Vertex buffer binding flag. */ BufferBindFlag[BufferBindFlag["VertexBuffer"] = 0] = "VertexBuffer";
18820
+ /** Index buffer binding flag. */ BufferBindFlag[BufferBindFlag["IndexBuffer"] = 1] = "IndexBuffer";
18770
18821
  return BufferBindFlag;
18771
18822
  }({});
18772
18823
 
@@ -26202,6 +26253,15 @@ PointerEventEmitter._tempRay = new engineMath.Ray();
26202
26253
  return ParticleBillboardVertexAttribute;
26203
26254
  }({});
26204
26255
 
26256
+ /**
26257
+ * @internal
26258
+ * Vertex attributes for the Transform Feedback buffer.
26259
+ */ var ParticleFeedbackVertexAttribute = /*#__PURE__*/ function(ParticleFeedbackVertexAttribute) {
26260
+ ParticleFeedbackVertexAttribute["Position"] = "a_FeedbackPosition";
26261
+ ParticleFeedbackVertexAttribute["Velocity"] = "a_FeedbackVelocity";
26262
+ return ParticleFeedbackVertexAttribute;
26263
+ }({});
26264
+
26205
26265
  /**
26206
26266
  * @internal
26207
26267
  */ var ParticleInstanceVertexAttribute = /*#__PURE__*/ function(ParticleInstanceVertexAttribute) {
@@ -26296,6 +26356,22 @@ PointerEventEmitter._tempRay = new engineMath.Ray();
26296
26356
  return _class;
26297
26357
  }(ContentRestorer))());
26298
26358
  };
26359
+ ParticleBufferUtils.feedbackVertexStride = 24;
26360
+ ParticleBufferUtils.feedbackVertexElements = [
26361
+ new VertexElement(ParticleFeedbackVertexAttribute.Position, 0, VertexElementFormat.Vector3, 0),
26362
+ new VertexElement(ParticleFeedbackVertexAttribute.Velocity, 12, VertexElementFormat.Vector3, 0)
26363
+ ];
26364
+ ParticleBufferUtils.feedbackInstanceElements = [
26365
+ new VertexElement(ParticleInstanceVertexAttribute.ShapePositionStartLifeTime, 0, VertexElementFormat.Vector4, 0),
26366
+ new VertexElement(ParticleInstanceVertexAttribute.DirectionTime, 16, VertexElementFormat.Vector4, 0),
26367
+ new VertexElement(ParticleInstanceVertexAttribute.StartSize, 48, VertexElementFormat.Vector3, 0),
26368
+ new VertexElement(ParticleInstanceVertexAttribute.StartSpeed, 72, VertexElementFormat.Float, 0),
26369
+ new VertexElement(ParticleInstanceVertexAttribute.Random0, 76, VertexElementFormat.Vector4, 0),
26370
+ new VertexElement(ParticleInstanceVertexAttribute.Random1, 92, VertexElementFormat.Vector4, 0),
26371
+ new VertexElement(ParticleInstanceVertexAttribute.SimulationWorldPosition, 108, VertexElementFormat.Vector3, 0),
26372
+ new VertexElement(ParticleInstanceVertexAttribute.SimulationWorldRotation, 120, VertexElementFormat.Vector4, 0),
26373
+ new VertexElement(ParticleInstanceVertexAttribute.Random2, 152, VertexElementFormat.Vector4, 0)
26374
+ ];
26299
26375
  ParticleBufferUtils.instanceVertexStride = 168;
26300
26376
  ParticleBufferUtils.instanceVertexFloatStride = ParticleBufferUtils.instanceVertexStride / 4;
26301
26377
  ParticleBufferUtils.startLifeTimeOffset = 3;
@@ -26328,7 +26404,7 @@ var depthOnlyVs = "#define MATERIAL_OMIT_NORMAL\n#include <common>\n#include <co
26328
26404
 
26329
26405
  var particleFs = "#include <common>\n\nvarying vec4 v_Color;\nvarying vec2 v_TextureCoordinate;\nuniform sampler2D material_BaseTexture;\nuniform vec4 material_BaseColor;\n \nuniform mediump vec3 material_EmissiveColor;\n#ifdef MATERIAL_HAS_EMISSIVETEXTURE\n uniform sampler2D material_EmissiveTexture;\n#endif\n\n#ifdef RENDERER_MODE_MESH\n\tvarying vec4 v_MeshColor;\n#endif\n\nvoid main() {\n\tvec4 color = material_BaseColor * v_Color;\n\n\t#if defined(RENDERER_MODE_MESH) && defined(RENDERER_ENABLE_VERTEXCOLOR)\n\t\tcolor *= v_MeshColor;\n\t#endif\n\n\t#ifdef MATERIAL_HAS_BASETEXTURE\n\t\tcolor *= texture2DSRGB(material_BaseTexture, v_TextureCoordinate);\n\t#endif\n\t\n\t// Emissive\n\tvec3 emissiveRadiance = material_EmissiveColor;\n\t#ifdef MATERIAL_HAS_EMISSIVETEXTURE\n\t\temissiveRadiance *= texture2DSRGB(material_EmissiveTexture, v_TextureCoordinate).rgb;\n\t#endif\n\n\tcolor.rgb += emissiveRadiance;\n\n\tgl_FragColor = color;\n}"; // eslint-disable-line
26330
26406
 
26331
- var particleVs = "#if defined(RENDERER_MODE_SPHERE_BILLBOARD) || defined(RENDERER_MODE_STRETCHED_BILLBOARD) || defined(RENDERER_MODE_HORIZONTAL_BILLBOARD) || defined(RENDERER_MODE_VERTICAL_BILLBOARD)\n attribute vec4 a_CornerTextureCoordinate;\n#endif\n\n#ifdef RENDERER_MODE_MESH\n attribute vec3 POSITION;\n #ifdef RENDERER_ENABLE_VERTEXCOLOR\n attribute vec4 COLOR_0;\n #endif\n attribute vec2 TEXCOORD_0;\n varying vec4 v_MeshColor;\n#endif\n\nattribute vec4 a_ShapePositionStartLifeTime;\nattribute vec4 a_DirectionTime;\nattribute vec4 a_StartColor;\nattribute vec3 a_StartSize;\nattribute vec3 a_StartRotation0;\nattribute float a_StartSpeed;\n\n//#if defined(COLOR_OVER_LIFETIME) || defined(RENDERER_COL_RANDOM_GRADIENTS) || defined(RENDERER_SOL_RANDOM_CURVES) || defined(RENDERER_SOL_RANDOM_CURVES_SEPARATE) || defined(ROTATION_OVER_LIFE_TIME_RANDOM_CONSTANTS) || defined(ROTATION_OVER_LIFETIME_RANDOM_CURVES)\n attribute vec4 a_Random0;\n//#endif\n\n#if defined(RENDERER_TSA_FRAME_RANDOM_CURVES) || defined(RENDERER_VOL_IS_RANDOM_TWO)\n attribute vec4 a_Random1; // x:texture sheet animation random\n#endif\n\nattribute vec3 a_SimulationWorldPosition;\nattribute vec4 a_SimulationWorldRotation;\n\nvarying vec4 v_Color;\n#ifdef MATERIAL_HAS_BASETEXTURE\n attribute vec4 a_SimulationUV;\n varying vec2 v_TextureCoordinate;\n#endif\n\nuniform float renderer_CurrentTime;\nuniform vec3 renderer_Gravity;\nuniform vec2 u_DragConstant;\nuniform vec3 renderer_WorldPosition;\nuniform vec4 renderer_WorldRotation;\nuniform bool renderer_ThreeDStartRotation;\nuniform int renderer_ScalingMode;\nuniform vec3 renderer_PositionScale;\nuniform vec3 renderer_SizeScale;\nuniform vec3 renderer_PivotOffset;\n\nuniform mat4 camera_ViewMat;\nuniform mat4 camera_ProjMat;\n\n#ifdef RENDERER_MODE_STRETCHED_BILLBOARD\n uniform vec3 camera_Position;\n#endif\nuniform vec3 camera_Forward; // TODO:只有几种广告牌模式需要用\nuniform vec3 camera_Up;\n\nuniform float renderer_StretchedBillboardLengthScale;\nuniform float renderer_StretchedBillboardSpeedScale;\nuniform int renderer_SimulationSpace;\n\n#include <particle_common>\n#include <velocity_over_lifetime_module>\n#include <force_over_lifetime_module>\n#include <color_over_lifetime_module>\n#include <size_over_lifetime_module>\n#include <rotation_over_lifetime_module>\n#include <texture_sheet_animation_module>\n\nvec3 getStartPosition(vec3 startVelocity, float age, vec3 dragData) {\n vec3 startPosition;\n float lastTime = min(startVelocity.x / dragData.x, age); // todo 0/0\n startPosition = lastTime * (startVelocity - 0.5 * dragData * lastTime);\n return startPosition;\n}\n\nvec3 computeParticlePosition(in vec3 startVelocity, in float age, in float normalizedAge, vec3 gravityVelocity, vec4 worldRotation, vec3 dragData, inout vec3 localVelocity, inout vec3 worldVelocity) {\n vec3 startPosition = getStartPosition(startVelocity, age, dragData);\n\n vec3 finalPosition;\n vec3 localPositionOffset = startPosition;\n vec3 worldPositionOffset;\n\n #ifdef _VOL_MODULE_ENABLED\n vec3 lifeVelocity; \n vec3 velocityPositionOffset = computeVelocityPositionOffset(normalizedAge, age, lifeVelocity);\n if (renderer_VOLSpace == 0) {\n localVelocity += lifeVelocity;\n localPositionOffset += velocityPositionOffset;\n } else {\n worldVelocity += lifeVelocity;\n worldPositionOffset += velocityPositionOffset;\n }\n #endif\n\n #ifdef _FOL_MODULE_ENABLED\n vec3 forceVelocity;\n vec3 forcePositionOffset = computeForcePositionOffset(normalizedAge, age, forceVelocity);\n if (renderer_FOLSpace == 0) {\n localVelocity += forceVelocity;\n localPositionOffset += forcePositionOffset;\n } else {\n worldVelocity += forceVelocity;\n worldPositionOffset += forcePositionOffset;\n }\n #endif\n\n finalPosition = rotationByQuaternions(a_ShapePositionStartLifeTime.xyz + localPositionOffset, worldRotation) + worldPositionOffset;\n\n if (renderer_SimulationSpace == 0) {\n finalPosition = finalPosition + renderer_WorldPosition;\n } else if (renderer_SimulationSpace == 1) {\n\t finalPosition = finalPosition + a_SimulationWorldPosition;\n\t}\n\n finalPosition += 0.5 * gravityVelocity * age;\n\n return finalPosition;\n}\n\nvoid main() {\n float age = renderer_CurrentTime - a_DirectionTime.w;\n float normalizedAge = age / a_ShapePositionStartLifeTime.w;\n if (normalizedAge < 1.0) {\n vec3 startVelocity = a_DirectionTime.xyz * a_StartSpeed;\n vec3 gravityVelocity = renderer_Gravity * a_Random0.x * age;\n\n vec4 worldRotation;\n if (renderer_SimulationSpace == 0) {\n worldRotation = renderer_WorldRotation;\n } else {\n worldRotation = a_SimulationWorldRotation;\n }\n\n vec3 localVelocity = startVelocity;\n vec3 worldVelocity = gravityVelocity;\n\n //drag\n vec3 dragData = a_DirectionTime.xyz * mix(u_DragConstant.x, u_DragConstant.y, a_Random0.x);\n vec3 center = computeParticlePosition(startVelocity, age, normalizedAge, gravityVelocity, worldRotation, dragData, localVelocity, worldVelocity);\n\n #include <sphere_billboard>\n #include <stretched_billboard>\n #include <horizontal_billboard>\n #include <vertical_billboard>\n #include <particle_mesh>\n\n gl_Position = camera_ProjMat * camera_ViewMat * vec4(center, 1.0);\n v_Color = computeParticleColor(a_StartColor, normalizedAge);\n\n #ifdef MATERIAL_HAS_BASETEXTURE\n vec2 simulateUV;\n #if defined(RENDERER_MODE_SPHERE_BILLBOARD) || defined(RENDERER_MODE_STRETCHED_BILLBOARD) || defined(RENDERER_MODE_HORIZONTAL_BILLBOARD) || defined(RENDERER_MODE_VERTICAL_BILLBOARD)\n simulateUV = a_CornerTextureCoordinate.zw * a_SimulationUV.xy + a_SimulationUV.zw;\n v_TextureCoordinate = computeParticleUV(simulateUV, normalizedAge);\n #endif\n #ifdef RENDERER_MODE_MESH\n simulateUV = a_SimulationUV.zw + TEXCOORD_0 * a_SimulationUV.xy;\n v_TextureCoordinate = computeParticleUV(simulateUV, normalizedAge);\n #endif\n #endif\n } else {\n\t gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // Discard use out of X(-1,1),Y(-1,1),Z(0,1)\n }\n}"; // eslint-disable-line
26407
+ var particleVs = "#if defined(RENDERER_MODE_SPHERE_BILLBOARD) || defined(RENDERER_MODE_STRETCHED_BILLBOARD) || defined(RENDERER_MODE_HORIZONTAL_BILLBOARD) || defined(RENDERER_MODE_VERTICAL_BILLBOARD)\n attribute vec4 a_CornerTextureCoordinate;\n#endif\n\n#ifdef RENDERER_MODE_MESH\n attribute vec3 POSITION;\n #ifdef RENDERER_ENABLE_VERTEXCOLOR\n attribute vec4 COLOR_0;\n #endif\n attribute vec2 TEXCOORD_0;\n varying vec4 v_MeshColor;\n#endif\n\nattribute vec4 a_ShapePositionStartLifeTime;\nattribute vec4 a_DirectionTime;\nattribute vec4 a_StartColor;\nattribute vec3 a_StartSize;\nattribute vec3 a_StartRotation0;\nattribute float a_StartSpeed;\n\n//#if defined(COLOR_OVER_LIFETIME) || defined(RENDERER_COL_RANDOM_GRADIENTS) || defined(RENDERER_SOL_RANDOM_CURVES) || defined(RENDERER_SOL_RANDOM_CURVES_SEPARATE) || defined(ROTATION_OVER_LIFE_TIME_RANDOM_CONSTANTS) || defined(ROTATION_OVER_LIFETIME_RANDOM_CURVES)\n attribute vec4 a_Random0;\n//#endif\n\n#if defined(RENDERER_TSA_FRAME_RANDOM_CURVES) || defined(RENDERER_VOL_IS_RANDOM_TWO)\n attribute vec4 a_Random1; // x:texture sheet animation random\n#endif\n\n#if defined(RENDERER_FOL_CONSTANT_MODE) || defined(RENDERER_FOL_CURVE_MODE) || defined(RENDERER_LVL_MODULE_ENABLED)\n attribute vec4 a_Random2;\n#endif\n\nattribute vec3 a_SimulationWorldPosition;\nattribute vec4 a_SimulationWorldRotation;\n\n#ifdef RENDERER_TRANSFORM_FEEDBACK\n attribute vec3 a_FeedbackPosition;\n attribute vec3 a_FeedbackVelocity;\n#endif\n\nvarying vec4 v_Color;\n#ifdef MATERIAL_HAS_BASETEXTURE\n attribute vec4 a_SimulationUV;\n varying vec2 v_TextureCoordinate;\n#endif\n\nuniform float renderer_CurrentTime;\nuniform vec3 renderer_Gravity;\nuniform vec3 renderer_WorldPosition;\nuniform vec4 renderer_WorldRotation;\nuniform bool renderer_ThreeDStartRotation;\nuniform int renderer_ScalingMode;\nuniform vec3 renderer_PositionScale;\nuniform vec3 renderer_SizeScale;\nuniform vec3 renderer_PivotOffset;\n\nuniform mat4 camera_ViewMat;\nuniform mat4 camera_ProjMat;\n\n#ifdef RENDERER_MODE_STRETCHED_BILLBOARD\n uniform vec3 camera_Position;\n#endif\nuniform vec3 camera_Forward; // TODO:只有几种广告牌模式需要用\nuniform vec3 camera_Up;\n\nuniform float renderer_StretchedBillboardLengthScale;\nuniform float renderer_StretchedBillboardSpeedScale;\nuniform int renderer_SimulationSpace;\n\n#include <particle_common>\n#include <velocity_over_lifetime_module>\n#include <force_over_lifetime_module>\n#include <color_over_lifetime_module>\n#include <size_over_lifetime_module>\n#include <rotation_over_lifetime_module>\n#include <texture_sheet_animation_module>\n\nvec3 computeParticlePosition(in vec3 startVelocity, in float age, in float normalizedAge, vec3 gravityVelocity, vec4 worldRotation, inout vec3 localVelocity, inout vec3 worldVelocity) {\n vec3 startPosition = startVelocity * age;\n\n vec3 finalPosition;\n vec3 localPositionOffset = startPosition;\n vec3 worldPositionOffset;\n\n #ifdef _VOL_MODULE_ENABLED\n vec3 lifeVelocity; \n vec3 velocityPositionOffset = computeVelocityPositionOffset(normalizedAge, age, lifeVelocity);\n if (renderer_VOLSpace == 0) {\n localVelocity += lifeVelocity;\n localPositionOffset += velocityPositionOffset;\n } else {\n worldVelocity += lifeVelocity;\n worldPositionOffset += velocityPositionOffset;\n }\n #endif\n\n #ifdef _FOL_MODULE_ENABLED\n vec3 forceVelocity;\n vec3 forcePositionOffset = computeForcePositionOffset(normalizedAge, age, forceVelocity);\n if (renderer_FOLSpace == 0) {\n localVelocity += forceVelocity;\n localPositionOffset += forcePositionOffset;\n } else {\n worldVelocity += forceVelocity;\n worldPositionOffset += forcePositionOffset;\n }\n #endif\n\n finalPosition = rotationByQuaternions(a_ShapePositionStartLifeTime.xyz + localPositionOffset, worldRotation) + worldPositionOffset;\n\n if (renderer_SimulationSpace == 0) {\n finalPosition = finalPosition + renderer_WorldPosition;\n } else if (renderer_SimulationSpace == 1) {\n\t finalPosition = finalPosition + a_SimulationWorldPosition;\n\t}\n\n finalPosition += 0.5 * gravityVelocity * age;\n\n return finalPosition;\n}\n\nvoid main() {\n float age = renderer_CurrentTime - a_DirectionTime.w;\n float normalizedAge = age / a_ShapePositionStartLifeTime.w;\n // normalizedAge >= 0.0: skip stale TF slots whose startTime is from a previous playback (e.g. after StopEmittingAndClear).\n if (normalizedAge >= 0.0 && normalizedAge < 1.0) {\n vec4 worldRotation;\n if (renderer_SimulationSpace == 0) {\n worldRotation = renderer_WorldRotation;\n } else {\n worldRotation = a_SimulationWorldRotation;\n }\n\n vec3 localVelocity;\n vec3 worldVelocity;\n\n #ifdef RENDERER_TRANSFORM_FEEDBACK\n // Transform Feedback mode: position in simulation space (local or world).\n // Local: transform to world; World: use directly.\n vec3 center;\n if (renderer_SimulationSpace == 0) {\n center = rotationByQuaternions(a_FeedbackPosition, worldRotation) + renderer_WorldPosition;\n } else if (renderer_SimulationSpace == 1) {\n center = a_FeedbackPosition;\n }\n localVelocity = a_FeedbackVelocity;\n worldVelocity = vec3(0.0);\n\n #ifdef _VOL_MODULE_ENABLED\n vec3 instantVOLVelocity;\n computeVelocityPositionOffset(normalizedAge, age, instantVOLVelocity);\n if (renderer_VOLSpace == 0) {\n localVelocity += instantVOLVelocity;\n } else {\n worldVelocity += instantVOLVelocity;\n }\n #endif\n #else\n // Original analytical path\n vec3 startVelocity = a_DirectionTime.xyz * a_StartSpeed;\n vec3 gravityVelocity = renderer_Gravity * a_Random0.x * age;\n localVelocity = startVelocity;\n worldVelocity = gravityVelocity;\n vec3 center = computeParticlePosition(startVelocity, age, normalizedAge, gravityVelocity, worldRotation, localVelocity, worldVelocity);\n #endif\n\n #include <sphere_billboard>\n #include <stretched_billboard>\n #include <horizontal_billboard>\n #include <vertical_billboard>\n #include <particle_mesh>\n\n gl_Position = camera_ProjMat * camera_ViewMat * vec4(center, 1.0);\n v_Color = computeParticleColor(a_StartColor, normalizedAge);\n\n #ifdef MATERIAL_HAS_BASETEXTURE\n vec2 simulateUV;\n #if defined(RENDERER_MODE_SPHERE_BILLBOARD) || defined(RENDERER_MODE_STRETCHED_BILLBOARD) || defined(RENDERER_MODE_HORIZONTAL_BILLBOARD) || defined(RENDERER_MODE_VERTICAL_BILLBOARD)\n simulateUV = a_CornerTextureCoordinate.zw * a_SimulationUV.xy + a_SimulationUV.zw;\n v_TextureCoordinate = computeParticleUV(simulateUV, normalizedAge);\n #endif\n #ifdef RENDERER_MODE_MESH\n simulateUV = a_SimulationUV.zw + TEXCOORD_0 * a_SimulationUV.xy;\n v_TextureCoordinate = computeParticleUV(simulateUV, normalizedAge);\n #endif\n #endif\n } else {\n\t gl_Position = vec4(2.0, 2.0, 2.0, 1.0); // Discard use out of X(-1,1),Y(-1,1),Z(0,1)\n }\n}"; // eslint-disable-line
26332
26408
 
26333
26409
  var pbrSpecularFs = "#include <common>\n#include <camera_declare>\n\n#include <FogFragmentDeclaration>\n\n#include <uv_share>\n#include <normal_share>\n#include <color_share>\n#include <worldpos_share>\n\n#include <light_frag_define>\n\n\n#include <pbr_frag_define>\n#include <pbr_helper>\n\nvoid main() {\n #include <pbr_frag>\n #include <FogFragment>\n}\n"; // eslint-disable-line
26334
26410
 
@@ -26364,12 +26440,46 @@ var unlitFs = "#include <common>\n#include <uv_share>\n#include <FogFragmentDecl
26364
26440
 
26365
26441
  var unlitVs = "#include <common>\n#include <common_vert>\n#include <blendShape_input>\n#include <uv_share>\n#include <FogVertexDeclaration>\n\nvoid main() {\n\n #include <begin_position_vert>\n #include <blendShape_vert>\n #include <skinning_vert>\n #include <uv_vert>\n #include <position_vert>\n\n #include <FogVertex>\n}\n"; // eslint-disable-line
26366
26442
 
26443
+ /**
26444
+ * @internal
26445
+ * Shared shader definition for Transform Feedback simulation.
26446
+ * Multiple simulators using the same shader share a single program pool per engine.
26447
+ */ var TransformFeedbackShader = /*#__PURE__*/ function() {
26448
+ function TransformFeedbackShader(vertexSource, fragmentSource, feedbackVaryings) {
26449
+ this._id = ShaderPass._shaderPassCounter++;
26450
+ this.vertexSource = vertexSource;
26451
+ this.fragmentSource = fragmentSource;
26452
+ this.feedbackVaryings = feedbackVaryings;
26453
+ }
26454
+ var _proto = TransformFeedbackShader.prototype;
26455
+ /**
26456
+ * Get or compile a shader program for the given engine and macro combination.
26457
+ */ _proto.getProgram = function getProgram(engine, macroCollection) {
26458
+ var pool = engine._getShaderProgramPool(this._id);
26459
+ var program = pool.get(macroCollection);
26460
+ if (program) return program;
26461
+ var _ShaderFactory_compilePlatformSource = ShaderFactory.compilePlatformSource(engine, macroCollection, this.vertexSource, this.fragmentSource), vertexSource = _ShaderFactory_compilePlatformSource.vertexSource, fragmentSource = _ShaderFactory_compilePlatformSource.fragmentSource;
26462
+ program = new ShaderProgram(engine, vertexSource, fragmentSource, this.feedbackVaryings);
26463
+ if (!program.isValid) {
26464
+ Logger.error("TransformFeedbackShader: Failed to compile shader program.");
26465
+ return null;
26466
+ }
26467
+ pool.cache(program);
26468
+ return program;
26469
+ };
26470
+ return TransformFeedbackShader;
26471
+ }();
26472
+
26367
26473
  /**
26368
26474
  * Internal shader pool.
26369
26475
  * @internal
26370
26476
  */ var ShaderPool = /*#__PURE__*/ function() {
26371
26477
  function ShaderPool() {}
26372
26478
  ShaderPool.init = function init() {
26479
+ ShaderPool.particleFeedbackShader = new TransformFeedbackShader("#include <particle_feedback_simulation>", "void main() { discard; }", [
26480
+ "v_FeedbackPosition",
26481
+ "v_FeedbackVelocity"
26482
+ ]);
26373
26483
  var shadowCasterPass = new ShaderPass("ShadowCaster", shadowMapVs, shadowMapFs, {
26374
26484
  pipelineStage: PipelineStage.ShadowCaster
26375
26485
  });
@@ -26862,8 +26972,7 @@ ShaderPool.init();
26862
26972
  };
26863
26973
  /**
26864
26974
  * @internal
26865
- */ _proto._getShaderProgramPool = function _getShaderProgramPool(shaderPass) {
26866
- var index = shaderPass._shaderPassId;
26975
+ */ _proto._getShaderProgramPool = function _getShaderProgramPool(index, trackPools) {
26867
26976
  var shaderProgramPools = this._shaderProgramPools;
26868
26977
  var pool = shaderProgramPools[index];
26869
26978
  if (!pool) {
@@ -26872,7 +26981,7 @@ ShaderPool.init();
26872
26981
  shaderProgramPools.length = length;
26873
26982
  }
26874
26983
  shaderProgramPools[index] = pool = new ShaderProgramPool(this);
26875
- shaderPass._shaderProgramPools.push(pool);
26984
+ trackPools == null ? void 0 : trackPools.push(pool);
26876
26985
  }
26877
26986
  return pool;
26878
26987
  };
@@ -33263,6 +33372,10 @@ var ParticleStopMode = /*#__PURE__*/ function(ParticleStopMode) {
33263
33372
  shaderData.setFloat(ParticleRenderer._currentTime, this.generator._playTime);
33264
33373
  shaderData.setVector3(ParticleRenderer._pivotOffsetProperty, this.pivot);
33265
33374
  this.generator._updateShaderData(shaderData);
33375
+ // Run Transform Feedback simulation after shader data is up to date
33376
+ if (generator._useTransformFeedback) {
33377
+ generator._updateFeedback(shaderData, this.engine.time.deltaTime * generator.main.simulationSpeed);
33378
+ }
33266
33379
  };
33267
33380
  _proto._render = function _render(context) {
33268
33381
  var generator = this.generator;
@@ -33271,7 +33384,9 @@ var ParticleStopMode = /*#__PURE__*/ function(ParticleStopMode) {
33271
33384
  if (!aliveParticleCount) {
33272
33385
  return;
33273
33386
  }
33274
- generator._primitive.instanceCount = aliveParticleCount;
33387
+ // Transform Feedback: render all slots (instance buffer not compacted, dead particles discarded in shader)
33388
+ // Non-Transform Feedback: render only alive particles (instance buffer compacted)
33389
+ generator._primitive.instanceCount = generator._useTransformFeedback ? generator._firstActiveElement <= generator._firstFreeElement ? generator._firstFreeElement : generator._currentParticleCount : aliveParticleCount;
33275
33390
  var material = this.getMaterial();
33276
33391
  if (!material || this._renderMode === ParticleRenderMode.Mesh && !this._mesh) {
33277
33392
  return;
@@ -33427,6 +33542,331 @@ __decorate([
33427
33542
  return ParticleUpdateFlags;
33428
33543
  }({});
33429
33544
 
33545
+ /**
33546
+ * Transform Feedback object for GPU-based data capture.
33547
+ * @internal
33548
+ */ var TransformFeedback = /*#__PURE__*/ function(GraphicsResource) {
33549
+ _inherits(TransformFeedback, GraphicsResource);
33550
+ function TransformFeedback(engine) {
33551
+ var _this;
33552
+ _this = GraphicsResource.call(this, engine) || this;
33553
+ _this._platformTransformFeedback = engine._hardwareRenderer.createPlatformTransformFeedback();
33554
+ return _this;
33555
+ }
33556
+ var _proto = TransformFeedback.prototype;
33557
+ /**
33558
+ * Bind this Transform Feedback object as active.
33559
+ */ _proto.bind = function bind() {
33560
+ this._platformTransformFeedback.bind();
33561
+ };
33562
+ /**
33563
+ * Bind a buffer range as output at the given index.
33564
+ * @param index - Output binding point index (corresponds to varying index in shader)
33565
+ * @param buffer - Output buffer to capture data into
33566
+ * @param byteOffset - Starting byte offset in the buffer
33567
+ * @param byteSize - Size in bytes of the capture range
33568
+ */ _proto.bindBufferRange = function bindBufferRange(index, buffer, byteOffset, byteSize) {
33569
+ this._platformTransformFeedback.bindBufferRange(index, buffer._platformBuffer, byteOffset, byteSize);
33570
+ };
33571
+ /**
33572
+ * Begin a Transform Feedback pass.
33573
+ * @param primitiveMode - Primitive topology mode
33574
+ */ _proto.begin = function begin(primitiveMode) {
33575
+ this._platformTransformFeedback.begin(primitiveMode);
33576
+ };
33577
+ /**
33578
+ * End the current Transform Feedback pass.
33579
+ */ _proto.end = function end() {
33580
+ this._platformTransformFeedback.end();
33581
+ };
33582
+ /**
33583
+ * Unbind the output buffer at the given index from the Transform Feedback target.
33584
+ * @param index - Output binding point index
33585
+ */ _proto.unbindBuffer = function unbindBuffer(index) {
33586
+ this._platformTransformFeedback.unbindBuffer(index);
33587
+ };
33588
+ /**
33589
+ * Unbind this Transform Feedback object.
33590
+ */ _proto.unbind = function unbind() {
33591
+ this._platformTransformFeedback.unbind();
33592
+ };
33593
+ _proto._rebuild = function _rebuild() {
33594
+ this._platformTransformFeedback = this._engine._hardwareRenderer.createPlatformTransformFeedback();
33595
+ };
33596
+ _proto._onDestroy = function _onDestroy() {
33597
+ GraphicsResource.prototype._onDestroy.call(this);
33598
+ this._platformTransformFeedback.destroy();
33599
+ };
33600
+ return TransformFeedback;
33601
+ }(GraphicsResource);
33602
+
33603
+ /**
33604
+ * @internal
33605
+ * Primitive for Transform Feedback simulation with read/write buffer swapping.
33606
+ */ var TransformFeedbackPrimitive = /*#__PURE__*/ function(GraphicsResource) {
33607
+ _inherits(TransformFeedbackPrimitive, GraphicsResource);
33608
+ function TransformFeedbackPrimitive(engine, byteStride) {
33609
+ var _this;
33610
+ _this = GraphicsResource.call(this, engine) || this, _this._readIsA = true;
33611
+ _this._byteStride = byteStride;
33612
+ _this._transformFeedback = new TransformFeedback(engine);
33613
+ _this._transformFeedback.isGCIgnored = true;
33614
+ _this._platformPrimitive = engine._hardwareRenderer.createPlatformTransformFeedbackPrimitive();
33615
+ _this.isGCIgnored = true;
33616
+ return _this;
33617
+ }
33618
+ var _proto = TransformFeedbackPrimitive.prototype;
33619
+ /**
33620
+ * Resize read and write buffers.
33621
+ * @param vertexCount - Number of vertices to allocate
33622
+ */ _proto.resize = function resize(vertexCount) {
33623
+ var byteLength = this._byteStride * vertexCount;
33624
+ var bufferA = new Buffer(this._engine, BufferBindFlag.VertexBuffer, byteLength, BufferUsage.Dynamic, false);
33625
+ bufferA.isGCIgnored = true;
33626
+ var bufferB = new Buffer(this._engine, BufferBindFlag.VertexBuffer, byteLength, BufferUsage.Dynamic, false);
33627
+ bufferB.isGCIgnored = true;
33628
+ this._bindingA = new VertexBufferBinding(bufferA, this._byteStride);
33629
+ this._bindingB = new VertexBufferBinding(bufferB, this._byteStride);
33630
+ this._readIsA = true;
33631
+ this._platformPrimitive.invalidate();
33632
+ };
33633
+ /**
33634
+ * Update vertex layout, only rebuilds when program changes.
33635
+ * @param program - Shader program for attribute locations
33636
+ * @param feedbackElements - Vertex elements describing the read/write buffer
33637
+ * @param inputBinding - Additional input buffer binding
33638
+ * @param inputElements - Vertex elements describing the input buffer
33639
+ */ _proto.updateVertexLayout = function updateVertexLayout(program, feedbackElements, inputBinding, inputElements) {
33640
+ this._platformPrimitive.updateVertexLayout(program, this._bindingA, this._bindingB, feedbackElements, inputBinding, inputElements);
33641
+ };
33642
+ /**
33643
+ * Bind state before issuing draw calls.
33644
+ */ _proto.beginDraw = function beginDraw() {
33645
+ this._engine._hardwareRenderer.enableRasterizerDiscard();
33646
+ this._transformFeedback.bind();
33647
+ this._platformPrimitive.bind(this._readIsA);
33648
+ };
33649
+ /**
33650
+ * Issue a draw call for a vertex range, capturing output to the write buffer.
33651
+ * @param mode - Primitive topology
33652
+ * @param first - First vertex index
33653
+ * @param count - Number of vertices
33654
+ */ _proto.draw = function draw(mode, first, count) {
33655
+ var transformFeedback = this._transformFeedback;
33656
+ transformFeedback.bindBufferRange(0, this.writeBinding.buffer, first * this._byteStride, count * this._byteStride);
33657
+ transformFeedback.begin(mode);
33658
+ this._platformPrimitive.draw(mode, first, count);
33659
+ transformFeedback.end();
33660
+ };
33661
+ /**
33662
+ * Unbind state after draw calls.
33663
+ */ _proto.endDraw = function endDraw() {
33664
+ this._platformPrimitive.unbind();
33665
+ this._transformFeedback.unbindBuffer(0);
33666
+ this._transformFeedback.unbind();
33667
+ this._engine._hardwareRenderer.disableRasterizerDiscard();
33668
+ this._engine._hardwareRenderer.invalidateShaderProgramState();
33669
+ };
33670
+ /**
33671
+ * Swap read and write buffers.
33672
+ */ _proto.swap = function swap() {
33673
+ this._readIsA = !this._readIsA;
33674
+ };
33675
+ _proto._rebuild = function _rebuild() {
33676
+ this._platformPrimitive = this._engine._hardwareRenderer.createPlatformTransformFeedbackPrimitive();
33677
+ };
33678
+ _proto._onDestroy = function _onDestroy() {
33679
+ var _this__platformPrimitive, _this__bindingA, _this__bindingB, _this__transformFeedback;
33680
+ GraphicsResource.prototype._onDestroy.call(this);
33681
+ (_this__platformPrimitive = this._platformPrimitive) == null ? void 0 : _this__platformPrimitive.destroy();
33682
+ (_this__bindingA = this._bindingA) == null ? void 0 : _this__bindingA.buffer.destroy();
33683
+ (_this__bindingB = this._bindingB) == null ? void 0 : _this__bindingB.buffer.destroy();
33684
+ (_this__transformFeedback = this._transformFeedback) == null ? void 0 : _this__transformFeedback.destroy();
33685
+ };
33686
+ _create_class(TransformFeedbackPrimitive, [
33687
+ {
33688
+ key: "readBinding",
33689
+ get: /**
33690
+ * The current read buffer binding.
33691
+ */ function get() {
33692
+ return this._readIsA ? this._bindingA : this._bindingB;
33693
+ }
33694
+ },
33695
+ {
33696
+ key: "writeBinding",
33697
+ get: /**
33698
+ * The current write buffer binding.
33699
+ */ function get() {
33700
+ return this._readIsA ? this._bindingB : this._bindingA;
33701
+ }
33702
+ }
33703
+ ]);
33704
+ return TransformFeedbackPrimitive;
33705
+ }(GraphicsResource);
33706
+
33707
+ /**
33708
+ * @internal
33709
+ * General-purpose Transform Feedback simulator.
33710
+ * Manages per-frame simulation with shared shader program caching.
33711
+ */ var TransformFeedbackSimulator = /*#__PURE__*/ function() {
33712
+ function TransformFeedbackSimulator(engine, byteStride, shader) {
33713
+ this._engine = engine;
33714
+ this._primitive = new TransformFeedbackPrimitive(engine, byteStride);
33715
+ this._shader = shader;
33716
+ }
33717
+ var _proto = TransformFeedbackSimulator.prototype;
33718
+ /**
33719
+ * Resize feedback buffers.
33720
+ * @param vertexCount - Number of vertices to allocate
33721
+ */ _proto.resize = function resize(vertexCount) {
33722
+ this._primitive.resize(vertexCount);
33723
+ };
33724
+ /**
33725
+ * Begin a simulation step: get/compile program, bind, upload uniforms, update layout.
33726
+ * @param shaderData - Shader data with current macros and uniforms
33727
+ * @param feedbackElements - Vertex elements for the feedback buffer
33728
+ * @param inputBinding - Input buffer binding
33729
+ * @param inputElements - Vertex elements for the input buffer
33730
+ */ _proto.beginUpdate = function beginUpdate(shaderData, feedbackElements, inputBinding, inputElements) {
33731
+ var program = this._shader.getProgram(this._engine, shaderData._macroCollection);
33732
+ if (!program) return false;
33733
+ program.bind();
33734
+ program.uploadUniforms(program.rendererUniformBlock, shaderData);
33735
+ program.uploadUniforms(program.otherUniformBlock, shaderData);
33736
+ this._primitive.updateVertexLayout(program, feedbackElements, inputBinding, inputElements);
33737
+ this._primitive.beginDraw();
33738
+ return true;
33739
+ };
33740
+ /**
33741
+ * Issue a draw call for a vertex range.
33742
+ * @param mode - Primitive topology
33743
+ * @param first - First vertex index
33744
+ * @param count - Number of vertices
33745
+ */ _proto.draw = function draw(mode, first, count) {
33746
+ this._primitive.draw(mode, first, count);
33747
+ };
33748
+ /**
33749
+ * End the simulation step: unbind state and swap buffers.
33750
+ */ _proto.endUpdate = function endUpdate() {
33751
+ this._primitive.endDraw();
33752
+ this._primitive.swap();
33753
+ };
33754
+ _proto.destroy = function destroy() {
33755
+ var _this__primitive;
33756
+ (_this__primitive = this._primitive) == null ? void 0 : _this__primitive.destroy();
33757
+ };
33758
+ _create_class(TransformFeedbackSimulator, [
33759
+ {
33760
+ key: "readBinding",
33761
+ get: /**
33762
+ * The current read buffer binding.
33763
+ */ function get() {
33764
+ return this._primitive.readBinding;
33765
+ }
33766
+ },
33767
+ {
33768
+ key: "writeBinding",
33769
+ get: /**
33770
+ * The current write buffer binding.
33771
+ */ function get() {
33772
+ return this._primitive.writeBinding;
33773
+ }
33774
+ }
33775
+ ]);
33776
+ return TransformFeedbackSimulator;
33777
+ }();
33778
+
33779
+ /**
33780
+ * @internal
33781
+ * Particle-specific Transform Feedback simulation.
33782
+ */ var ParticleTransformFeedbackSimulator = /*#__PURE__*/ function() {
33783
+ function ParticleTransformFeedbackSimulator(engine) {
33784
+ this._particleInitData = new Float32Array(6);
33785
+ this._simulator = new TransformFeedbackSimulator(engine, ParticleBufferUtils.feedbackVertexStride, ShaderPool.particleFeedbackShader);
33786
+ }
33787
+ var _proto = ParticleTransformFeedbackSimulator.prototype;
33788
+ /**
33789
+ * Resize feedback buffers.
33790
+ * Saves pre-resize buffers internally for subsequent `copyOldBufferData` / `destroyOldBuffers` calls.
33791
+ * @param particleCount - Number of particles to allocate
33792
+ * @param instanceBinding - New instance vertex buffer binding
33793
+ */ _proto.resize = function resize(particleCount, instanceBinding) {
33794
+ var _this__simulator_readBinding, _this__simulator_writeBinding;
33795
+ this._oldReadBuffer = (_this__simulator_readBinding = this._simulator.readBinding) == null ? void 0 : _this__simulator_readBinding.buffer;
33796
+ this._oldWriteBuffer = (_this__simulator_writeBinding = this._simulator.writeBinding) == null ? void 0 : _this__simulator_writeBinding.buffer;
33797
+ this._simulator.resize(particleCount);
33798
+ this._instanceBinding = instanceBinding;
33799
+ };
33800
+ /**
33801
+ * Write initial position and velocity for a newly emitted particle.
33802
+ */ _proto.writeParticleData = function writeParticleData(index, position, vx, vy, vz) {
33803
+ var data = this._particleInitData;
33804
+ data[0] = position.x;
33805
+ data[1] = position.y;
33806
+ data[2] = position.z;
33807
+ data[3] = vx;
33808
+ data[4] = vy;
33809
+ data[5] = vz;
33810
+ var simulator = this._simulator;
33811
+ var byteOffset = index * ParticleBufferUtils.feedbackVertexStride;
33812
+ simulator.readBinding.buffer.setData(data, byteOffset);
33813
+ simulator.writeBinding.buffer.setData(data, byteOffset);
33814
+ };
33815
+ /**
33816
+ * Copy data from pre-resize buffers to current buffers.
33817
+ * Must be called after `resize` which saves the old buffers.
33818
+ */ _proto.copyOldBufferData = function copyOldBufferData(srcByteOffset, dstByteOffset, byteLength) {
33819
+ this._simulator.readBinding.buffer.copyFromBuffer(this._oldReadBuffer, srcByteOffset, dstByteOffset, byteLength);
33820
+ this._simulator.writeBinding.buffer.copyFromBuffer(this._oldWriteBuffer, srcByteOffset, dstByteOffset, byteLength);
33821
+ };
33822
+ /**
33823
+ * Destroy pre-resize buffers saved during `resize`.
33824
+ */ _proto.destroyOldBuffers = function destroyOldBuffers() {
33825
+ var _this__oldReadBuffer, _this__oldWriteBuffer;
33826
+ (_this__oldReadBuffer = this._oldReadBuffer) == null ? void 0 : _this__oldReadBuffer.destroy();
33827
+ (_this__oldWriteBuffer = this._oldWriteBuffer) == null ? void 0 : _this__oldWriteBuffer.destroy();
33828
+ this._oldReadBuffer = null;
33829
+ this._oldWriteBuffer = null;
33830
+ };
33831
+ /**
33832
+ * Run one simulation step.
33833
+ * @param shaderData - Shader data with current macros and uniforms
33834
+ * @param particleCount - Total particle slot count
33835
+ * @param firstActive - First active particle index in ring buffer
33836
+ * @param firstFree - First free particle index in ring buffer
33837
+ * @param deltaTime - Frame delta time
33838
+ */ _proto.update = function update(shaderData, particleCount, firstActive, firstFree, deltaTime) {
33839
+ if (firstActive === firstFree) return;
33840
+ shaderData.setFloat(ParticleTransformFeedbackSimulator._deltaTimeProperty, deltaTime);
33841
+ if (!this._simulator.beginUpdate(shaderData, ParticleBufferUtils.feedbackVertexElements, this._instanceBinding, ParticleBufferUtils.feedbackInstanceElements)) return;
33842
+ if (firstActive < firstFree) {
33843
+ this._simulator.draw(MeshTopology.Points, firstActive, firstFree - firstActive);
33844
+ } else {
33845
+ this._simulator.draw(MeshTopology.Points, firstActive, particleCount - firstActive);
33846
+ if (firstFree > 0) {
33847
+ this._simulator.draw(MeshTopology.Points, 0, firstFree);
33848
+ }
33849
+ }
33850
+ this._simulator.endUpdate();
33851
+ };
33852
+ _proto.destroy = function destroy() {
33853
+ var _this__simulator;
33854
+ (_this__simulator = this._simulator) == null ? void 0 : _this__simulator.destroy();
33855
+ };
33856
+ _create_class(ParticleTransformFeedbackSimulator, [
33857
+ {
33858
+ key: "readBinding",
33859
+ get: /**
33860
+ * The current read buffer binding for the render pass.
33861
+ */ function get() {
33862
+ return this._simulator.readBinding;
33863
+ }
33864
+ }
33865
+ ]);
33866
+ return ParticleTransformFeedbackSimulator;
33867
+ }();
33868
+ ParticleTransformFeedbackSimulator._deltaTimeProperty = ShaderProperty.getByName("renderer_DeltaTime");
33869
+
33430
33870
  /**
33431
33871
  * Particle curve mode.
33432
33872
  */ var ParticleCurveMode = /*#__PURE__*/ function(ParticleCurveMode) {
@@ -33466,6 +33906,7 @@ __decorate([
33466
33906
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["Shape"] = 2941263940] = "Shape";
33467
33907
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["GravityModifier"] = 2759560269] = "GravityModifier";
33468
33908
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["ForceOverLifetime"] = 3875246972] = "ForceOverLifetime";
33909
+ ParticleRandomSubSeeds[ParticleRandomSubSeeds["LimitVelocityOverLifetime"] = 3047300990] = "LimitVelocityOverLifetime";
33469
33910
  return ParticleRandomSubSeeds;
33470
33911
  }({});
33471
33912
 
@@ -34523,6 +34964,415 @@ __decorate([
34523
34964
  deepClone
34524
34965
  ], ForceOverLifetimeModule.prototype, "_forceZ", void 0);
34525
34966
 
34967
+ /**
34968
+ * Limit velocity over lifetime module.
34969
+ */ var LimitVelocityOverLifetimeModule = /*#__PURE__*/ function(ParticleGeneratorModule) {
34970
+ _inherits(LimitVelocityOverLifetimeModule, ParticleGeneratorModule);
34971
+ function LimitVelocityOverLifetimeModule(generator) {
34972
+ var _this;
34973
+ _this = ParticleGeneratorModule.call(this, generator) || this, /** @internal */ _this._speedRand = new engineMath.Rand(0, ParticleRandomSubSeeds.LimitVelocityOverLifetime), _this._speedMinConstantVec = new engineMath.Vector3(), _this._speedMaxConstantVec = new engineMath.Vector3(), _this._dragConstantVec = new engineMath.Vector2(), _this._separateAxes = false, _this._dampen = 0, _this._multiplyDragByParticleSize = false, _this._multiplyDragByParticleVelocity = false, _this._space = ParticleSimulationSpace.Local;
34974
+ _this.speedX = new ParticleCompositeCurve(1);
34975
+ _this.speedY = new ParticleCompositeCurve(1);
34976
+ _this.speedZ = new ParticleCompositeCurve(1);
34977
+ _this.drag = new ParticleCompositeCurve(0);
34978
+ return _this;
34979
+ }
34980
+ var _proto = LimitVelocityOverLifetimeModule.prototype;
34981
+ /**
34982
+ * @internal
34983
+ */ _proto._isDragRandomMode = function _isDragRandomMode() {
34984
+ return this._drag.mode === ParticleCurveMode.TwoConstants || this._drag.mode === ParticleCurveMode.TwoCurves;
34985
+ };
34986
+ /**
34987
+ * @internal
34988
+ */ _proto._isSpeedRandomMode = function _isSpeedRandomMode() {
34989
+ if (this._separateAxes) {
34990
+ return (this._speedX.mode === ParticleCurveMode.TwoConstants || this._speedX.mode === ParticleCurveMode.TwoCurves) && (this._speedY.mode === ParticleCurveMode.TwoConstants || this._speedY.mode === ParticleCurveMode.TwoCurves) && (this._speedZ.mode === ParticleCurveMode.TwoConstants || this._speedZ.mode === ParticleCurveMode.TwoCurves);
34991
+ }
34992
+ return this._speedX.mode === ParticleCurveMode.TwoConstants || this._speedX.mode === ParticleCurveMode.TwoCurves;
34993
+ };
34994
+ /**
34995
+ * @internal
34996
+ */ _proto._updateShaderData = function _updateShaderData(shaderData) {
34997
+ var enabledModuleMacro = null;
34998
+ var separateAxesMacro = null;
34999
+ var speedModeMacro = null;
35000
+ var speedRandomMacro = null;
35001
+ var dragCurveMacro = null;
35002
+ var dragRandomMacro = null;
35003
+ var dragSizeMacro = null;
35004
+ var dragVelocityMacro = null;
35005
+ if (this.enabled) {
35006
+ enabledModuleMacro = LimitVelocityOverLifetimeModule._enabledMacro;
35007
+ // Dampen
35008
+ shaderData.setFloat(LimitVelocityOverLifetimeModule._dampenProperty, this._dampen);
35009
+ // Space
35010
+ shaderData.setInt(LimitVelocityOverLifetimeModule._spaceProperty, this._space);
35011
+ // Limit speed
35012
+ if (this._separateAxes) {
35013
+ separateAxesMacro = LimitVelocityOverLifetimeModule._separateAxesMacro;
35014
+ var result = this._uploadSeparateAxisSpeeds(shaderData);
35015
+ speedModeMacro = result.modeMacro;
35016
+ speedRandomMacro = result.randomMacro;
35017
+ } else {
35018
+ var result1 = this._uploadScalarSpeed(shaderData);
35019
+ speedModeMacro = result1.modeMacro;
35020
+ speedRandomMacro = result1.randomMacro;
35021
+ }
35022
+ // Drag
35023
+ var dragResult = this._uploadDrag(shaderData);
35024
+ dragCurveMacro = dragResult.curveMacro;
35025
+ dragRandomMacro = dragResult.randomMacro;
35026
+ // Drag modifiers
35027
+ if (this._multiplyDragByParticleSize) {
35028
+ dragSizeMacro = LimitVelocityOverLifetimeModule._multiplyDragBySizeMacro;
35029
+ }
35030
+ if (this._multiplyDragByParticleVelocity) {
35031
+ dragVelocityMacro = LimitVelocityOverLifetimeModule._multiplyDragByVelocityMacro;
35032
+ }
35033
+ }
35034
+ this._enabledModuleMacro = this._enableMacro(shaderData, this._enabledModuleMacro, enabledModuleMacro);
35035
+ this._separateAxesCachedMacro = this._enableMacro(shaderData, this._separateAxesCachedMacro, separateAxesMacro);
35036
+ this._speedModeMacro = this._enableMacro(shaderData, this._speedModeMacro, speedModeMacro);
35037
+ this._speedRandomMacro = this._enableMacro(shaderData, this._speedRandomMacro, speedRandomMacro);
35038
+ this._dragCurveCachedMacro = this._enableMacro(shaderData, this._dragCurveCachedMacro, dragCurveMacro);
35039
+ this._dragRandomCachedMacro = this._enableMacro(shaderData, this._dragRandomCachedMacro, dragRandomMacro);
35040
+ this._dragSizeMacro = this._enableMacro(shaderData, this._dragSizeMacro, dragSizeMacro);
35041
+ this._dragVelocityMacro = this._enableMacro(shaderData, this._dragVelocityMacro, dragVelocityMacro);
35042
+ };
35043
+ /**
35044
+ * @internal
35045
+ */ _proto._resetRandomSeed = function _resetRandomSeed(seed) {
35046
+ this._speedRand.reset(seed, ParticleRandomSubSeeds.LimitVelocityOverLifetime);
35047
+ };
35048
+ _proto._uploadScalarSpeed = function _uploadScalarSpeed(shaderData) {
35049
+ var speedX = this._speedX;
35050
+ var modeMacro = null;
35051
+ var randomMacro = null;
35052
+ var isRandomCurveMode = speedX.mode === ParticleCurveMode.TwoCurves;
35053
+ if (isRandomCurveMode || speedX.mode === ParticleCurveMode.Curve) {
35054
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedMaxCurveProperty, speedX.curveMax._getTypeArray());
35055
+ modeMacro = LimitVelocityOverLifetimeModule._speedCurveModeMacro;
35056
+ if (isRandomCurveMode) {
35057
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedMinCurveProperty, speedX.curveMin._getTypeArray());
35058
+ randomMacro = LimitVelocityOverLifetimeModule._speedIsRandomMacro;
35059
+ }
35060
+ } else {
35061
+ shaderData.setFloat(LimitVelocityOverLifetimeModule._speedMaxConstProperty, speedX.constantMax);
35062
+ modeMacro = LimitVelocityOverLifetimeModule._speedConstantModeMacro;
35063
+ if (speedX.mode === ParticleCurveMode.TwoConstants) {
35064
+ shaderData.setFloat(LimitVelocityOverLifetimeModule._speedMinConstProperty, speedX.constantMin);
35065
+ randomMacro = LimitVelocityOverLifetimeModule._speedIsRandomMacro;
35066
+ }
35067
+ }
35068
+ return {
35069
+ modeMacro: modeMacro,
35070
+ randomMacro: randomMacro
35071
+ };
35072
+ };
35073
+ _proto._uploadSeparateAxisSpeeds = function _uploadSeparateAxisSpeeds(shaderData) {
35074
+ var speedX = this._speedX;
35075
+ var speedY = this._speedY;
35076
+ var speedZ = this._speedZ;
35077
+ var modeMacro = null;
35078
+ var randomMacro = null;
35079
+ var isRandomCurveMode = speedX.mode === ParticleCurveMode.TwoCurves && speedY.mode === ParticleCurveMode.TwoCurves && speedZ.mode === ParticleCurveMode.TwoCurves;
35080
+ if (isRandomCurveMode || speedX.mode === ParticleCurveMode.Curve && speedY.mode === ParticleCurveMode.Curve && speedZ.mode === ParticleCurveMode.Curve) {
35081
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedXMaxCurveProperty, speedX.curveMax._getTypeArray());
35082
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedYMaxCurveProperty, speedY.curveMax._getTypeArray());
35083
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedZMaxCurveProperty, speedZ.curveMax._getTypeArray());
35084
+ modeMacro = LimitVelocityOverLifetimeModule._speedCurveModeMacro;
35085
+ if (isRandomCurveMode) {
35086
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedXMinCurveProperty, speedX.curveMin._getTypeArray());
35087
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedYMinCurveProperty, speedY.curveMin._getTypeArray());
35088
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._speedZMinCurveProperty, speedZ.curveMin._getTypeArray());
35089
+ randomMacro = LimitVelocityOverLifetimeModule._speedIsRandomMacro;
35090
+ }
35091
+ } else {
35092
+ var constantMax = this._speedMaxConstantVec;
35093
+ constantMax.set(speedX.constantMax, speedY.constantMax, speedZ.constantMax);
35094
+ shaderData.setVector3(LimitVelocityOverLifetimeModule._speedMaxConstVecProperty, constantMax);
35095
+ modeMacro = LimitVelocityOverLifetimeModule._speedConstantModeMacro;
35096
+ if (speedX.mode === ParticleCurveMode.TwoConstants && speedY.mode === ParticleCurveMode.TwoConstants && speedZ.mode === ParticleCurveMode.TwoConstants) {
35097
+ var constantMin = this._speedMinConstantVec;
35098
+ constantMin.set(speedX.constantMin, speedY.constantMin, speedZ.constantMin);
35099
+ shaderData.setVector3(LimitVelocityOverLifetimeModule._speedMinConstVecProperty, constantMin);
35100
+ randomMacro = LimitVelocityOverLifetimeModule._speedIsRandomMacro;
35101
+ }
35102
+ }
35103
+ return {
35104
+ modeMacro: modeMacro,
35105
+ randomMacro: randomMacro
35106
+ };
35107
+ };
35108
+ _proto._uploadDrag = function _uploadDrag(shaderData) {
35109
+ var drag = this._drag;
35110
+ var curveMacro = null;
35111
+ var randomMacro = null;
35112
+ var isRandomCurveMode = drag.mode === ParticleCurveMode.TwoCurves;
35113
+ if (isRandomCurveMode || drag.mode === ParticleCurveMode.Curve) {
35114
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._dragMaxCurveProperty, drag.curveMax._getTypeArray());
35115
+ curveMacro = LimitVelocityOverLifetimeModule._dragCurveModeMacro;
35116
+ if (isRandomCurveMode) {
35117
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._dragMinCurveProperty, drag.curveMin._getTypeArray());
35118
+ randomMacro = LimitVelocityOverLifetimeModule._dragIsRandomMacro;
35119
+ }
35120
+ } else {
35121
+ var dragVec = this._dragConstantVec;
35122
+ if (drag.mode === ParticleCurveMode.TwoConstants) {
35123
+ dragVec.set(drag.constantMin, drag.constantMax);
35124
+ } else {
35125
+ dragVec.set(drag.constantMax, drag.constantMax);
35126
+ }
35127
+ shaderData.setVector2(LimitVelocityOverLifetimeModule._dragConstantProperty, dragVec);
35128
+ }
35129
+ return {
35130
+ curveMacro: curveMacro,
35131
+ randomMacro: randomMacro
35132
+ };
35133
+ };
35134
+ _create_class(LimitVelocityOverLifetimeModule, [
35135
+ {
35136
+ key: "separateAxes",
35137
+ get: /**
35138
+ * Whether to limit velocity on each axis separately.
35139
+ */ function get() {
35140
+ return this._separateAxes;
35141
+ },
35142
+ set: function set(value) {
35143
+ if (value !== this._separateAxes) {
35144
+ this._separateAxes = value;
35145
+ this._generator._renderer._onGeneratorParamsChanged();
35146
+ }
35147
+ }
35148
+ },
35149
+ {
35150
+ key: "speed",
35151
+ get: /**
35152
+ * Speed limit when separateAxes is false.
35153
+ */ function get() {
35154
+ return this._speedX;
35155
+ },
35156
+ set: function set(value) {
35157
+ this.speedX = value;
35158
+ }
35159
+ },
35160
+ {
35161
+ key: "speedX",
35162
+ get: /**
35163
+ * Speed limit for the x-axis (or overall limit when separateAxes is false).
35164
+ */ function get() {
35165
+ return this._speedX;
35166
+ },
35167
+ set: function set(value) {
35168
+ var lastValue = this._speedX;
35169
+ if (value !== lastValue) {
35170
+ this._speedX = value;
35171
+ this._onCompositeCurveChange(lastValue, value);
35172
+ }
35173
+ }
35174
+ },
35175
+ {
35176
+ key: "speedY",
35177
+ get: /**
35178
+ * Speed limit for the y-axis.
35179
+ */ function get() {
35180
+ return this._speedY;
35181
+ },
35182
+ set: function set(value) {
35183
+ var lastValue = this._speedY;
35184
+ if (value !== lastValue) {
35185
+ this._speedY = value;
35186
+ this._onCompositeCurveChange(lastValue, value);
35187
+ }
35188
+ }
35189
+ },
35190
+ {
35191
+ key: "speedZ",
35192
+ get: /**
35193
+ * Speed limit for the z-axis.
35194
+ */ function get() {
35195
+ return this._speedZ;
35196
+ },
35197
+ set: function set(value) {
35198
+ var lastValue = this._speedZ;
35199
+ if (value !== lastValue) {
35200
+ this._speedZ = value;
35201
+ this._onCompositeCurveChange(lastValue, value);
35202
+ }
35203
+ }
35204
+ },
35205
+ {
35206
+ key: "dampen",
35207
+ get: /**
35208
+ * Controls how much the velocity is dampened when it exceeds the limit.
35209
+ * @remarks Value is clamped to [0, 1]. 0 means no damping, 1 means full damping.
35210
+ */ function get() {
35211
+ return this._dampen;
35212
+ },
35213
+ set: function set(value) {
35214
+ value = Math.max(0, Math.min(1, value));
35215
+ if (value !== this._dampen) {
35216
+ this._dampen = value;
35217
+ this._generator._renderer._onGeneratorParamsChanged();
35218
+ }
35219
+ }
35220
+ },
35221
+ {
35222
+ key: "drag",
35223
+ get: /**
35224
+ * Controls the amount of drag applied to particle velocities.
35225
+ */ function get() {
35226
+ return this._drag;
35227
+ },
35228
+ set: function set(value) {
35229
+ var lastValue = this._drag;
35230
+ if (value !== lastValue) {
35231
+ this._drag = value;
35232
+ this._onCompositeCurveChange(lastValue, value);
35233
+ }
35234
+ }
35235
+ },
35236
+ {
35237
+ key: "multiplyDragByParticleSize",
35238
+ get: /**
35239
+ * Adjust the amount of drag based on particle sizes.
35240
+ */ function get() {
35241
+ return this._multiplyDragByParticleSize;
35242
+ },
35243
+ set: function set(value) {
35244
+ if (value !== this._multiplyDragByParticleSize) {
35245
+ this._multiplyDragByParticleSize = value;
35246
+ this._generator._renderer._onGeneratorParamsChanged();
35247
+ }
35248
+ }
35249
+ },
35250
+ {
35251
+ key: "multiplyDragByParticleVelocity",
35252
+ get: /**
35253
+ * Adjust the amount of drag based on particle speeds.
35254
+ */ function get() {
35255
+ return this._multiplyDragByParticleVelocity;
35256
+ },
35257
+ set: function set(value) {
35258
+ if (value !== this._multiplyDragByParticleVelocity) {
35259
+ this._multiplyDragByParticleVelocity = value;
35260
+ this._generator._renderer._onGeneratorParamsChanged();
35261
+ }
35262
+ }
35263
+ },
35264
+ {
35265
+ key: "space",
35266
+ get: /**
35267
+ * Specifies if the velocity limits are in local space or world space.
35268
+ * @remarks Only takes effect when 'separateAxes' is enabled.
35269
+ */ function get() {
35270
+ return this._space;
35271
+ },
35272
+ set: function set(value) {
35273
+ if (value !== this._space) {
35274
+ this._space = value;
35275
+ this._generator._renderer._onGeneratorParamsChanged();
35276
+ }
35277
+ }
35278
+ },
35279
+ {
35280
+ key: "enabled",
35281
+ get: /**
35282
+ * Specifies whether the module is enabled.
35283
+ * @remarks This module requires WebGL2, On WebGL1, enabling will be silently ignored.
35284
+ */ function get() {
35285
+ return this._enabled;
35286
+ },
35287
+ set: function set(value) {
35288
+ if (value !== this._enabled) {
35289
+ if (value && !this._generator._renderer.engine._hardwareRenderer.isWebGL2) {
35290
+ return;
35291
+ }
35292
+ this._enabled = value;
35293
+ this._generator._setTransformFeedback(value);
35294
+ this._generator._renderer._onGeneratorParamsChanged();
35295
+ }
35296
+ }
35297
+ }
35298
+ ]);
35299
+ return LimitVelocityOverLifetimeModule;
35300
+ }(ParticleGeneratorModule);
35301
+ LimitVelocityOverLifetimeModule._enabledMacro = ShaderMacro.getByName("RENDERER_LVL_MODULE_ENABLED");
35302
+ LimitVelocityOverLifetimeModule._separateAxesMacro = ShaderMacro.getByName("RENDERER_LVL_SEPARATE_AXES");
35303
+ LimitVelocityOverLifetimeModule._speedConstantModeMacro = ShaderMacro.getByName("RENDERER_LVL_SPEED_CONSTANT_MODE");
35304
+ LimitVelocityOverLifetimeModule._speedCurveModeMacro = ShaderMacro.getByName("RENDERER_LVL_SPEED_CURVE_MODE");
35305
+ LimitVelocityOverLifetimeModule._speedIsRandomMacro = ShaderMacro.getByName("RENDERER_LVL_SPEED_IS_RANDOM_TWO");
35306
+ LimitVelocityOverLifetimeModule._dragCurveModeMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_CURVE_MODE");
35307
+ LimitVelocityOverLifetimeModule._dragIsRandomMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_IS_RANDOM_TWO");
35308
+ LimitVelocityOverLifetimeModule._multiplyDragBySizeMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_MULTIPLY_SIZE");
35309
+ LimitVelocityOverLifetimeModule._multiplyDragByVelocityMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_MULTIPLY_VELOCITY");
35310
+ LimitVelocityOverLifetimeModule._speedMaxConstProperty = ShaderProperty.getByName("renderer_LVLSpeedMaxConst");
35311
+ LimitVelocityOverLifetimeModule._speedMinConstProperty = ShaderProperty.getByName("renderer_LVLSpeedMinConst");
35312
+ LimitVelocityOverLifetimeModule._speedMaxCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedMaxCurve");
35313
+ LimitVelocityOverLifetimeModule._speedMinCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedMinCurve");
35314
+ LimitVelocityOverLifetimeModule._speedMaxConstVecProperty = ShaderProperty.getByName("renderer_LVLSpeedMaxConstVector");
35315
+ LimitVelocityOverLifetimeModule._speedMinConstVecProperty = ShaderProperty.getByName("renderer_LVLSpeedMinConstVector");
35316
+ LimitVelocityOverLifetimeModule._speedXMaxCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedXMaxCurve");
35317
+ LimitVelocityOverLifetimeModule._speedXMinCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedXMinCurve");
35318
+ LimitVelocityOverLifetimeModule._speedYMaxCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedYMaxCurve");
35319
+ LimitVelocityOverLifetimeModule._speedYMinCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedYMinCurve");
35320
+ LimitVelocityOverLifetimeModule._speedZMaxCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedZMaxCurve");
35321
+ LimitVelocityOverLifetimeModule._speedZMinCurveProperty = ShaderProperty.getByName("renderer_LVLSpeedZMinCurve");
35322
+ LimitVelocityOverLifetimeModule._dampenProperty = ShaderProperty.getByName("renderer_LVLDampen");
35323
+ LimitVelocityOverLifetimeModule._dragConstantProperty = ShaderProperty.getByName("renderer_LVLDragConstant");
35324
+ LimitVelocityOverLifetimeModule._dragMaxCurveProperty = ShaderProperty.getByName("renderer_LVLDragMaxCurve");
35325
+ LimitVelocityOverLifetimeModule._dragMinCurveProperty = ShaderProperty.getByName("renderer_LVLDragMinCurve");
35326
+ LimitVelocityOverLifetimeModule._spaceProperty = ShaderProperty.getByName("renderer_LVLSpace");
35327
+ __decorate([
35328
+ ignoreClone
35329
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedRand", void 0);
35330
+ __decorate([
35331
+ ignoreClone
35332
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedMinConstantVec", void 0);
35333
+ __decorate([
35334
+ ignoreClone
35335
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedMaxConstantVec", void 0);
35336
+ __decorate([
35337
+ ignoreClone
35338
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragConstantVec", void 0);
35339
+ __decorate([
35340
+ ignoreClone
35341
+ ], LimitVelocityOverLifetimeModule.prototype, "_enabledModuleMacro", void 0);
35342
+ __decorate([
35343
+ ignoreClone
35344
+ ], LimitVelocityOverLifetimeModule.prototype, "_separateAxesCachedMacro", void 0);
35345
+ __decorate([
35346
+ ignoreClone
35347
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedModeMacro", void 0);
35348
+ __decorate([
35349
+ ignoreClone
35350
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedRandomMacro", void 0);
35351
+ __decorate([
35352
+ ignoreClone
35353
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragCurveCachedMacro", void 0);
35354
+ __decorate([
35355
+ ignoreClone
35356
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragRandomCachedMacro", void 0);
35357
+ __decorate([
35358
+ ignoreClone
35359
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragSizeMacro", void 0);
35360
+ __decorate([
35361
+ ignoreClone
35362
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragVelocityMacro", void 0);
35363
+ __decorate([
35364
+ deepClone
35365
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedX", void 0);
35366
+ __decorate([
35367
+ deepClone
35368
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedY", void 0);
35369
+ __decorate([
35370
+ deepClone
35371
+ ], LimitVelocityOverLifetimeModule.prototype, "_speedZ", void 0);
35372
+ __decorate([
35373
+ deepClone
35374
+ ], LimitVelocityOverLifetimeModule.prototype, "_drag", void 0);
35375
+
34526
35376
  /**
34527
35377
  * Control how Particle Generator apply transform scale.
34528
35378
  */ var ParticleScaleMode = /*#__PURE__*/ function(ParticleScaleMode) {
@@ -35571,6 +36421,8 @@ __decorate([
35571
36421
  /** @internal */ this._firstRetiredElement = 0;
35572
36422
  /** @internal */ this._vertexBufferBindings = new Array();
35573
36423
  /** @internal */ this._subPrimitive = new SubMesh(0, 0, MeshTopology.Triangles);
36424
+ /** @internal */ this._useTransformFeedback = false;
36425
+ /** @internal */ this._feedbackBindingIndex = -1;
35574
36426
  this._isPlaying = false;
35575
36427
  this._instanceBufferResized = false;
35576
36428
  this._waitProcessRetiredElementCount = 0;
@@ -35589,6 +36441,7 @@ __decorate([
35589
36441
  this.velocityOverLifetime = new VelocityOverLifetimeModule(this);
35590
36442
  this.forceOverLifetime = new ForceOverLifetimeModule(this);
35591
36443
  this.sizeOverLifetime = new SizeOverLifetimeModule(this);
36444
+ this.limitVelocityOverLifetime = new LimitVelocityOverLifetimeModule(this);
35592
36445
  this.emission.enabled = true;
35593
36446
  }
35594
36447
  var _proto = ParticleGenerator.prototype;
@@ -35627,11 +36480,7 @@ __decorate([
35627
36480
  } else {
35628
36481
  this._isPlaying = false;
35629
36482
  if (stopMode === ParticleStopMode.StopEmittingAndClear) {
35630
- // Move the pointer to free immediately
35631
- var firstFreeElement = this._firstFreeElement;
35632
- this._firstRetiredElement = firstFreeElement;
35633
- this._firstActiveElement = firstFreeElement;
35634
- this._firstNewElement = firstFreeElement;
36483
+ this._clearActiveParticles();
35635
36484
  this._playTime = 0;
35636
36485
  this._firstActiveTransformedBoundingBox = this._firstFreeTransformedBoundingBox;
35637
36486
  this.emission._reset();
@@ -35715,6 +36564,16 @@ __decorate([
35715
36564
  this._isPlaying = false;
35716
36565
  }
35717
36566
  }
36567
+ // Retire all particles on device restore before bounds/volume bookkeeping
36568
+ var isContentLost = this._instanceVertexBufferBinding._buffer.isContentLost;
36569
+ if (isContentLost) {
36570
+ this._firstActiveElement = 0;
36571
+ this._firstNewElement = 0;
36572
+ this._firstFreeElement = 0;
36573
+ this._firstRetiredElement = 0;
36574
+ this._waitProcessRetiredElementCount = 0;
36575
+ this._firstActiveTransformedBoundingBox = this._firstFreeTransformedBoundingBox;
36576
+ }
35718
36577
  if (this.isAlive) {
35719
36578
  if (main.simulationSpace === ParticleSimulationSpace.World) {
35720
36579
  this._generateTransformedBounds();
@@ -35728,16 +36587,21 @@ __decorate([
35728
36587
  if (this.isAlive !== lastAlive) {
35729
36588
  this._renderer._onWorldVolumeChanged();
35730
36589
  }
35731
- // Add new particles to vertex buffer when has wait process retired element or new particle
35732
- //
35733
- // Another choice is just add new particles to vertex buffer and render all particles ignore the retired particle in shader, especially billboards
35734
- // But webgl don't support map buffer range, so this choice don't have performance advantage even less set data to GPU
35735
- if (this._firstNewElement != this._firstFreeElement || this._waitProcessRetiredElementCount > 0 || this._instanceBufferResized || this._instanceVertexBufferBinding._buffer.isContentLost) {
36590
+ if (this._firstNewElement != this._firstFreeElement || this._waitProcessRetiredElementCount > 0 || this._instanceBufferResized) {
35736
36591
  this._addActiveParticlesToVertexBuffer();
35737
36592
  }
35738
36593
  };
35739
36594
  /**
35740
36595
  * @internal
36596
+ * Run Transform Feedback simulation pass.
36597
+ */ _proto._updateFeedback = function _updateFeedback(shaderData, deltaTime) {
36598
+ this._feedbackSimulator.update(shaderData, this._currentParticleCount, this._firstActiveElement, this._firstFreeElement, deltaTime);
36599
+ // After swap, update the render pass buffer binding to point to the latest output.
36600
+ // VAO is disabled in TF mode so direct assignment is safe (no stale VAO issue).
36601
+ this._primitive.vertexBufferBindings[this._feedbackBindingIndex] = this._feedbackSimulator.readBinding;
36602
+ };
36603
+ /**
36604
+ * @internal
35741
36605
  */ _proto._reorganizeGeometryBuffers = function _reorganizeGeometryBuffers() {
35742
36606
  var _this = this, renderer = _this._renderer, primitive = _this._primitive, vertexBufferBindings = _this._vertexBufferBindings;
35743
36607
  var _renderer_engine = renderer.engine, particleUtils = _renderer_engine._particleBufferUtils;
@@ -35789,6 +36653,15 @@ __decorate([
35789
36653
  if (this._instanceVertexBufferBinding) {
35790
36654
  vertexBufferBindings.push(this._instanceVertexBufferBinding);
35791
36655
  }
36656
+ // Add feedback buffer binding for render pass
36657
+ if (this._useTransformFeedback) {
36658
+ this._feedbackBindingIndex = vertexBufferBindings.length;
36659
+ primitive.addVertexElement(new VertexElement(ParticleFeedbackVertexAttribute.Position, 0, VertexElementFormat.Vector3, this._feedbackBindingIndex, 1));
36660
+ primitive.addVertexElement(new VertexElement(ParticleFeedbackVertexAttribute.Velocity, 12, VertexElementFormat.Vector3, this._feedbackBindingIndex, 1));
36661
+ vertexBufferBindings.push(this._feedbackSimulator.readBinding);
36662
+ } else {
36663
+ this._feedbackBindingIndex = -1;
36664
+ }
35792
36665
  primitive.setVertexBufferBindings(vertexBufferBindings);
35793
36666
  };
35794
36667
  /**
@@ -35804,18 +36677,28 @@ __decorate([
35804
36677
  vertexInstanceBuffer.isGCIgnored = true;
35805
36678
  var vertexBufferBindings = this._primitive.vertexBufferBindings;
35806
36679
  var vertexBufferBinding = new VertexBufferBinding(vertexInstanceBuffer, stride);
35807
- var instanceVertices = new Float32Array(newByteLength / 4);
35808
36680
  var lastInstanceVertices = this._instanceVertices;
36681
+ var useFeedback = this._useTransformFeedback;
36682
+ var instanceVertices = new Float32Array(newByteLength / 4);
36683
+ if (useFeedback) {
36684
+ this._feedbackSimulator.resize(newParticleCount, vertexBufferBinding);
36685
+ }
35809
36686
  if (lastInstanceVertices) {
35810
- var floatStride = ParticleBufferUtils.instanceVertexFloatStride;
36687
+ var floatStride = ParticleBufferUtils.instanceVertexFloatStride, feedbackVertexStride = ParticleBufferUtils.feedbackVertexStride;
35811
36688
  var firstFreeElement = this._firstFreeElement;
35812
36689
  var firstRetiredElement = this._firstRetiredElement;
35813
36690
  if (isIncrease) {
36691
+ // Copy front segment [0, firstFreeElement)
35814
36692
  instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, 0, firstFreeElement * floatStride));
36693
+ // Copy tail segment shifted by increaseCount
35815
36694
  var nextFreeElement = firstFreeElement + 1;
35816
- var freeEndOffset = (nextFreeElement + increaseCount) * floatStride;
35817
- instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, nextFreeElement * floatStride * 4), freeEndOffset);
35818
- // Maintain expanded pointers
36695
+ var tailCount = this._currentParticleCount - nextFreeElement;
36696
+ var tailDstElement = nextFreeElement + increaseCount;
36697
+ instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, nextFreeElement * floatStride * 4), tailDstElement * floatStride);
36698
+ if (useFeedback) {
36699
+ this._feedbackSimulator.copyOldBufferData(0, 0, firstFreeElement * feedbackVertexStride);
36700
+ this._feedbackSimulator.copyOldBufferData(nextFreeElement * feedbackVertexStride, tailDstElement * feedbackVertexStride, tailCount * feedbackVertexStride);
36701
+ }
35819
36702
  this._firstNewElement > firstFreeElement && (this._firstNewElement += increaseCount);
35820
36703
  this._firstActiveElement > firstFreeElement && (this._firstActiveElement += increaseCount);
35821
36704
  firstRetiredElement > firstFreeElement && (this._firstRetiredElement += increaseCount);
@@ -35824,7 +36707,6 @@ __decorate([
35824
36707
  if (firstRetiredElement <= firstFreeElement) {
35825
36708
  migrateCount = firstFreeElement - firstRetiredElement;
35826
36709
  bufferOffset = 0;
35827
- // Maintain expanded pointers
35828
36710
  this._firstFreeElement -= firstRetiredElement;
35829
36711
  this._firstNewElement -= firstRetiredElement;
35830
36712
  this._firstActiveElement -= firstRetiredElement;
@@ -35832,20 +36714,29 @@ __decorate([
35832
36714
  } else {
35833
36715
  migrateCount = this._currentParticleCount - firstRetiredElement;
35834
36716
  bufferOffset = firstFreeElement;
35835
- // Maintain expanded pointers
35836
36717
  this._firstNewElement > firstFreeElement && (this._firstNewElement -= firstFreeElement);
35837
36718
  this._firstActiveElement > firstFreeElement && (this._firstActiveElement -= firstFreeElement);
35838
36719
  firstRetiredElement > firstFreeElement && (this._firstRetiredElement -= firstFreeElement);
35839
36720
  }
35840
36721
  instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, firstRetiredElement * floatStride * 4, migrateCount * floatStride), bufferOffset * floatStride);
36722
+ if (useFeedback) {
36723
+ this._feedbackSimulator.copyOldBufferData(firstRetiredElement * feedbackVertexStride, bufferOffset * feedbackVertexStride, migrateCount * feedbackVertexStride);
36724
+ }
36725
+ }
36726
+ if (useFeedback) {
36727
+ this._feedbackSimulator.destroyOldBuffers();
35841
36728
  }
35842
36729
  this._instanceBufferResized = true;
35843
36730
  }
35844
- // Instance buffer always at last
35845
- this._primitive.setVertexBufferBinding(lastInstanceVertices ? vertexBufferBindings.length - 1 : vertexBufferBindings.length, vertexBufferBinding);
36731
+ // Update instance buffer binding
36732
+ var instanceBindingIndex = lastInstanceVertices ? vertexBufferBindings.length - 1 - (useFeedback ? 1 : 0) : vertexBufferBindings.length;
36733
+ this._primitive.setVertexBufferBinding(instanceBindingIndex, vertexBufferBinding);
35846
36734
  this._instanceVertices = instanceVertices;
35847
36735
  this._instanceVertexBufferBinding = vertexBufferBinding;
35848
36736
  this._currentParticleCount = newParticleCount;
36737
+ if (useFeedback) {
36738
+ this._primitive.setVertexBufferBinding(this._feedbackBindingIndex, this._feedbackSimulator.readBinding);
36739
+ }
35849
36740
  };
35850
36741
  /**
35851
36742
  * @internal
@@ -35853,6 +36744,7 @@ __decorate([
35853
36744
  this.main._updateShaderData(shaderData);
35854
36745
  this.velocityOverLifetime._updateShaderData(shaderData);
35855
36746
  this.forceOverLifetime._updateShaderData(shaderData);
36747
+ this.limitVelocityOverLifetime._updateShaderData(shaderData);
35856
36748
  this.textureSheetAnimation._updateShaderData(shaderData);
35857
36749
  this.sizeOverLifetime._updateShaderData(shaderData);
35858
36750
  this.rotationOverLifetime._updateShaderData(shaderData);
@@ -35867,11 +36759,41 @@ __decorate([
35867
36759
  this.textureSheetAnimation._resetRandomSeed(seed);
35868
36760
  this.velocityOverLifetime._resetRandomSeed(seed);
35869
36761
  this.forceOverLifetime._resetRandomSeed(seed);
36762
+ this.limitVelocityOverLifetime._resetRandomSeed(seed);
35870
36763
  this.rotationOverLifetime._resetRandomSeed(seed);
35871
36764
  this.colorOverLifetime._resetRandomSeed(seed);
35872
36765
  };
35873
36766
  /**
35874
36767
  * @internal
36768
+ */ _proto._setTransformFeedback = function _setTransformFeedback(enabled) {
36769
+ this._useTransformFeedback = enabled;
36770
+ // Switching TF mode invalidates all active particle state: feedback buffers and instance
36771
+ // buffer layout are incompatible between the two paths. Clear rather than show a one-frame
36772
+ // jump; new particles will fill in naturally from the next emit cycle.
36773
+ this._clearActiveParticles();
36774
+ if (enabled) {
36775
+ if (!this._feedbackSimulator) {
36776
+ this._feedbackSimulator = new ParticleTransformFeedbackSimulator(this._renderer.engine);
36777
+ }
36778
+ var simulator = this._feedbackSimulator;
36779
+ var readBinding = simulator.readBinding;
36780
+ if (!readBinding || readBinding.buffer.byteLength !== this._currentParticleCount * ParticleBufferUtils.feedbackVertexStride) {
36781
+ simulator.resize(this._currentParticleCount, this._instanceVertexBufferBinding);
36782
+ simulator.destroyOldBuffers();
36783
+ } else {
36784
+ simulator._instanceBinding = this._instanceVertexBufferBinding;
36785
+ }
36786
+ this._renderer.shaderData.enableMacro(ParticleGenerator._transformFeedbackMacro);
36787
+ // Feedback buffer swaps every frame; VAO caching would bake stale buffer handles.
36788
+ this._primitive.enableVAO = false;
36789
+ } else {
36790
+ this._renderer.shaderData.disableMacro(ParticleGenerator._transformFeedbackMacro);
36791
+ this._primitive.enableVAO = true;
36792
+ }
36793
+ this._reorganizeGeometryBuffers();
36794
+ };
36795
+ /**
36796
+ * @internal
35875
36797
  */ _proto._getAliveParticleCount = function _getAliveParticleCount() {
35876
36798
  if (this._firstActiveElement <= this._firstFreeElement) {
35877
36799
  return this._firstFreeElement - this._firstActiveElement;
@@ -35898,10 +36820,19 @@ __decorate([
35898
36820
  };
35899
36821
  /**
35900
36822
  * @internal
36823
+ */ _proto._cloneTo = function _cloneTo(target) {
36824
+ if (target.limitVelocityOverLifetime.enabled) {
36825
+ target._setTransformFeedback(true);
36826
+ }
36827
+ };
36828
+ /**
36829
+ * @internal
35901
36830
  */ _proto._destroy = function _destroy() {
36831
+ var _this__feedbackSimulator;
35902
36832
  this._instanceVertexBufferBinding.buffer.destroy();
35903
36833
  this._primitive.destroy();
35904
36834
  this.emission._destroy();
36835
+ (_this__feedbackSimulator = this._feedbackSimulator) == null ? void 0 : _this__feedbackSimulator.destroy();
35905
36836
  };
35906
36837
  /**
35907
36838
  * @internal
@@ -36133,8 +37064,34 @@ __decorate([
36133
37064
  instanceVertices[offset + 39] = rand1.random();
36134
37065
  instanceVertices[offset + 40] = rand1.random();
36135
37066
  }
37067
+ var limitVelocityOverLifetime = this.limitVelocityOverLifetime;
37068
+ if (limitVelocityOverLifetime.enabled && (limitVelocityOverLifetime._isSpeedRandomMode() || limitVelocityOverLifetime._isDragRandomMode())) {
37069
+ instanceVertices[offset + 41] = limitVelocityOverLifetime._speedRand.random();
37070
+ }
37071
+ // Initialize feedback buffer for this particle
37072
+ if (this._useTransformFeedback) {
37073
+ this._addFeedbackParticle(firstFreeElement, position, direction, startSpeed, transform);
37074
+ }
36136
37075
  this._firstFreeElement = nextFreeElement;
36137
37076
  };
37077
+ _proto._addFeedbackParticle = function _addFeedbackParticle(index, shapePosition, direction, startSpeed, transform) {
37078
+ var position;
37079
+ if (this.main.simulationSpace === ParticleSimulationSpace.Local) {
37080
+ position = shapePosition;
37081
+ } else {
37082
+ position = ParticleGenerator._tempVector32;
37083
+ engineMath.Vector3.transformByQuat(shapePosition, transform.worldRotationQuaternion, position);
37084
+ position.add(transform.worldPosition);
37085
+ }
37086
+ this._feedbackSimulator.writeParticleData(index, position, direction.x * startSpeed, direction.y * startSpeed, direction.z * startSpeed);
37087
+ };
37088
+ _proto._clearActiveParticles = function _clearActiveParticles() {
37089
+ var firstFreeElement = this._firstFreeElement;
37090
+ this._firstRetiredElement = firstFreeElement;
37091
+ this._firstActiveElement = firstFreeElement;
37092
+ this._firstNewElement = firstFreeElement;
37093
+ this._firstActiveTransformedBoundingBox = this._firstFreeTransformedBoundingBox;
37094
+ };
36138
37095
  _proto._retireActiveParticles = function _retireActiveParticles() {
36139
37096
  var engine = this._renderer.engine;
36140
37097
  var frameCount = engine.time.frameCount;
@@ -36178,16 +37135,19 @@ __decorate([
36178
37135
  return;
36179
37136
  }
36180
37137
  var byteStride = ParticleBufferUtils.instanceVertexStride;
36181
- var start = firstActiveElement * byteStride;
36182
37138
  var instanceBuffer = this._instanceVertexBufferBinding.buffer;
36183
37139
  var dataBuffer = this._instanceVertices.buffer;
37140
+ // Feedback mode: upload in-place (indices match feedback buffer slots)
37141
+ // Non-feedback mode: compact to GPU offset 0
37142
+ var compact = !this._useTransformFeedback;
37143
+ var start = firstActiveElement * byteStride;
36184
37144
  if (firstActiveElement < firstFreeElement) {
36185
- instanceBuffer.setData(dataBuffer, 0, start, (firstFreeElement - firstActiveElement) * byteStride, SetDataOptions.Discard);
37145
+ instanceBuffer.setData(dataBuffer, compact ? 0 : start, start, (firstFreeElement - firstActiveElement) * byteStride, SetDataOptions.Discard);
36186
37146
  } else {
36187
- var firstSegmentCount = (this._currentParticleCount - firstActiveElement) * byteStride;
36188
- instanceBuffer.setData(dataBuffer, 0, start, firstSegmentCount, SetDataOptions.Discard);
37147
+ var firstSegmentSize = (this._currentParticleCount - firstActiveElement) * byteStride;
37148
+ instanceBuffer.setData(dataBuffer, compact ? 0 : start, start, firstSegmentSize, SetDataOptions.Discard);
36189
37149
  if (firstFreeElement > 0) {
36190
- instanceBuffer.setData(dataBuffer, firstSegmentCount, 0, firstFreeElement * byteStride);
37150
+ instanceBuffer.setData(dataBuffer, compact ? firstSegmentSize : 0, 0, firstFreeElement * byteStride);
36191
37151
  }
36192
37152
  }
36193
37153
  this._firstNewElement = firstFreeElement;
@@ -36405,11 +37365,13 @@ ParticleGenerator._tempVector21 = new engineMath.Vector2();
36405
37365
  ParticleGenerator._tempVector22 = new engineMath.Vector2();
36406
37366
  ParticleGenerator._tempVector30 = new engineMath.Vector3();
36407
37367
  ParticleGenerator._tempVector31 = new engineMath.Vector3();
37368
+ ParticleGenerator._tempVector32 = new engineMath.Vector3();
36408
37369
  ParticleGenerator._tempMat = new engineMath.Matrix();
36409
37370
  ParticleGenerator._tempColor0 = new engineMath.Color();
36410
37371
  ParticleGenerator._tempParticleRenderers = new Array();
36411
37372
  ParticleGenerator._particleIncreaseCount = 128;
36412
37373
  ParticleGenerator._transformedBoundsIncreaseCount = 16;
37374
+ ParticleGenerator._transformFeedbackMacro = ShaderMacro.getByName("RENDERER_TRANSFORM_FEEDBACK");
36413
37375
  __decorate([
36414
37376
  deepClone
36415
37377
  ], ParticleGenerator.prototype, "main", void 0);
@@ -36422,6 +37384,9 @@ __decorate([
36422
37384
  __decorate([
36423
37385
  deepClone
36424
37386
  ], ParticleGenerator.prototype, "forceOverLifetime", void 0);
37387
+ __decorate([
37388
+ deepClone
37389
+ ], ParticleGenerator.prototype, "limitVelocityOverLifetime", void 0);
36425
37390
  __decorate([
36426
37391
  deepClone
36427
37392
  ], ParticleGenerator.prototype, "sizeOverLifetime", void 0);
@@ -36458,6 +37423,15 @@ __decorate([
36458
37423
  __decorate([
36459
37424
  ignoreClone
36460
37425
  ], ParticleGenerator.prototype, "_subPrimitive", void 0);
37426
+ __decorate([
37427
+ ignoreClone
37428
+ ], ParticleGenerator.prototype, "_feedbackSimulator", void 0);
37429
+ __decorate([
37430
+ ignoreClone
37431
+ ], ParticleGenerator.prototype, "_useTransformFeedback", void 0);
37432
+ __decorate([
37433
+ ignoreClone
37434
+ ], ParticleGenerator.prototype, "_feedbackBindingIndex", void 0);
36461
37435
  __decorate([
36462
37436
  ignoreClone
36463
37437
  ], ParticleGenerator.prototype, "_isPlaying", void 0);
@@ -38615,6 +39589,7 @@ exports.Keys = Keys;
38615
39589
  exports.Layer = Layer;
38616
39590
  exports.LayerPathMask = LayerPathMask;
38617
39591
  exports.Light = Light;
39592
+ exports.LimitVelocityOverLifetimeModule = LimitVelocityOverLifetimeModule;
38618
39593
  exports.Loader = Loader;
38619
39594
  exports.Logger = Logger;
38620
39595
  exports.MSAASamples = MSAASamples;