@galacean/engine 2.0.0-alpha.16 → 2.0.0-alpha.17

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/browser.js CHANGED
@@ -9880,13 +9880,15 @@
9880
9880
  ShadowVertexDeclaration: ShadowVertexDeclaration,
9881
9881
  ShadowVertex: ShadowVertex
9882
9882
  };
9883
- 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
9883
+ 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
9884
9884
  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
9885
9885
  var rotation_over_lifetime_module = "#if defined(RENDERER_ROL_CONSTANT_MODE) || defined(RENDERER_ROL_CURVE_MODE)\n #ifdef RENDERER_ROL_CURVE_MODE\n uniform vec2 renderer_ROLMaxCurveZ[4];\n #ifdef RENDERER_ROL_IS_SEPARATE\n uniform vec2 renderer_ROLMaxCurveX[4];\n uniform vec2 renderer_ROLMaxCurveY[4];\n #endif\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n uniform vec2 renderer_ROLMinCurveZ[4];\n #ifdef RENDERER_ROL_IS_SEPARATE\n uniform vec2 renderer_ROLMinCurveX[4];\n uniform vec2 renderer_ROLMinCurveY[4];\n #endif\n #endif\n #else\n uniform vec3 renderer_ROLMaxConst;\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n uniform vec3 renderer_ROLMinConst;\n #endif\n #endif\n#endif\n\nfloat computeParticleRotationFloat(in float rotation, in float age, in float normalizedAge) {\n #if defined(RENDERER_ROL_CONSTANT_MODE) || defined(RENDERER_ROL_CURVE_MODE)\n #ifdef RENDERER_ROL_CURVE_MODE\n float currentValue;\n float lifeRotation = evaluateParticleCurveCumulative(renderer_ROLMaxCurveZ, normalizedAge, currentValue);\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n lifeRotation = mix(evaluateParticleCurveCumulative(renderer_ROLMinCurveZ, normalizedAge, currentValue), lifeRotation, a_Random0.w);\n #endif\n rotation += lifeRotation * a_ShapePositionStartLifeTime.w;\n #else\n float lifeRotation = renderer_ROLMaxConst.z;\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n lifeRotation = mix(renderer_ROLMinConst.z, lifeRotation, a_Random0.w);\n #endif\n rotation += lifeRotation * age;\n #endif\n #endif\n return rotation;\n}\n\n\n#if defined(RENDERER_MODE_MESH) && (defined(RENDERER_ROL_CONSTANT_MODE) || defined(RENDERER_ROL_CURVE_MODE))\nvec3 computeParticleRotationVec3(in vec3 rotation, in float age, in float normalizedAge) {\n #ifdef RENDERER_ROL_IS_SEPARATE\n #ifdef RENDERER_ROL_CONSTANT_MODE\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n vec3 ageRot = mix(renderer_ROLMinConst, renderer_ROLMaxConst, a_Random0.w) * age;\n #else\n vec3 ageRot = renderer_ROLMaxConst * age;\n #endif\n rotation += ageRot;\n #endif\n #ifdef RENDERER_ROL_CURVE_MODE\n float currentValue;\n float lifetime = a_ShapePositionStartLifeTime.w;\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n rotation += vec3(\n mix(evaluateParticleCurveCumulative(renderer_ROLMinCurveX, normalizedAge, currentValue),\n evaluateParticleCurveCumulative(renderer_ROLMaxCurveX, normalizedAge, currentValue), a_Random0.w),\n mix(evaluateParticleCurveCumulative(renderer_ROLMinCurveY, normalizedAge, currentValue),\n evaluateParticleCurveCumulative(renderer_ROLMaxCurveY, normalizedAge, currentValue), a_Random0.w),\n mix(evaluateParticleCurveCumulative(renderer_ROLMinCurveZ, normalizedAge, currentValue),\n evaluateParticleCurveCumulative(renderer_ROLMaxCurveZ, normalizedAge, currentValue), a_Random0.w)) * lifetime;\n #else\n rotation += vec3(\n evaluateParticleCurveCumulative(renderer_ROLMaxCurveX, normalizedAge, currentValue),\n evaluateParticleCurveCumulative(renderer_ROLMaxCurveY, normalizedAge, currentValue),\n evaluateParticleCurveCumulative(renderer_ROLMaxCurveZ, normalizedAge, currentValue)) * lifetime;\n #endif\n #endif\n #else\n #ifdef RENDERER_ROL_CONSTANT_MODE\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n float ageRot = mix(renderer_ROLMinConst.z, renderer_ROLMaxConst.z, a_Random0.w) * age;\n #else\n float ageRot = renderer_ROLMaxConst.z * age;\n #endif\n rotation += ageRot;\n #endif\n\n #ifdef RENDERER_ROL_CURVE_MODE\n float currentValue;\n float lifeRotation = evaluateParticleCurveCumulative(renderer_ROLMaxCurveZ, normalizedAge, currentValue);\n #ifdef RENDERER_ROL_IS_RANDOM_TWO\n lifeRotation = mix(evaluateParticleCurveCumulative(renderer_ROLMinCurveZ, normalizedAge, currentValue), lifeRotation, a_Random0.w);\n #endif\n rotation += lifeRotation * a_ShapePositionStartLifeTime.w;\n #endif\n #endif\n return rotation;\n}\n#endif\n"; // eslint-disable-line
9886
9886
  var size_over_lifetime_module = "#ifdef RENDERER_SOL_CURVE_MODE\n uniform vec2 renderer_SOLMaxCurveX[4]; // x:time y:value\n #ifdef RENDERER_SOL_IS_SEPARATE\n uniform vec2 renderer_SOLMaxCurveY[4]; // x:time y:value\n uniform vec2 renderer_SOLMaxCurveZ[4]; // x:time y:value\n #endif\n\n #ifdef RENDERER_SOL_IS_RANDOM_TWO\n uniform vec2 renderer_SOLMinCurveX[4]; // x:time y:value\n #ifdef RENDERER_SOL_IS_SEPARATE\n uniform vec2 renderer_SOLMinCurveY[4]; // x:time y:value\n uniform vec2 renderer_SOLMinCurveZ[4]; // x:time y:value\n #endif\n #endif\n#endif\n\nvec2 computeParticleSizeBillboard(in vec2 size, in float normalizedAge) {\n #ifdef RENDERER_SOL_CURVE_MODE\n float lifeSizeX = evaluateParticleCurve(renderer_SOLMaxCurveX, normalizedAge);\n #ifdef RENDERER_SOL_IS_RANDOM_TWO\n lifeSizeX = mix(evaluateParticleCurve(renderer_SOLMinCurveX, normalizedAge), lifeSizeX, a_Random0.z);\n #endif\n\n #ifdef RENDERER_SOL_IS_SEPARATE\n float lifeSizeY = evaluateParticleCurve(renderer_SOLMaxCurveY, normalizedAge);\n #ifdef RENDERER_SOL_IS_RANDOM_TWO\n lifeSizeY = mix(evaluateParticleCurve(renderer_SOLMinCurveY, normalizedAge), lifeSizeY, a_Random0.z);\n #endif\n size *= vec2(lifeSizeX, lifeSizeY);\n #else\n size *= lifeSizeX;\n #endif\n #endif\n return size;\n}\n\n#ifdef RENDERER_MODE_MESH\n vec3 computeParticleSizeMesh(in vec3 size, in float normalizedAge) {\n #ifdef RENDERER_SOL_CURVE\n size *= evaluateParticleCurve(renderer_SOLMaxCurveX, normalizedAge);\n #endif\n #ifdef RENDERER_SOL_RANDOM_CURVES\n size *= mix(evaluateParticleCurve(renderer_SOLMaxCurveX, normalizedAge),\n evaluateParticleCurve(u_SOLSizeGradientMax, normalizedAge),\n a_Random0.z);\n #endif\n #ifdef RENDERER_SOL_CURVE_SEPARATE\n size *= vec3(evaluateParticleCurve(renderer_SOLMinCurveX, normalizedAge),\n evaluateParticleCurve(renderer_SOLMinCurveY, normalizedAge),\n evaluateParticleCurve(renderer_SOLMinCurveZ, normalizedAge));\n #endif\n #ifdef RENDERER_SOL_RANDOM_CURVES_SEPARATE\n size *= vec3(mix(evaluateParticleCurve(renderer_SOLMinCurveX, normalizedAge),\n evaluateParticleCurve(renderer_SOLMaxCurveX, normalizedAge),\n a_Random0.z),\n mix(evaluateParticleCurve(renderer_SOLMinCurveY, normalizedAge),\n evaluateParticleCurve(renderer_SOLMaxCurveY, normalizedAge),\n a_Random0.z),\n mix(evaluateParticleCurve(renderer_SOLMinCurveZ, normalizedAge),\n evaluateParticleCurve(renderer_SOLMaxCurveZ, normalizedAge),\n a_Random0.z));\n #endif\n return size;\n }\n#endif"; // eslint-disable-line
9887
9887
  var color_over_lifetime_module = "#if defined(RENDERER_COL_GRADIENT) || defined(RENDERER_COL_RANDOM_GRADIENTS)\n uniform vec4 renderer_COLMaxGradientColor[4]; // x:time y:r z:g w:b\n uniform vec2 renderer_COLMaxGradientAlpha[4]; // x:time y:alpha\n\n #ifdef RENDERER_COL_RANDOM_GRADIENTS\n uniform vec4 renderer_COLMinGradientColor[4]; // x:time y:r z:g w:b\n uniform vec2 renderer_COLMinGradientAlpha[4]; // x:time y:alpha\n #endif\n\n uniform vec4 renderer_COLGradientKeysMaxTime; // x: minColorKeysMaxTime, y: minAlphaKeysMaxTime, z: maxColorKeysMaxTime, w: maxAlphaKeysMaxTime\n#endif\n\n\nvec4 computeParticleColor(in vec4 color, in float normalizedAge) {\n #if defined(RENDERER_COL_GRADIENT) || defined(RENDERER_COL_RANDOM_GRADIENTS)\n vec4 gradientColor = evaluateParticleGradient(renderer_COLMaxGradientColor, renderer_COLGradientKeysMaxTime.z, renderer_COLMaxGradientAlpha, renderer_COLGradientKeysMaxTime.w, normalizedAge);\n #endif\n\n #ifdef RENDERER_COL_RANDOM_GRADIENTS\n gradientColor = mix(evaluateParticleGradient(renderer_COLMinGradientColor,renderer_COLGradientKeysMaxTime.x, renderer_COLMinGradientAlpha, renderer_COLGradientKeysMaxTime.y, normalizedAge), gradientColor, a_Random0.y);\n #endif\n\n #if defined(RENDERER_COL_GRADIENT) || defined(RENDERER_COL_RANDOM_GRADIENTS)\n color *= gradientColor;\n #endif\n\n return color;\n}\n"; // eslint-disable-line
9888
9888
  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
9889
- 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
9889
+ 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
9890
+ 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_LIMIT_CONSTANT_MODE\n uniform float renderer_LVLLimitMaxConst;\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n uniform float renderer_LVLLimitMinConst;\n #endif\n #endif\n #ifdef RENDERER_LVL_LIMIT_CURVE_MODE\n uniform vec2 renderer_LVLLimitMaxCurve[4];\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n uniform vec2 renderer_LVLLimitMinCurve[4];\n #endif\n #endif\n #endif\n\n // Per-axis limit\n #ifdef RENDERER_LVL_SEPARATE_AXES\n #ifdef RENDERER_LVL_LIMIT_CONSTANT_MODE\n uniform vec3 renderer_LVLLimitMaxConstVector;\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n uniform vec3 renderer_LVLLimitMinConstVector;\n #endif\n #endif\n #ifdef RENDERER_LVL_LIMIT_CURVE_MODE\n uniform vec2 renderer_LVLLimitXMaxCurve[4];\n uniform vec2 renderer_LVLLimitYMaxCurve[4];\n uniform vec2 renderer_LVLLimitZMaxCurve[4];\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n uniform vec2 renderer_LVLLimitXMinCurve[4];\n uniform vec2 renderer_LVLLimitYMinCurve[4];\n uniform vec2 renderer_LVLLimitZMinCurve[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 limitValue;\n #ifdef RENDERER_LVL_LIMIT_CONSTANT_MODE\n limitValue = renderer_LVLLimitMaxConstVector;\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n limitValue = mix(renderer_LVLLimitMinConstVector, limitValue, limitRand);\n #endif\n #endif\n #ifdef RENDERER_LVL_LIMIT_CURVE_MODE\n limitValue = vec3(\n evaluateParticleCurve(renderer_LVLLimitXMaxCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLLimitYMaxCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLLimitZMaxCurve, normalizedAge)\n );\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n vec3 minLimitValue = vec3(\n evaluateParticleCurve(renderer_LVLLimitXMinCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLLimitYMinCurve, normalizedAge),\n evaluateParticleCurve(renderer_LVLLimitZMinCurve, normalizedAge)\n );\n limitValue = mix(minLimitValue, limitValue, limitRand);\n #endif\n #endif\n\n vec3 absVel = abs(velocity);\n vec3 excess = max(absVel - limitValue, vec3(0.0));\n velocity = sign(velocity) * (absVel - excess * effectiveDampen);\n #else\n float limitValue;\n #ifdef RENDERER_LVL_LIMIT_CONSTANT_MODE\n limitValue = renderer_LVLLimitMaxConst;\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n limitValue = mix(renderer_LVLLimitMinConst, limitValue, limitRand);\n #endif\n #endif\n #ifdef RENDERER_LVL_LIMIT_CURVE_MODE\n limitValue = evaluateParticleCurve(renderer_LVLLimitMaxCurve, normalizedAge);\n #ifdef RENDERER_LVL_LIMIT_IS_RANDOM_TWO\n float minLimitValue = evaluateParticleCurve(renderer_LVLLimitMinCurve, normalizedAge);\n limitValue = mix(minLimitValue, limitValue, limitRand);\n #endif\n #endif\n\n float speed = length(velocity);\n if (speed > limitValue && speed > 0.0) {\n float excess = speed - limitValue;\n velocity = velocity * ((speed - excess * effectiveDampen) / speed);\n }\n #endif\n return velocity;\n }\n\n#endif\n"; // eslint-disable-line
9891
+ 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
9890
9892
  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
9891
9893
  var stretched_billboard = "#ifdef RENDERER_MODE_STRETCHED_BILLBOARD\n\tvec2 corner = a_CornerTextureCoordinate.xy + renderer_PivotOffset.xy;\n\tvec3 velocity = rotationByQuaternions(renderer_SizeScale * localVelocity, worldRotation) + worldVelocity;\n\tvec3 cameraUpVector = normalize(velocity);\n\tvec3 direction = normalize(center - camera_Position);\n\tvec3 sideVector = normalize(cross(direction, normalize(velocity)));\n\n\tsideVector = renderer_SizeScale.xzy * sideVector;\n\tcameraUpVector = length(vec3(renderer_SizeScale.x, 0.0, 0.0)) * cameraUpVector;\n\n\tvec2 size = computeParticleSizeBillboard(a_StartSize.xy, normalizedAge);\n\n\tconst mat2 rotationZHalfPI = mat2(0.0, -1.0, 1.0, 0.0);\n\tcorner = rotationZHalfPI * corner;\n\tcorner.y = corner.y - abs(corner.y);\n\n\tfloat speed = length(velocity); // TODO:\n\tcenter += sign(renderer_SizeScale.x) * (sign(renderer_StretchedBillboardLengthScale) * size.x * corner.x * sideVector\n\t + (speed * renderer_StretchedBillboardSpeedScale + size.y * renderer_StretchedBillboardLengthScale) * corner.y * cameraUpVector);\n#endif"; // eslint-disable-line
9892
9894
  var vertical_billboard = "#ifdef RENDERER_MODE_VERTICAL_BILLBOARD\n\tvec2 corner = a_CornerTextureCoordinate.xy + renderer_PivotOffset.xy; // Billboard模式z轴无效\n\tconst vec3 cameraUpVector = vec3(0.0, 1.0, 0.0);\n\tvec3 sideVector = normalize(cross(camera_Forward, cameraUpVector));\n\n\tfloat rot = radians(computeParticleRotationFloat(a_StartRotation0.x, age, normalizedAge));\n\tfloat c = cos(rot);\n\tfloat s = sin(rot);\n\tmat2 rotation = mat2(c, -s, s, c);\n\tcorner = rotation * corner * cos(0.78539816339744830961566084581988); // TODO:临时缩小cos45,不确定U3D原因\n\tcorner *= computeParticleSizeBillboard(a_StartSize.xy, normalizedAge);\n\tcenter += renderer_SizeScale.xzy * (corner.x * sideVector + corner.y * cameraUpVector);\n#endif"; // eslint-disable-line
@@ -9900,6 +9902,8 @@
9900
9902
  color_over_lifetime_module: color_over_lifetime_module,
9901
9903
  texture_sheet_animation_module: texture_sheet_animation_module,
9902
9904
  force_over_lifetime_module: force_over_lifetime_module,
9905
+ limit_velocity_over_lifetime_module: limit_velocity_over_lifetime_module,
9906
+ particle_feedback_simulation: particle_feedback_simulation,
9903
9907
  sphere_billboard: sphere_billboard,
9904
9908
  stretched_billboard: stretched_billboard,
9905
9909
  vertical_billboard: vertical_billboard,
@@ -9963,6 +9967,41 @@
9963
9967
  return "#define " + (m.value ? m.name + " " + m.value : m.name) + "\n";
9964
9968
  }).join("");
9965
9969
  };
9970
+ /**
9971
+ * @internal
9972
+ * Compile vertex and fragment source with standard macros, includes, and version header.
9973
+ * @param engine - Engine instance
9974
+ * @param macroCollection - Current macro collection
9975
+ * @param vertexSource - Raw vertex shader source (may contain #include)
9976
+ * @param fragmentSource - Raw fragment shader source
9977
+ * @returns Compiled { vertexSource, fragmentSource } ready for ShaderProgram
9978
+ */ ShaderFactory.compilePlatformSource = function compilePlatformSource(engine, macroCollection, vertexSource, fragmentSource) {
9979
+ var isWebGL2 = engine._hardwareRenderer.isWebGL2;
9980
+ var shaderMacroList = new Array();
9981
+ ShaderMacro._getMacrosElements(macroCollection, shaderMacroList);
9982
+ shaderMacroList.push(ShaderMacro.getByName(isWebGL2 ? "GRAPHICS_API_WEBGL2" : "GRAPHICS_API_WEBGL1"));
9983
+ if (engine._hardwareRenderer.canIUse(GLCapabilityType.shaderTextureLod)) {
9984
+ shaderMacroList.push(ShaderMacro.getByName("HAS_TEX_LOD"));
9985
+ }
9986
+ if (engine._hardwareRenderer.canIUse(GLCapabilityType.standardDerivatives)) {
9987
+ shaderMacroList.push(ShaderMacro.getByName("HAS_DERIVATIVES"));
9988
+ }
9989
+ var noIncludeVertex = ShaderFactory.parseIncludes(vertexSource);
9990
+ var noIncludeFrag = ShaderFactory.parseIncludes(fragmentSource);
9991
+ var macroStr = ShaderFactory.parseCustomMacros(shaderMacroList);
9992
+ noIncludeVertex = macroStr + noIncludeVertex;
9993
+ noIncludeFrag = macroStr + noIncludeFrag;
9994
+ if (isWebGL2) {
9995
+ noIncludeVertex = ShaderFactory.convertTo300(noIncludeVertex);
9996
+ noIncludeFrag = ShaderFactory.convertTo300(noIncludeFrag, true);
9997
+ }
9998
+ var versionStr = isWebGL2 ? "#version 300 es" : "#version 100";
9999
+ 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";
10000
+ return {
10001
+ vertexSource: versionStr + "\nprecision highp float;\n" + noIncludeVertex,
10002
+ fragmentSource: versionStr + "\n" + (isWebGL2 ? "" : ShaderFactory._shaderExtension) + precisionStr + noIncludeFrag
10003
+ };
10004
+ };
9966
10005
  ShaderFactory.registerInclude = function registerInclude(includeName, includeSource) {
9967
10006
  if (ShaderLib[includeName]) {
9968
10007
  throw 'The "' + includeName + '" shader include already exist';
@@ -10290,7 +10329,7 @@
10290
10329
  * Shader program, corresponding to the GPU shader program.
10291
10330
  * @internal
10292
10331
  */ var ShaderProgram = /*#__PURE__*/ function() {
10293
- function ShaderProgram(engine, vertexSource, fragmentSource) {
10332
+ function ShaderProgram(engine, vertexSource, fragmentSource, transformFeedbackVaryings) {
10294
10333
  this.sceneUniformBlock = new ShaderUniformBlock();
10295
10334
  this.cameraUniformBlock = new ShaderUniformBlock();
10296
10335
  this.rendererUniformBlock = new ShaderUniformBlock();
@@ -10306,7 +10345,7 @@
10306
10345
  this._activeTextureUint = 0;
10307
10346
  this._engine = engine;
10308
10347
  this._gl = engine._hardwareRenderer.gl;
10309
- this._glProgram = this._createProgram(vertexSource, fragmentSource);
10348
+ this._glProgram = this._createProgram(vertexSource, fragmentSource, transformFeedbackVaryings);
10310
10349
  if (this._glProgram) {
10311
10350
  this._isValid = true;
10312
10351
  this._recordLocation();
@@ -10452,7 +10491,7 @@
10452
10491
  };
10453
10492
  /**
10454
10493
  * Init and link program with shader.
10455
- */ _proto._createProgram = function _createProgram(vertexSource, fragmentSource) {
10494
+ */ _proto._createProgram = function _createProgram(vertexSource, fragmentSource, transformFeedbackVaryings) {
10456
10495
  var gl = this._gl;
10457
10496
  // Create and compile shader
10458
10497
  var vertexShader = this._createShader(gl.VERTEX_SHADER, vertexSource);
@@ -10470,6 +10509,10 @@
10470
10509
  }
10471
10510
  gl.attachShader(program, vertexShader);
10472
10511
  gl.attachShader(program, fragmentShader);
10512
+ // Set Transform Feedback varyings before linking (WebGL2 only)
10513
+ if (transformFeedbackVaryings == null ? void 0 : transformFeedbackVaryings.length) {
10514
+ gl.transformFeedbackVaryings(program, transformFeedbackVaryings, gl.INTERLEAVED_ATTRIBS);
10515
+ }
10473
10516
  gl.linkProgram(program);
10474
10517
  gl.validateProgram(program);
10475
10518
  gl.deleteShader(vertexShader);
@@ -10732,7 +10775,7 @@
10732
10775
  /**
10733
10776
  * @internal
10734
10777
  */ _proto._getShaderProgram = function _getShaderProgram(engine, macroCollection) {
10735
- var shaderProgramPool = engine._getShaderProgramPool(this);
10778
+ var shaderProgramPool = engine._getShaderProgramPool(this._shaderPassId, this._shaderProgramPools);
10736
10779
  var shaderProgram = shaderProgramPool.get(macroCollection);
10737
10780
  if (shaderProgram) {
10738
10781
  return shaderProgram;
@@ -10754,6 +10797,13 @@
10754
10797
  shaderProgramPools.length = 0;
10755
10798
  };
10756
10799
  _proto._getCanonicalShaderProgram = function _getCanonicalShaderProgram(engine, macroCollection) {
10800
+ if (this._platformTarget != undefined) {
10801
+ return this._getShaderLabProgram(engine, macroCollection);
10802
+ }
10803
+ var _ShaderFactory_compilePlatformSource = ShaderFactory.compilePlatformSource(engine, macroCollection, this._vertexSource, this._fragmentSource), vertexSource = _ShaderFactory_compilePlatformSource.vertexSource, fragmentSource = _ShaderFactory_compilePlatformSource.fragmentSource;
10804
+ return new ShaderProgram(engine, vertexSource, fragmentSource);
10805
+ };
10806
+ _proto._getShaderLabProgram = function _getShaderLabProgram(engine, macroCollection) {
10757
10807
  var isWebGL2 = engine._hardwareRenderer.isWebGL2;
10758
10808
  var shaderMacroList = new Array();
10759
10809
  ShaderMacro._getMacrosElements(macroCollection, shaderMacroList);
@@ -10764,32 +10814,22 @@
10764
10814
  if (engine._hardwareRenderer.canIUse(GLCapabilityType.standardDerivatives)) {
10765
10815
  shaderMacroList.push(ShaderMacro.getByName("HAS_DERIVATIVES"));
10766
10816
  }
10767
- // Compatible with non-shaderlab syntax
10768
10817
  var noIncludeVertex = ShaderFactory.parseIncludes(this._vertexSource);
10769
10818
  var noIncludeFrag = ShaderFactory.parseIncludes(this._fragmentSource);
10770
- // Parse macros when use shaderlab
10771
- if (this._platformTarget != undefined) {
10772
- noIncludeVertex = Shader._shaderLab._parseMacros(noIncludeVertex, shaderMacroList);
10773
- noIncludeFrag = Shader._shaderLab._parseMacros(noIncludeFrag, shaderMacroList);
10774
- } else {
10775
- var macroNameStr = ShaderFactory.parseCustomMacros(shaderMacroList);
10776
- noIncludeVertex = macroNameStr + noIncludeVertex;
10777
- noIncludeFrag = macroNameStr + noIncludeFrag;
10778
- }
10779
- // Need to convert to 300 es when the target is GLSL ES 100 or unkdown
10780
- if (isWebGL2 && (this._platformTarget == undefined || this._platformTarget === ShaderLanguage.GLSLES100)) {
10819
+ noIncludeVertex = Shader._shaderLab._parseMacros(noIncludeVertex, shaderMacroList);
10820
+ noIncludeFrag = Shader._shaderLab._parseMacros(noIncludeFrag, shaderMacroList);
10821
+ if (isWebGL2 && this._platformTarget === ShaderLanguage.GLSLES100) {
10781
10822
  noIncludeVertex = ShaderFactory.convertTo300(noIncludeVertex);
10782
10823
  noIncludeFrag = ShaderFactory.convertTo300(noIncludeFrag, true);
10783
10824
  }
10784
10825
  var versionStr = isWebGL2 ? "#version 300 es" : "#version 100";
10785
- var vertexSource = " " + versionStr + " \n " + noIncludeVertex + "\n ";
10826
+ var vertexSource = " " + versionStr + "\n " + noIncludeVertex + "\n ";
10786
10827
  var fragmentSource = " " + versionStr + "\n " + (isWebGL2 ? "" : ShaderFactory._shaderExtension) + "\n " + precisionStr + "\n " + noIncludeFrag + "\n ";
10787
- var shaderProgram = new ShaderProgram(engine, vertexSource, fragmentSource);
10788
- return shaderProgram;
10828
+ return new ShaderProgram(engine, vertexSource, fragmentSource);
10789
10829
  };
10790
10830
  return ShaderPass;
10791
10831
  }(ShaderPart);
10792
- ShaderPass._shaderPassCounter = 0;
10832
+ /** @internal */ ShaderPass._shaderPassCounter = 0;
10793
10833
  /** @internal */ ShaderPass._shaderRootPath = "shaders://root/";
10794
10834
  /**
10795
10835
  * Sub shader.
@@ -23304,6 +23344,15 @@
23304
23344
  this._platformBuffer.getData(data, bufferByteOffset, dataOffset, dataLength);
23305
23345
  };
23306
23346
  /**
23347
+ * Copy data from another buffer on the GPU.
23348
+ * @param srcBuffer - Source buffer
23349
+ * @param srcByteOffset - Byte offset in the source buffer
23350
+ * @param dstByteOffset - Byte offset in this buffer
23351
+ * @param byteLength - Number of bytes to copy
23352
+ */ _proto.copyFromBuffer = function copyFromBuffer(srcBuffer, srcByteOffset, dstByteOffset, byteLength) {
23353
+ this._platformBuffer.copyFromBuffer(srcBuffer._platformBuffer, srcByteOffset, dstByteOffset, byteLength);
23354
+ };
23355
+ /**
23307
23356
  * Mark buffer as readable, the `data` property will be not accessible anymore.
23308
23357
  */ _proto.markAsUnreadable = function markAsUnreadable() {
23309
23358
  this._data = null;
@@ -23593,8 +23642,8 @@
23593
23642
  /**
23594
23643
  * Buffer binding flag.
23595
23644
  */ var BufferBindFlag = /*#__PURE__*/ function(BufferBindFlag) {
23596
- /** Vertex buffer binding flag */ BufferBindFlag[BufferBindFlag["VertexBuffer"] = 0] = "VertexBuffer";
23597
- /** Index buffer binding flag */ BufferBindFlag[BufferBindFlag["IndexBuffer"] = 1] = "IndexBuffer";
23645
+ /** Vertex buffer binding flag. */ BufferBindFlag[BufferBindFlag["VertexBuffer"] = 0] = "VertexBuffer";
23646
+ /** Index buffer binding flag. */ BufferBindFlag[BufferBindFlag["IndexBuffer"] = 1] = "IndexBuffer";
23598
23647
  return BufferBindFlag;
23599
23648
  }({});
23600
23649
  /**
@@ -30966,6 +31015,14 @@
30966
31015
  ParticleBillboardVertexAttribute["cornerTextureCoordinate"] = "a_CornerTextureCoordinate";
30967
31016
  return ParticleBillboardVertexAttribute;
30968
31017
  }({});
31018
+ /**
31019
+ * @internal
31020
+ * Vertex attributes for the Transform Feedback buffer.
31021
+ */ var ParticleFeedbackVertexAttribute = /*#__PURE__*/ function(ParticleFeedbackVertexAttribute) {
31022
+ ParticleFeedbackVertexAttribute["Position"] = "a_FeedbackPosition";
31023
+ ParticleFeedbackVertexAttribute["Velocity"] = "a_FeedbackVelocity";
31024
+ return ParticleFeedbackVertexAttribute;
31025
+ }({});
30969
31026
  /**
30970
31027
  * @internal
30971
31028
  */ var ParticleInstanceVertexAttribute = /*#__PURE__*/ function(ParticleInstanceVertexAttribute) {
@@ -31058,6 +31115,22 @@
31058
31115
  return _class;
31059
31116
  }(ContentRestorer))());
31060
31117
  };
31118
+ ParticleBufferUtils.feedbackVertexStride = 24;
31119
+ ParticleBufferUtils.feedbackVertexElements = [
31120
+ new VertexElement(ParticleFeedbackVertexAttribute.Position, 0, VertexElementFormat.Vector3, 0),
31121
+ new VertexElement(ParticleFeedbackVertexAttribute.Velocity, 12, VertexElementFormat.Vector3, 0)
31122
+ ];
31123
+ ParticleBufferUtils.feedbackInstanceElements = [
31124
+ new VertexElement(ParticleInstanceVertexAttribute.ShapePositionStartLifeTime, 0, VertexElementFormat.Vector4, 0),
31125
+ new VertexElement(ParticleInstanceVertexAttribute.DirectionTime, 16, VertexElementFormat.Vector4, 0),
31126
+ new VertexElement(ParticleInstanceVertexAttribute.StartSize, 48, VertexElementFormat.Vector3, 0),
31127
+ new VertexElement(ParticleInstanceVertexAttribute.StartSpeed, 72, VertexElementFormat.Float, 0),
31128
+ new VertexElement(ParticleInstanceVertexAttribute.Random0, 76, VertexElementFormat.Vector4, 0),
31129
+ new VertexElement(ParticleInstanceVertexAttribute.Random1, 92, VertexElementFormat.Vector4, 0),
31130
+ new VertexElement(ParticleInstanceVertexAttribute.SimulationWorldPosition, 108, VertexElementFormat.Vector3, 0),
31131
+ new VertexElement(ParticleInstanceVertexAttribute.SimulationWorldRotation, 120, VertexElementFormat.Vector4, 0),
31132
+ new VertexElement(ParticleInstanceVertexAttribute.Random2, 152, VertexElementFormat.Vector4, 0)
31133
+ ];
31061
31134
  ParticleBufferUtils.instanceVertexStride = 168;
31062
31135
  ParticleBufferUtils.instanceVertexFloatStride = ParticleBufferUtils.instanceVertexStride / 4;
31063
31136
  ParticleBufferUtils.startLifeTimeOffset = 3;
@@ -31078,7 +31151,7 @@
31078
31151
  var depthOnlyFs = "void main() {\n}"; // eslint-disable-line
31079
31152
  var depthOnlyVs = "#define MATERIAL_OMIT_NORMAL\n#include <common>\n#include <common_vert>\n#include <blendShape_input>\nuniform mat4 camera_VPMat;\n\n\nvoid main() {\n\n #include <begin_position_vert>\n #include <blendShape_vert>\n #include <skinning_vert>\n #include <position_vert>\n\n}\n"; // eslint-disable-line
31080
31153
  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
31081
- 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
31154
+ 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
31082
31155
  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
31083
31156
  var pbrFs = "#include <common>\n#include <camera_declare>\n#include <transform_declare>\n\n#include <FogFragmentDeclaration>\n#include <PositionClipSpaceDeclaration>\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#include <pbr_frag_define>\n#include <pbr_helper>\n\nvoid main() {\n #include <pbr_frag>\n #include <FogFragment>\n}\n"; // eslint-disable-line
31084
31157
  var pbrVs = "#include <common>\n#include <common_vert>\n#include <blendShape_input>\n#include <uv_share>\n#include <color_share>\n#include <normal_share>\n#include <worldpos_share>\n\n#include <ShadowVertexDeclaration>\n#include <FogVertexDeclaration>\n#include <PositionClipSpaceDeclaration>\n\nvoid main() {\n\n #include <begin_position_vert>\n #include <begin_normal_vert>\n #include <blendShape_vert>\n #include <skinning_vert>\n #include <uv_vert>\n #include <color_vert>\n #include <normal_vert>\n #include <worldpos_vert>\n #include <position_vert>\n\n #include <ShadowVertex>\n #include <FogVertex>\n #include <PositionClipSpaceVertex>\n}\n"; // eslint-disable-line
@@ -31096,12 +31169,45 @@
31096
31169
  var trailVs = "attribute vec4 a_PositionBirthTime; // xyz: World position, w: Birth time (used by CPU only)\nattribute vec4 a_CornerTangent; // x: Corner (-1 or 1), yzw: Tangent direction\nattribute float a_Distance; // Absolute cumulative distance (written once per point)\n\nuniform vec4 renderer_TrailParams; // x: TextureMode (0: Stretch, 1: Tile), y: TextureScaleX, z: TextureScaleY\nuniform vec2 renderer_DistanceParams; // x: HeadDistance, y: TailDistance\nuniform vec3 camera_Position;\nuniform mat4 camera_ViewMat;\nuniform mat4 camera_ProjMat;\nuniform vec2 renderer_WidthCurve[4]; // Width curve (4 keyframes max: x=time, y=value)\nuniform vec4 renderer_ColorKeys[4]; // Color gradient (x=time, yzw=rgb)\nuniform vec2 renderer_AlphaKeys[4]; // Alpha gradient (x=time, y=alpha)\nuniform vec4 renderer_CurveMaxTime; // x: colorMaxTime, y: alphaMaxTime, z: widthMaxTime\n\nvarying vec2 v_uv;\nvarying vec4 v_color;\n\n#include <particle_common>\n\nvoid main() {\n vec3 position = a_PositionBirthTime.xyz;\n float corner = a_CornerTangent.x;\n vec3 tangent = a_CornerTangent.yzw;\n\n // Distance-based relative position: 0=head(newest), 1=tail(oldest)\n float distFromHead = renderer_DistanceParams.x - a_Distance;\n float totalDist = renderer_DistanceParams.x - renderer_DistanceParams.y;\n float relativePos = totalDist > 0.0 ? distFromHead / totalDist : 0.0;\n\n // Billboard: expand perpendicular to tangent and view direction\n vec3 toCamera = normalize(camera_Position - position);\n vec3 right = cross(tangent, toCamera);\n float rightLenSq = dot(right, right);\n if (rightLenSq < 0.000001) {\n right = cross(tangent, vec3(0.0, 1.0, 0.0));\n rightLenSq = dot(right, right);\n if (rightLenSq < 0.000001) {\n right = cross(tangent, vec3(1.0, 0.0, 0.0));\n rightLenSq = dot(right, right);\n }\n }\n right = right * inversesqrt(rightLenSq);\n\n float width = evaluateParticleCurve(renderer_WidthCurve, min(relativePos, renderer_CurveMaxTime.z));\n vec3 worldPosition = position + right * width * 0.5 * corner;\n\n gl_Position = camera_ProjMat * camera_ViewMat * vec4(worldPosition, 1.0);\n\n // u = position along trail (affected by textureMode), v = corner side.\n float u = renderer_TrailParams.x == 0.0 ? relativePos : distFromHead;\n float v = corner * 0.5 + 0.5;\n v_uv = vec2(u * renderer_TrailParams.y, v * renderer_TrailParams.z);\n\n v_color = evaluateParticleGradient(renderer_ColorKeys, renderer_CurveMaxTime.x, renderer_AlphaKeys, renderer_CurveMaxTime.y, relativePos);\n}\n"; // eslint-disable-line
31097
31170
  var unlitFs = "#include <common>\n#include <uv_share>\n#include <FogFragmentDeclaration>\n\nuniform vec4 material_BaseColor;\nuniform float material_AlphaCutoff;\n\n#ifdef MATERIAL_HAS_BASETEXTURE\n uniform sampler2D material_BaseTexture;\n#endif\n\nvoid main() {\n vec4 baseColor = material_BaseColor;\n\n #ifdef MATERIAL_HAS_BASETEXTURE\n baseColor *= texture2DSRGB(material_BaseTexture, v_uv);\n #endif\n\n #ifdef MATERIAL_IS_ALPHA_CUTOFF\n if( baseColor.a < material_AlphaCutoff ) {\n discard;\n }\n #endif\n\n gl_FragColor = baseColor;\n\n #ifndef MATERIAL_IS_TRANSPARENT\n gl_FragColor.a = 1.0;\n #endif\n\n #include <FogFragment>\n}\n"; // eslint-disable-line
31098
31171
  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
31172
+ /**
31173
+ * @internal
31174
+ * Shared shader definition for Transform Feedback simulation.
31175
+ * Multiple simulators using the same shader share a single program pool per engine.
31176
+ */ var TransformFeedbackShader = /*#__PURE__*/ function() {
31177
+ function TransformFeedbackShader(vertexSource, fragmentSource, feedbackVaryings) {
31178
+ this._id = ShaderPass._shaderPassCounter++;
31179
+ this.vertexSource = vertexSource;
31180
+ this.fragmentSource = fragmentSource;
31181
+ this.feedbackVaryings = feedbackVaryings;
31182
+ }
31183
+ var _proto = TransformFeedbackShader.prototype;
31184
+ /**
31185
+ * Get or compile a shader program for the given engine and macro combination.
31186
+ */ _proto.getProgram = function getProgram(engine, macroCollection) {
31187
+ var pool = engine._getShaderProgramPool(this._id);
31188
+ var program = pool.get(macroCollection);
31189
+ if (program) return program;
31190
+ var _ShaderFactory_compilePlatformSource = ShaderFactory.compilePlatformSource(engine, macroCollection, this.vertexSource, this.fragmentSource), vertexSource = _ShaderFactory_compilePlatformSource.vertexSource, fragmentSource = _ShaderFactory_compilePlatformSource.fragmentSource;
31191
+ program = new ShaderProgram(engine, vertexSource, fragmentSource, this.feedbackVaryings);
31192
+ if (!program.isValid) {
31193
+ Logger.error("TransformFeedbackShader: Failed to compile shader program.");
31194
+ return null;
31195
+ }
31196
+ pool.cache(program);
31197
+ return program;
31198
+ };
31199
+ return TransformFeedbackShader;
31200
+ }();
31099
31201
  /**
31100
31202
  * Internal shader pool.
31101
31203
  * @internal
31102
31204
  */ var ShaderPool = /*#__PURE__*/ function() {
31103
31205
  function ShaderPool() {}
31104
31206
  ShaderPool.init = function init() {
31207
+ ShaderPool.particleFeedbackShader = new TransformFeedbackShader("#include <particle_feedback_simulation>", "void main() { discard; }", [
31208
+ "v_FeedbackPosition",
31209
+ "v_FeedbackVelocity"
31210
+ ]);
31105
31211
  var shadowCasterPass = new ShaderPass("ShadowCaster", shadowMapVs, shadowMapFs, {
31106
31212
  pipelineStage: PipelineStage.ShadowCaster
31107
31213
  });
@@ -31592,8 +31698,7 @@
31592
31698
  };
31593
31699
  /**
31594
31700
  * @internal
31595
- */ _proto._getShaderProgramPool = function _getShaderProgramPool(shaderPass) {
31596
- var index = shaderPass._shaderPassId;
31701
+ */ _proto._getShaderProgramPool = function _getShaderProgramPool(index, trackPools) {
31597
31702
  var shaderProgramPools = this._shaderProgramPools;
31598
31703
  var pool = shaderProgramPools[index];
31599
31704
  if (!pool) {
@@ -31602,7 +31707,7 @@
31602
31707
  shaderProgramPools.length = length;
31603
31708
  }
31604
31709
  shaderProgramPools[index] = pool = new ShaderProgramPool(this);
31605
- shaderPass._shaderProgramPools.push(pool);
31710
+ trackPools == null ? void 0 : trackPools.push(pool);
31606
31711
  }
31607
31712
  return pool;
31608
31713
  };
@@ -33476,24 +33581,24 @@
33476
33581
  Scene._fogColorProperty = ShaderProperty.getByName("scene_FogColor");
33477
33582
  Scene._fogParamsProperty = ShaderProperty.getByName("scene_FogParams");
33478
33583
  Scene._prefilterdDFGProperty = ShaderProperty.getByName("scene_PrefilteredDFG");
33479
- function _array_like_to_array$1(arr, len) {
33584
+ function _array_like_to_array$2(arr, len) {
33480
33585
  if (len == null || len > arr.length) len = arr.length;
33481
33586
  for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
33482
33587
  return arr2;
33483
33588
  }
33484
- function _unsupported_iterable_to_array$1(o, minLen) {
33589
+ function _unsupported_iterable_to_array$2(o, minLen) {
33485
33590
  if (!o) return;
33486
- if (typeof o === "string") return _array_like_to_array$1(o, minLen);
33591
+ if (typeof o === "string") return _array_like_to_array$2(o, minLen);
33487
33592
  var n = Object.prototype.toString.call(o).slice(8, -1);
33488
33593
  if (n === "Object" && o.constructor) n = o.constructor.name;
33489
33594
  if (n === "Map" || n === "Set") return Array.from(n);
33490
- if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
33595
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
33491
33596
  }
33492
- function _create_for_of_iterator_helper_loose$1(o, allowArrayLike) {
33597
+ function _create_for_of_iterator_helper_loose$2(o, allowArrayLike) {
33493
33598
  var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
33494
33599
  if (it) return (it = it.call(o)).next.bind(it);
33495
33600
  // Fallback for engines without symbol support
33496
- if (Array.isArray(o) || (it = _unsupported_iterable_to_array$1(o)) || allowArrayLike && o && typeof o.length === "number") {
33601
+ if (Array.isArray(o) || (it = _unsupported_iterable_to_array$2(o)) || allowArrayLike && o && typeof o.length === "number") {
33497
33602
  if (it) o = it;
33498
33603
  var i = 0;
33499
33604
  return function() {
@@ -33648,7 +33753,7 @@
33648
33753
  if (this.onPhysicsUpdate !== prototype.onPhysicsUpdate) {
33649
33754
  componentsManager.addOnPhysicsUpdateScript(this);
33650
33755
  }
33651
- for(var _iterator = _create_for_of_iterator_helper_loose$1(Object.values(PointerMethods)), _step; !(_step = _iterator()).done;){
33756
+ for(var _iterator = _create_for_of_iterator_helper_loose$2(Object.values(PointerMethods)), _step; !(_step = _iterator()).done;){
33652
33757
  var pointerMethod = _step.value;
33653
33758
  if (this[pointerMethod] === prototype[pointerMethod]) {
33654
33759
  this[pointerMethod] = null;
@@ -37902,6 +38007,10 @@
37902
38007
  shaderData.setFloat(ParticleRenderer._currentTime, this.generator._playTime);
37903
38008
  shaderData.setVector3(ParticleRenderer._pivotOffsetProperty, this.pivot);
37904
38009
  this.generator._updateShaderData(shaderData);
38010
+ // Run Transform Feedback simulation after shader data is up to date
38011
+ if (generator._useTransformFeedback) {
38012
+ generator._updateFeedback(shaderData, this.engine.time.deltaTime * generator.main.simulationSpeed);
38013
+ }
37905
38014
  };
37906
38015
  _proto._render = function _render(context) {
37907
38016
  var generator = this.generator;
@@ -37910,7 +38019,9 @@
37910
38019
  if (!aliveParticleCount) {
37911
38020
  return;
37912
38021
  }
37913
- generator._primitive.instanceCount = aliveParticleCount;
38022
+ // Transform Feedback: render all slots (instance buffer not compacted, dead particles discarded in shader)
38023
+ // Non-Transform Feedback: render only alive particles (instance buffer compacted)
38024
+ generator._primitive.instanceCount = generator._useTransformFeedback ? generator._firstActiveElement <= generator._firstFreeElement ? generator._firstFreeElement : generator._currentParticleCount : aliveParticleCount;
37914
38025
  var material = this.getMaterial();
37915
38026
  if (!material || this._renderMode === ParticleRenderMode.Mesh && !this._mesh) {
37916
38027
  return;
@@ -38065,6 +38176,327 @@
38065
38176
  /** On Generator Bounds Related Params Changed */ ParticleUpdateFlags[ParticleUpdateFlags["GeneratorVolume"] = 4] = "GeneratorVolume";
38066
38177
  return ParticleUpdateFlags;
38067
38178
  }({});
38179
+ /**
38180
+ * Transform Feedback object for GPU-based data capture.
38181
+ * @internal
38182
+ */ var TransformFeedback = /*#__PURE__*/ function(GraphicsResource) {
38183
+ _inherits$2(TransformFeedback, GraphicsResource);
38184
+ function TransformFeedback(engine) {
38185
+ var _this;
38186
+ _this = GraphicsResource.call(this, engine) || this;
38187
+ _this._platformTransformFeedback = engine._hardwareRenderer.createPlatformTransformFeedback();
38188
+ return _this;
38189
+ }
38190
+ var _proto = TransformFeedback.prototype;
38191
+ /**
38192
+ * Bind this Transform Feedback object as active.
38193
+ */ _proto.bind = function bind() {
38194
+ this._platformTransformFeedback.bind();
38195
+ };
38196
+ /**
38197
+ * Bind a buffer range as output at the given index.
38198
+ * @param index - Output binding point index (corresponds to varying index in shader)
38199
+ * @param buffer - Output buffer to capture data into
38200
+ * @param byteOffset - Starting byte offset in the buffer
38201
+ * @param byteSize - Size in bytes of the capture range
38202
+ */ _proto.bindBufferRange = function bindBufferRange(index, buffer, byteOffset, byteSize) {
38203
+ this._platformTransformFeedback.bindBufferRange(index, buffer._platformBuffer, byteOffset, byteSize);
38204
+ };
38205
+ /**
38206
+ * Begin a Transform Feedback pass.
38207
+ * @param primitiveMode - Primitive topology mode
38208
+ */ _proto.begin = function begin(primitiveMode) {
38209
+ this._platformTransformFeedback.begin(primitiveMode);
38210
+ };
38211
+ /**
38212
+ * End the current Transform Feedback pass.
38213
+ */ _proto.end = function end() {
38214
+ this._platformTransformFeedback.end();
38215
+ };
38216
+ /**
38217
+ * Unbind the output buffer at the given index from the Transform Feedback target.
38218
+ * @param index - Output binding point index
38219
+ */ _proto.unbindBuffer = function unbindBuffer(index) {
38220
+ this._platformTransformFeedback.unbindBuffer(index);
38221
+ };
38222
+ /**
38223
+ * Unbind this Transform Feedback object.
38224
+ */ _proto.unbind = function unbind() {
38225
+ this._platformTransformFeedback.unbind();
38226
+ };
38227
+ _proto._rebuild = function _rebuild() {
38228
+ this._platformTransformFeedback = this._engine._hardwareRenderer.createPlatformTransformFeedback();
38229
+ };
38230
+ _proto._onDestroy = function _onDestroy() {
38231
+ GraphicsResource.prototype._onDestroy.call(this);
38232
+ this._platformTransformFeedback.destroy();
38233
+ };
38234
+ return TransformFeedback;
38235
+ }(GraphicsResource);
38236
+ /**
38237
+ * @internal
38238
+ * Primitive for Transform Feedback simulation with read/write buffer swapping.
38239
+ */ var TransformFeedbackPrimitive = /*#__PURE__*/ function(GraphicsResource) {
38240
+ _inherits$2(TransformFeedbackPrimitive, GraphicsResource);
38241
+ function TransformFeedbackPrimitive(engine, byteStride) {
38242
+ var _this;
38243
+ _this = GraphicsResource.call(this, engine) || this, _this._readIsA = true;
38244
+ _this._byteStride = byteStride;
38245
+ _this._transformFeedback = new TransformFeedback(engine);
38246
+ _this._transformFeedback.isGCIgnored = true;
38247
+ _this._platformPrimitive = engine._hardwareRenderer.createPlatformTransformFeedbackPrimitive();
38248
+ _this.isGCIgnored = true;
38249
+ return _this;
38250
+ }
38251
+ var _proto = TransformFeedbackPrimitive.prototype;
38252
+ /**
38253
+ * Resize read and write buffers.
38254
+ * @param vertexCount - Number of vertices to allocate
38255
+ */ _proto.resize = function resize(vertexCount) {
38256
+ var byteLength = this._byteStride * vertexCount;
38257
+ var bufferA = new Buffer(this._engine, BufferBindFlag.VertexBuffer, byteLength, BufferUsage.Dynamic, false);
38258
+ bufferA.isGCIgnored = true;
38259
+ var bufferB = new Buffer(this._engine, BufferBindFlag.VertexBuffer, byteLength, BufferUsage.Dynamic, false);
38260
+ bufferB.isGCIgnored = true;
38261
+ this._bindingA = new VertexBufferBinding(bufferA, this._byteStride);
38262
+ this._bindingB = new VertexBufferBinding(bufferB, this._byteStride);
38263
+ this._readIsA = true;
38264
+ this._platformPrimitive.invalidate();
38265
+ };
38266
+ /**
38267
+ * Update vertex layout, only rebuilds when program changes.
38268
+ * @param program - Shader program for attribute locations
38269
+ * @param feedbackElements - Vertex elements describing the read/write buffer
38270
+ * @param inputBinding - Additional input buffer binding
38271
+ * @param inputElements - Vertex elements describing the input buffer
38272
+ */ _proto.updateVertexLayout = function updateVertexLayout(program, feedbackElements, inputBinding, inputElements) {
38273
+ this._platformPrimitive.updateVertexLayout(program, this._bindingA, this._bindingB, feedbackElements, inputBinding, inputElements);
38274
+ };
38275
+ /**
38276
+ * Bind state before issuing draw calls.
38277
+ */ _proto.beginDraw = function beginDraw() {
38278
+ this._engine._hardwareRenderer.enableRasterizerDiscard();
38279
+ this._transformFeedback.bind();
38280
+ this._platformPrimitive.bind(this._readIsA);
38281
+ };
38282
+ /**
38283
+ * Issue a draw call for a vertex range, capturing output to the write buffer.
38284
+ * @param mode - Primitive topology
38285
+ * @param first - First vertex index
38286
+ * @param count - Number of vertices
38287
+ */ _proto.draw = function draw(mode, first, count) {
38288
+ var transformFeedback = this._transformFeedback;
38289
+ transformFeedback.bindBufferRange(0, this.writeBinding.buffer, first * this._byteStride, count * this._byteStride);
38290
+ transformFeedback.begin(mode);
38291
+ this._platformPrimitive.draw(mode, first, count);
38292
+ transformFeedback.end();
38293
+ };
38294
+ /**
38295
+ * Unbind state after draw calls.
38296
+ */ _proto.endDraw = function endDraw() {
38297
+ this._platformPrimitive.unbind();
38298
+ this._transformFeedback.unbindBuffer(0);
38299
+ this._transformFeedback.unbind();
38300
+ this._engine._hardwareRenderer.disableRasterizerDiscard();
38301
+ this._engine._hardwareRenderer.invalidateShaderProgramState();
38302
+ };
38303
+ /**
38304
+ * Swap read and write buffers.
38305
+ */ _proto.swap = function swap() {
38306
+ this._readIsA = !this._readIsA;
38307
+ };
38308
+ _proto._rebuild = function _rebuild() {
38309
+ this._platformPrimitive = this._engine._hardwareRenderer.createPlatformTransformFeedbackPrimitive();
38310
+ };
38311
+ _proto._onDestroy = function _onDestroy() {
38312
+ var _this__platformPrimitive, _this__bindingA, _this__bindingB, _this__transformFeedback;
38313
+ GraphicsResource.prototype._onDestroy.call(this);
38314
+ (_this__platformPrimitive = this._platformPrimitive) == null ? void 0 : _this__platformPrimitive.destroy();
38315
+ (_this__bindingA = this._bindingA) == null ? void 0 : _this__bindingA.buffer.destroy();
38316
+ (_this__bindingB = this._bindingB) == null ? void 0 : _this__bindingB.buffer.destroy();
38317
+ (_this__transformFeedback = this._transformFeedback) == null ? void 0 : _this__transformFeedback.destroy();
38318
+ };
38319
+ _create_class$2(TransformFeedbackPrimitive, [
38320
+ {
38321
+ key: "readBinding",
38322
+ get: /**
38323
+ * The current read buffer binding.
38324
+ */ function get() {
38325
+ return this._readIsA ? this._bindingA : this._bindingB;
38326
+ }
38327
+ },
38328
+ {
38329
+ key: "writeBinding",
38330
+ get: /**
38331
+ * The current write buffer binding.
38332
+ */ function get() {
38333
+ return this._readIsA ? this._bindingB : this._bindingA;
38334
+ }
38335
+ }
38336
+ ]);
38337
+ return TransformFeedbackPrimitive;
38338
+ }(GraphicsResource);
38339
+ /**
38340
+ * @internal
38341
+ * General-purpose Transform Feedback simulator.
38342
+ * Manages per-frame simulation with shared shader program caching.
38343
+ */ var TransformFeedbackSimulator = /*#__PURE__*/ function() {
38344
+ function TransformFeedbackSimulator(engine, byteStride, shader) {
38345
+ this._engine = engine;
38346
+ this._primitive = new TransformFeedbackPrimitive(engine, byteStride);
38347
+ this._shader = shader;
38348
+ }
38349
+ var _proto = TransformFeedbackSimulator.prototype;
38350
+ /**
38351
+ * Resize feedback buffers.
38352
+ * @param vertexCount - Number of vertices to allocate
38353
+ */ _proto.resize = function resize(vertexCount) {
38354
+ this._primitive.resize(vertexCount);
38355
+ };
38356
+ /**
38357
+ * Begin a simulation step: get/compile program, bind, upload uniforms, update layout.
38358
+ * @param shaderData - Shader data with current macros and uniforms
38359
+ * @param feedbackElements - Vertex elements for the feedback buffer
38360
+ * @param inputBinding - Input buffer binding
38361
+ * @param inputElements - Vertex elements for the input buffer
38362
+ */ _proto.beginUpdate = function beginUpdate(shaderData, feedbackElements, inputBinding, inputElements) {
38363
+ var program = this._shader.getProgram(this._engine, shaderData._macroCollection);
38364
+ if (!program) return false;
38365
+ program.bind();
38366
+ program.uploadUniforms(program.rendererUniformBlock, shaderData);
38367
+ program.uploadUniforms(program.otherUniformBlock, shaderData);
38368
+ this._primitive.updateVertexLayout(program, feedbackElements, inputBinding, inputElements);
38369
+ this._primitive.beginDraw();
38370
+ return true;
38371
+ };
38372
+ /**
38373
+ * Issue a draw call for a vertex range.
38374
+ * @param mode - Primitive topology
38375
+ * @param first - First vertex index
38376
+ * @param count - Number of vertices
38377
+ */ _proto.draw = function draw(mode, first, count) {
38378
+ this._primitive.draw(mode, first, count);
38379
+ };
38380
+ /**
38381
+ * End the simulation step: unbind state and swap buffers.
38382
+ */ _proto.endUpdate = function endUpdate() {
38383
+ this._primitive.endDraw();
38384
+ this._primitive.swap();
38385
+ };
38386
+ _proto.destroy = function destroy() {
38387
+ var _this__primitive;
38388
+ (_this__primitive = this._primitive) == null ? void 0 : _this__primitive.destroy();
38389
+ };
38390
+ _create_class$2(TransformFeedbackSimulator, [
38391
+ {
38392
+ key: "readBinding",
38393
+ get: /**
38394
+ * The current read buffer binding.
38395
+ */ function get() {
38396
+ return this._primitive.readBinding;
38397
+ }
38398
+ },
38399
+ {
38400
+ key: "writeBinding",
38401
+ get: /**
38402
+ * The current write buffer binding.
38403
+ */ function get() {
38404
+ return this._primitive.writeBinding;
38405
+ }
38406
+ }
38407
+ ]);
38408
+ return TransformFeedbackSimulator;
38409
+ }();
38410
+ /**
38411
+ * @internal
38412
+ * Particle-specific Transform Feedback simulation.
38413
+ */ var ParticleTransformFeedbackSimulator = /*#__PURE__*/ function() {
38414
+ function ParticleTransformFeedbackSimulator(engine) {
38415
+ this._particleInitData = new Float32Array(6);
38416
+ this._simulator = new TransformFeedbackSimulator(engine, ParticleBufferUtils.feedbackVertexStride, ShaderPool.particleFeedbackShader);
38417
+ }
38418
+ var _proto = ParticleTransformFeedbackSimulator.prototype;
38419
+ /**
38420
+ * Resize feedback buffers.
38421
+ * Saves pre-resize buffers internally for subsequent `copyOldBufferData` / `destroyOldBuffers` calls.
38422
+ * @param particleCount - Number of particles to allocate
38423
+ * @param instanceBinding - New instance vertex buffer binding
38424
+ */ _proto.resize = function resize(particleCount, instanceBinding) {
38425
+ var _this__simulator_readBinding, _this__simulator_writeBinding;
38426
+ this._oldReadBuffer = (_this__simulator_readBinding = this._simulator.readBinding) == null ? void 0 : _this__simulator_readBinding.buffer;
38427
+ this._oldWriteBuffer = (_this__simulator_writeBinding = this._simulator.writeBinding) == null ? void 0 : _this__simulator_writeBinding.buffer;
38428
+ this._simulator.resize(particleCount);
38429
+ this._instanceBinding = instanceBinding;
38430
+ };
38431
+ /**
38432
+ * Write initial position and velocity for a newly emitted particle.
38433
+ */ _proto.writeParticleData = function writeParticleData(index, position, vx, vy, vz) {
38434
+ var data = this._particleInitData;
38435
+ data[0] = position.x;
38436
+ data[1] = position.y;
38437
+ data[2] = position.z;
38438
+ data[3] = vx;
38439
+ data[4] = vy;
38440
+ data[5] = vz;
38441
+ var simulator = this._simulator;
38442
+ var byteOffset = index * ParticleBufferUtils.feedbackVertexStride;
38443
+ simulator.readBinding.buffer.setData(data, byteOffset);
38444
+ simulator.writeBinding.buffer.setData(data, byteOffset);
38445
+ };
38446
+ /**
38447
+ * Copy data from pre-resize buffers to current buffers.
38448
+ * Must be called after `resize` which saves the old buffers.
38449
+ */ _proto.copyOldBufferData = function copyOldBufferData(srcByteOffset, dstByteOffset, byteLength) {
38450
+ this._simulator.readBinding.buffer.copyFromBuffer(this._oldReadBuffer, srcByteOffset, dstByteOffset, byteLength);
38451
+ this._simulator.writeBinding.buffer.copyFromBuffer(this._oldWriteBuffer, srcByteOffset, dstByteOffset, byteLength);
38452
+ };
38453
+ /**
38454
+ * Destroy pre-resize buffers saved during `resize`.
38455
+ */ _proto.destroyOldBuffers = function destroyOldBuffers() {
38456
+ var _this__oldReadBuffer, _this__oldWriteBuffer;
38457
+ (_this__oldReadBuffer = this._oldReadBuffer) == null ? void 0 : _this__oldReadBuffer.destroy();
38458
+ (_this__oldWriteBuffer = this._oldWriteBuffer) == null ? void 0 : _this__oldWriteBuffer.destroy();
38459
+ this._oldReadBuffer = null;
38460
+ this._oldWriteBuffer = null;
38461
+ };
38462
+ /**
38463
+ * Run one simulation step.
38464
+ * @param shaderData - Shader data with current macros and uniforms
38465
+ * @param particleCount - Total particle slot count
38466
+ * @param firstActive - First active particle index in ring buffer
38467
+ * @param firstFree - First free particle index in ring buffer
38468
+ * @param deltaTime - Frame delta time
38469
+ */ _proto.update = function update(shaderData, particleCount, firstActive, firstFree, deltaTime) {
38470
+ if (firstActive === firstFree) return;
38471
+ shaderData.setFloat(ParticleTransformFeedbackSimulator._deltaTimeProperty, deltaTime);
38472
+ if (!this._simulator.beginUpdate(shaderData, ParticleBufferUtils.feedbackVertexElements, this._instanceBinding, ParticleBufferUtils.feedbackInstanceElements)) return;
38473
+ if (firstActive < firstFree) {
38474
+ this._simulator.draw(MeshTopology.Points, firstActive, firstFree - firstActive);
38475
+ } else {
38476
+ this._simulator.draw(MeshTopology.Points, firstActive, particleCount - firstActive);
38477
+ if (firstFree > 0) {
38478
+ this._simulator.draw(MeshTopology.Points, 0, firstFree);
38479
+ }
38480
+ }
38481
+ this._simulator.endUpdate();
38482
+ };
38483
+ _proto.destroy = function destroy() {
38484
+ var _this__simulator;
38485
+ (_this__simulator = this._simulator) == null ? void 0 : _this__simulator.destroy();
38486
+ };
38487
+ _create_class$2(ParticleTransformFeedbackSimulator, [
38488
+ {
38489
+ key: "readBinding",
38490
+ get: /**
38491
+ * The current read buffer binding for the render pass.
38492
+ */ function get() {
38493
+ return this._simulator.readBinding;
38494
+ }
38495
+ }
38496
+ ]);
38497
+ return ParticleTransformFeedbackSimulator;
38498
+ }();
38499
+ ParticleTransformFeedbackSimulator._deltaTimeProperty = ShaderProperty.getByName("renderer_DeltaTime");
38068
38500
  /**
38069
38501
  * Particle curve mode.
38070
38502
  */ var ParticleCurveMode = /*#__PURE__*/ function(ParticleCurveMode) {
@@ -38102,6 +38534,7 @@
38102
38534
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["Shape"] = 2941263940] = "Shape";
38103
38535
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["GravityModifier"] = 2759560269] = "GravityModifier";
38104
38536
  ParticleRandomSubSeeds[ParticleRandomSubSeeds["ForceOverLifetime"] = 3875246972] = "ForceOverLifetime";
38537
+ ParticleRandomSubSeeds[ParticleRandomSubSeeds["LimitVelocityOverLifetime"] = 3047300990] = "LimitVelocityOverLifetime";
38105
38538
  return ParticleRandomSubSeeds;
38106
38539
  }({});
38107
38540
  /**
@@ -39151,6 +39584,413 @@
39151
39584
  __decorate$1([
39152
39585
  deepClone
39153
39586
  ], ForceOverLifetimeModule.prototype, "_forceZ", void 0);
39587
+ /**
39588
+ * Limit velocity over lifetime module.
39589
+ */ var LimitVelocityOverLifetimeModule = /*#__PURE__*/ function(ParticleGeneratorModule) {
39590
+ _inherits$2(LimitVelocityOverLifetimeModule, ParticleGeneratorModule);
39591
+ function LimitVelocityOverLifetimeModule(generator) {
39592
+ var _this;
39593
+ _this = ParticleGeneratorModule.call(this, generator) || this, /** @internal */ _this._limitRand = new Rand(0, ParticleRandomSubSeeds.LimitVelocityOverLifetime), _this._limitMinConstantVec = new Vector3(), _this._limitMaxConstantVec = new Vector3(), _this._dragConstantVec = new Vector2(), _this._separateAxes = false, _this._dampen = 1, _this._multiplyDragByParticleSize = false, _this._multiplyDragByParticleVelocity = false, _this._space = ParticleSimulationSpace.Local;
39594
+ _this.limitX = new ParticleCompositeCurve(1);
39595
+ _this.limitY = new ParticleCompositeCurve(1);
39596
+ _this.limitZ = new ParticleCompositeCurve(1);
39597
+ _this.drag = new ParticleCompositeCurve(0);
39598
+ return _this;
39599
+ }
39600
+ var _proto = LimitVelocityOverLifetimeModule.prototype;
39601
+ /**
39602
+ * @internal
39603
+ */ _proto._isDragRandomMode = function _isDragRandomMode() {
39604
+ return this._drag.mode === ParticleCurveMode.TwoConstants || this._drag.mode === ParticleCurveMode.TwoCurves;
39605
+ };
39606
+ /**
39607
+ * @internal
39608
+ */ _proto._isLimitRandomMode = function _isLimitRandomMode() {
39609
+ if (this._separateAxes) {
39610
+ return (this._limitX.mode === ParticleCurveMode.TwoConstants || this._limitX.mode === ParticleCurveMode.TwoCurves) && (this._limitY.mode === ParticleCurveMode.TwoConstants || this._limitY.mode === ParticleCurveMode.TwoCurves) && (this._limitZ.mode === ParticleCurveMode.TwoConstants || this._limitZ.mode === ParticleCurveMode.TwoCurves);
39611
+ }
39612
+ return this._limitX.mode === ParticleCurveMode.TwoConstants || this._limitX.mode === ParticleCurveMode.TwoCurves;
39613
+ };
39614
+ /**
39615
+ * @internal
39616
+ */ _proto._updateShaderData = function _updateShaderData(shaderData) {
39617
+ var enabledModuleMacro = null;
39618
+ var separateAxesMacro = null;
39619
+ var limitModeMacro = null;
39620
+ var limitRandomMacro = null;
39621
+ var dragCurveMacro = null;
39622
+ var dragRandomMacro = null;
39623
+ var dragSizeMacro = null;
39624
+ var dragVelocityMacro = null;
39625
+ if (this.enabled) {
39626
+ enabledModuleMacro = LimitVelocityOverLifetimeModule._enabledMacro;
39627
+ // Dampen
39628
+ shaderData.setFloat(LimitVelocityOverLifetimeModule._dampenProperty, this._dampen);
39629
+ // Space
39630
+ shaderData.setInt(LimitVelocityOverLifetimeModule._spaceProperty, this._space);
39631
+ // Limit
39632
+ if (this._separateAxes) {
39633
+ separateAxesMacro = LimitVelocityOverLifetimeModule._separateAxesMacro;
39634
+ var result = this._uploadSeparateAxisLimits(shaderData);
39635
+ limitModeMacro = result.modeMacro;
39636
+ limitRandomMacro = result.randomMacro;
39637
+ } else {
39638
+ var result1 = this._uploadScalarLimit(shaderData);
39639
+ limitModeMacro = result1.modeMacro;
39640
+ limitRandomMacro = result1.randomMacro;
39641
+ }
39642
+ // Drag
39643
+ var dragResult = this._uploadDrag(shaderData);
39644
+ dragCurveMacro = dragResult.curveMacro;
39645
+ dragRandomMacro = dragResult.randomMacro;
39646
+ // Drag modifiers
39647
+ if (this._multiplyDragByParticleSize) {
39648
+ dragSizeMacro = LimitVelocityOverLifetimeModule._multiplyDragBySizeMacro;
39649
+ }
39650
+ if (this._multiplyDragByParticleVelocity) {
39651
+ dragVelocityMacro = LimitVelocityOverLifetimeModule._multiplyDragByVelocityMacro;
39652
+ }
39653
+ }
39654
+ this._enabledModuleMacro = this._enableMacro(shaderData, this._enabledModuleMacro, enabledModuleMacro);
39655
+ this._separateAxesCachedMacro = this._enableMacro(shaderData, this._separateAxesCachedMacro, separateAxesMacro);
39656
+ this._limitModeMacro = this._enableMacro(shaderData, this._limitModeMacro, limitModeMacro);
39657
+ this._limitRandomMacro = this._enableMacro(shaderData, this._limitRandomMacro, limitRandomMacro);
39658
+ this._dragCurveCachedMacro = this._enableMacro(shaderData, this._dragCurveCachedMacro, dragCurveMacro);
39659
+ this._dragRandomCachedMacro = this._enableMacro(shaderData, this._dragRandomCachedMacro, dragRandomMacro);
39660
+ this._dragSizeMacro = this._enableMacro(shaderData, this._dragSizeMacro, dragSizeMacro);
39661
+ this._dragVelocityMacro = this._enableMacro(shaderData, this._dragVelocityMacro, dragVelocityMacro);
39662
+ };
39663
+ /**
39664
+ * @internal
39665
+ */ _proto._resetRandomSeed = function _resetRandomSeed(seed) {
39666
+ this._limitRand.reset(seed, ParticleRandomSubSeeds.LimitVelocityOverLifetime);
39667
+ };
39668
+ _proto._uploadScalarLimit = function _uploadScalarLimit(shaderData) {
39669
+ var limitX = this._limitX;
39670
+ var modeMacro = null;
39671
+ var randomMacro = null;
39672
+ var isRandomCurveMode = limitX.mode === ParticleCurveMode.TwoCurves;
39673
+ if (isRandomCurveMode || limitX.mode === ParticleCurveMode.Curve) {
39674
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitMaxCurveProperty, limitX.curveMax._getTypeArray());
39675
+ modeMacro = LimitVelocityOverLifetimeModule._limitCurveModeMacro;
39676
+ if (isRandomCurveMode) {
39677
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitMinCurveProperty, limitX.curveMin._getTypeArray());
39678
+ randomMacro = LimitVelocityOverLifetimeModule._limitIsRandomMacro;
39679
+ }
39680
+ } else {
39681
+ shaderData.setFloat(LimitVelocityOverLifetimeModule._limitMaxConstProperty, limitX.constantMax);
39682
+ modeMacro = LimitVelocityOverLifetimeModule._limitConstantModeMacro;
39683
+ if (limitX.mode === ParticleCurveMode.TwoConstants) {
39684
+ shaderData.setFloat(LimitVelocityOverLifetimeModule._limitMinConstProperty, limitX.constantMin);
39685
+ randomMacro = LimitVelocityOverLifetimeModule._limitIsRandomMacro;
39686
+ }
39687
+ }
39688
+ return {
39689
+ modeMacro: modeMacro,
39690
+ randomMacro: randomMacro
39691
+ };
39692
+ };
39693
+ _proto._uploadSeparateAxisLimits = function _uploadSeparateAxisLimits(shaderData) {
39694
+ var limitX = this._limitX;
39695
+ var limitY = this._limitY;
39696
+ var limitZ = this._limitZ;
39697
+ var modeMacro = null;
39698
+ var randomMacro = null;
39699
+ var isRandomCurveMode = limitX.mode === ParticleCurveMode.TwoCurves && limitY.mode === ParticleCurveMode.TwoCurves && limitZ.mode === ParticleCurveMode.TwoCurves;
39700
+ if (isRandomCurveMode || limitX.mode === ParticleCurveMode.Curve && limitY.mode === ParticleCurveMode.Curve && limitZ.mode === ParticleCurveMode.Curve) {
39701
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitXMaxCurveProperty, limitX.curveMax._getTypeArray());
39702
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitYMaxCurveProperty, limitY.curveMax._getTypeArray());
39703
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitZMaxCurveProperty, limitZ.curveMax._getTypeArray());
39704
+ modeMacro = LimitVelocityOverLifetimeModule._limitCurveModeMacro;
39705
+ if (isRandomCurveMode) {
39706
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitXMinCurveProperty, limitX.curveMin._getTypeArray());
39707
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitYMinCurveProperty, limitY.curveMin._getTypeArray());
39708
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._limitZMinCurveProperty, limitZ.curveMin._getTypeArray());
39709
+ randomMacro = LimitVelocityOverLifetimeModule._limitIsRandomMacro;
39710
+ }
39711
+ } else {
39712
+ var constantMax = this._limitMaxConstantVec;
39713
+ constantMax.set(limitX.constantMax, limitY.constantMax, limitZ.constantMax);
39714
+ shaderData.setVector3(LimitVelocityOverLifetimeModule._limitMaxConstVecProperty, constantMax);
39715
+ modeMacro = LimitVelocityOverLifetimeModule._limitConstantModeMacro;
39716
+ if (limitX.mode === ParticleCurveMode.TwoConstants && limitY.mode === ParticleCurveMode.TwoConstants && limitZ.mode === ParticleCurveMode.TwoConstants) {
39717
+ var constantMin = this._limitMinConstantVec;
39718
+ constantMin.set(limitX.constantMin, limitY.constantMin, limitZ.constantMin);
39719
+ shaderData.setVector3(LimitVelocityOverLifetimeModule._limitMinConstVecProperty, constantMin);
39720
+ randomMacro = LimitVelocityOverLifetimeModule._limitIsRandomMacro;
39721
+ }
39722
+ }
39723
+ return {
39724
+ modeMacro: modeMacro,
39725
+ randomMacro: randomMacro
39726
+ };
39727
+ };
39728
+ _proto._uploadDrag = function _uploadDrag(shaderData) {
39729
+ var drag = this._drag;
39730
+ var curveMacro = null;
39731
+ var randomMacro = null;
39732
+ var isRandomCurveMode = drag.mode === ParticleCurveMode.TwoCurves;
39733
+ if (isRandomCurveMode || drag.mode === ParticleCurveMode.Curve) {
39734
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._dragMaxCurveProperty, drag.curveMax._getTypeArray());
39735
+ curveMacro = LimitVelocityOverLifetimeModule._dragCurveModeMacro;
39736
+ if (isRandomCurveMode) {
39737
+ shaderData.setFloatArray(LimitVelocityOverLifetimeModule._dragMinCurveProperty, drag.curveMin._getTypeArray());
39738
+ randomMacro = LimitVelocityOverLifetimeModule._dragIsRandomMacro;
39739
+ }
39740
+ } else {
39741
+ var dragVec = this._dragConstantVec;
39742
+ if (drag.mode === ParticleCurveMode.TwoConstants) {
39743
+ dragVec.set(drag.constantMin, drag.constantMax);
39744
+ } else {
39745
+ dragVec.set(drag.constantMax, drag.constantMax);
39746
+ }
39747
+ shaderData.setVector2(LimitVelocityOverLifetimeModule._dragConstantProperty, dragVec);
39748
+ }
39749
+ return {
39750
+ curveMacro: curveMacro,
39751
+ randomMacro: randomMacro
39752
+ };
39753
+ };
39754
+ _create_class$2(LimitVelocityOverLifetimeModule, [
39755
+ {
39756
+ key: "separateAxes",
39757
+ get: /**
39758
+ * Whether to limit velocity on each axis separately.
39759
+ */ function get() {
39760
+ return this._separateAxes;
39761
+ },
39762
+ set: function set(value) {
39763
+ if (value !== this._separateAxes) {
39764
+ this._separateAxes = value;
39765
+ this._generator._renderer._onGeneratorParamsChanged();
39766
+ }
39767
+ }
39768
+ },
39769
+ {
39770
+ key: "limit",
39771
+ get: /**
39772
+ * Speed limit when separateAxes is false.
39773
+ */ function get() {
39774
+ return this._limitX;
39775
+ },
39776
+ set: function set(value) {
39777
+ this.limitX = value;
39778
+ }
39779
+ },
39780
+ {
39781
+ key: "limitX",
39782
+ get: /**
39783
+ * Speed limit for the x-axis (or overall limit when separateAxes is false).
39784
+ */ function get() {
39785
+ return this._limitX;
39786
+ },
39787
+ set: function set(value) {
39788
+ var lastValue = this._limitX;
39789
+ if (value !== lastValue) {
39790
+ this._limitX = value;
39791
+ this._onCompositeCurveChange(lastValue, value);
39792
+ }
39793
+ }
39794
+ },
39795
+ {
39796
+ key: "limitY",
39797
+ get: /**
39798
+ * Speed limit for the y-axis.
39799
+ */ function get() {
39800
+ return this._limitY;
39801
+ },
39802
+ set: function set(value) {
39803
+ var lastValue = this._limitY;
39804
+ if (value !== lastValue) {
39805
+ this._limitY = value;
39806
+ this._onCompositeCurveChange(lastValue, value);
39807
+ }
39808
+ }
39809
+ },
39810
+ {
39811
+ key: "limitZ",
39812
+ get: /**
39813
+ * Speed limit for the z-axis.
39814
+ */ function get() {
39815
+ return this._limitZ;
39816
+ },
39817
+ set: function set(value) {
39818
+ var lastValue = this._limitZ;
39819
+ if (value !== lastValue) {
39820
+ this._limitZ = value;
39821
+ this._onCompositeCurveChange(lastValue, value);
39822
+ }
39823
+ }
39824
+ },
39825
+ {
39826
+ key: "dampen",
39827
+ get: /**
39828
+ * Controls how much the velocity is dampened when it exceeds the limit.
39829
+ * @remarks Value is clamped to [0, 1]. 0 means no damping, 1 means full damping.
39830
+ */ function get() {
39831
+ return this._dampen;
39832
+ },
39833
+ set: function set(value) {
39834
+ value = Math.max(0, Math.min(1, value));
39835
+ if (value !== this._dampen) {
39836
+ this._dampen = value;
39837
+ this._generator._renderer._onGeneratorParamsChanged();
39838
+ }
39839
+ }
39840
+ },
39841
+ {
39842
+ key: "drag",
39843
+ get: /**
39844
+ * Controls the amount of drag applied to particle velocities.
39845
+ */ function get() {
39846
+ return this._drag;
39847
+ },
39848
+ set: function set(value) {
39849
+ var lastValue = this._drag;
39850
+ if (value !== lastValue) {
39851
+ this._drag = value;
39852
+ this._onCompositeCurveChange(lastValue, value);
39853
+ }
39854
+ }
39855
+ },
39856
+ {
39857
+ key: "multiplyDragByParticleSize",
39858
+ get: /**
39859
+ * Adjust the amount of drag based on particle sizes.
39860
+ */ function get() {
39861
+ return this._multiplyDragByParticleSize;
39862
+ },
39863
+ set: function set(value) {
39864
+ if (value !== this._multiplyDragByParticleSize) {
39865
+ this._multiplyDragByParticleSize = value;
39866
+ this._generator._renderer._onGeneratorParamsChanged();
39867
+ }
39868
+ }
39869
+ },
39870
+ {
39871
+ key: "multiplyDragByParticleVelocity",
39872
+ get: /**
39873
+ * Adjust the amount of drag based on particle speeds.
39874
+ */ function get() {
39875
+ return this._multiplyDragByParticleVelocity;
39876
+ },
39877
+ set: function set(value) {
39878
+ if (value !== this._multiplyDragByParticleVelocity) {
39879
+ this._multiplyDragByParticleVelocity = value;
39880
+ this._generator._renderer._onGeneratorParamsChanged();
39881
+ }
39882
+ }
39883
+ },
39884
+ {
39885
+ key: "space",
39886
+ get: /**
39887
+ * Specifies if the velocity limits are in local space or world space.
39888
+ */ function get() {
39889
+ return this._space;
39890
+ },
39891
+ set: function set(value) {
39892
+ if (value !== this._space) {
39893
+ this._space = value;
39894
+ this._generator._renderer._onGeneratorParamsChanged();
39895
+ }
39896
+ }
39897
+ },
39898
+ {
39899
+ key: "enabled",
39900
+ get: /**
39901
+ * Specifies whether the module is enabled.
39902
+ * @remarks This module requires WebGL2, On WebGL1, enabling will be silently ignored.
39903
+ */ function get() {
39904
+ return this._enabled;
39905
+ },
39906
+ set: function set(value) {
39907
+ if (value !== this._enabled) {
39908
+ if (value && !this._generator._renderer.engine._hardwareRenderer.isWebGL2) {
39909
+ return;
39910
+ }
39911
+ this._enabled = value;
39912
+ this._generator._setTransformFeedback(value);
39913
+ this._generator._renderer._onGeneratorParamsChanged();
39914
+ }
39915
+ }
39916
+ }
39917
+ ]);
39918
+ return LimitVelocityOverLifetimeModule;
39919
+ }(ParticleGeneratorModule);
39920
+ LimitVelocityOverLifetimeModule._enabledMacro = ShaderMacro.getByName("RENDERER_LVL_MODULE_ENABLED");
39921
+ LimitVelocityOverLifetimeModule._separateAxesMacro = ShaderMacro.getByName("RENDERER_LVL_SEPARATE_AXES");
39922
+ LimitVelocityOverLifetimeModule._limitConstantModeMacro = ShaderMacro.getByName("RENDERER_LVL_LIMIT_CONSTANT_MODE");
39923
+ LimitVelocityOverLifetimeModule._limitCurveModeMacro = ShaderMacro.getByName("RENDERER_LVL_LIMIT_CURVE_MODE");
39924
+ LimitVelocityOverLifetimeModule._limitIsRandomMacro = ShaderMacro.getByName("RENDERER_LVL_LIMIT_IS_RANDOM_TWO");
39925
+ LimitVelocityOverLifetimeModule._dragCurveModeMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_CURVE_MODE");
39926
+ LimitVelocityOverLifetimeModule._dragIsRandomMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_IS_RANDOM_TWO");
39927
+ LimitVelocityOverLifetimeModule._multiplyDragBySizeMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_MULTIPLY_SIZE");
39928
+ LimitVelocityOverLifetimeModule._multiplyDragByVelocityMacro = ShaderMacro.getByName("RENDERER_LVL_DRAG_MULTIPLY_VELOCITY");
39929
+ LimitVelocityOverLifetimeModule._limitMaxConstProperty = ShaderProperty.getByName("renderer_LVLLimitMaxConst");
39930
+ LimitVelocityOverLifetimeModule._limitMinConstProperty = ShaderProperty.getByName("renderer_LVLLimitMinConst");
39931
+ LimitVelocityOverLifetimeModule._limitMaxCurveProperty = ShaderProperty.getByName("renderer_LVLLimitMaxCurve");
39932
+ LimitVelocityOverLifetimeModule._limitMinCurveProperty = ShaderProperty.getByName("renderer_LVLLimitMinCurve");
39933
+ LimitVelocityOverLifetimeModule._limitMaxConstVecProperty = ShaderProperty.getByName("renderer_LVLLimitMaxConstVector");
39934
+ LimitVelocityOverLifetimeModule._limitMinConstVecProperty = ShaderProperty.getByName("renderer_LVLLimitMinConstVector");
39935
+ LimitVelocityOverLifetimeModule._limitXMaxCurveProperty = ShaderProperty.getByName("renderer_LVLLimitXMaxCurve");
39936
+ LimitVelocityOverLifetimeModule._limitXMinCurveProperty = ShaderProperty.getByName("renderer_LVLLimitXMinCurve");
39937
+ LimitVelocityOverLifetimeModule._limitYMaxCurveProperty = ShaderProperty.getByName("renderer_LVLLimitYMaxCurve");
39938
+ LimitVelocityOverLifetimeModule._limitYMinCurveProperty = ShaderProperty.getByName("renderer_LVLLimitYMinCurve");
39939
+ LimitVelocityOverLifetimeModule._limitZMaxCurveProperty = ShaderProperty.getByName("renderer_LVLLimitZMaxCurve");
39940
+ LimitVelocityOverLifetimeModule._limitZMinCurveProperty = ShaderProperty.getByName("renderer_LVLLimitZMinCurve");
39941
+ LimitVelocityOverLifetimeModule._dampenProperty = ShaderProperty.getByName("renderer_LVLDampen");
39942
+ LimitVelocityOverLifetimeModule._dragConstantProperty = ShaderProperty.getByName("renderer_LVLDragConstant");
39943
+ LimitVelocityOverLifetimeModule._dragMaxCurveProperty = ShaderProperty.getByName("renderer_LVLDragMaxCurve");
39944
+ LimitVelocityOverLifetimeModule._dragMinCurveProperty = ShaderProperty.getByName("renderer_LVLDragMinCurve");
39945
+ LimitVelocityOverLifetimeModule._spaceProperty = ShaderProperty.getByName("renderer_LVLSpace");
39946
+ __decorate$1([
39947
+ ignoreClone
39948
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitRand", void 0);
39949
+ __decorate$1([
39950
+ ignoreClone
39951
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitMinConstantVec", void 0);
39952
+ __decorate$1([
39953
+ ignoreClone
39954
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitMaxConstantVec", void 0);
39955
+ __decorate$1([
39956
+ ignoreClone
39957
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragConstantVec", void 0);
39958
+ __decorate$1([
39959
+ ignoreClone
39960
+ ], LimitVelocityOverLifetimeModule.prototype, "_enabledModuleMacro", void 0);
39961
+ __decorate$1([
39962
+ ignoreClone
39963
+ ], LimitVelocityOverLifetimeModule.prototype, "_separateAxesCachedMacro", void 0);
39964
+ __decorate$1([
39965
+ ignoreClone
39966
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitModeMacro", void 0);
39967
+ __decorate$1([
39968
+ ignoreClone
39969
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitRandomMacro", void 0);
39970
+ __decorate$1([
39971
+ ignoreClone
39972
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragCurveCachedMacro", void 0);
39973
+ __decorate$1([
39974
+ ignoreClone
39975
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragRandomCachedMacro", void 0);
39976
+ __decorate$1([
39977
+ ignoreClone
39978
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragSizeMacro", void 0);
39979
+ __decorate$1([
39980
+ ignoreClone
39981
+ ], LimitVelocityOverLifetimeModule.prototype, "_dragVelocityMacro", void 0);
39982
+ __decorate$1([
39983
+ deepClone
39984
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitX", void 0);
39985
+ __decorate$1([
39986
+ deepClone
39987
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitY", void 0);
39988
+ __decorate$1([
39989
+ deepClone
39990
+ ], LimitVelocityOverLifetimeModule.prototype, "_limitZ", void 0);
39991
+ __decorate$1([
39992
+ deepClone
39993
+ ], LimitVelocityOverLifetimeModule.prototype, "_drag", void 0);
39154
39994
  /**
39155
39995
  * Control how Particle Generator apply transform scale.
39156
39996
  */ var ParticleScaleMode = /*#__PURE__*/ function(ParticleScaleMode) {
@@ -40192,6 +41032,8 @@
40192
41032
  /** @internal */ this._firstRetiredElement = 0;
40193
41033
  /** @internal */ this._vertexBufferBindings = new Array();
40194
41034
  /** @internal */ this._subPrimitive = new SubMesh(0, 0, MeshTopology.Triangles);
41035
+ /** @internal */ this._useTransformFeedback = false;
41036
+ /** @internal */ this._feedbackBindingIndex = -1;
40195
41037
  this._isPlaying = false;
40196
41038
  this._instanceBufferResized = false;
40197
41039
  this._waitProcessRetiredElementCount = 0;
@@ -40210,6 +41052,7 @@
40210
41052
  this.velocityOverLifetime = new VelocityOverLifetimeModule(this);
40211
41053
  this.forceOverLifetime = new ForceOverLifetimeModule(this);
40212
41054
  this.sizeOverLifetime = new SizeOverLifetimeModule(this);
41055
+ this.limitVelocityOverLifetime = new LimitVelocityOverLifetimeModule(this);
40213
41056
  this.emission.enabled = true;
40214
41057
  }
40215
41058
  var _proto = ParticleGenerator.prototype;
@@ -40248,11 +41091,7 @@
40248
41091
  } else {
40249
41092
  this._isPlaying = false;
40250
41093
  if (stopMode === ParticleStopMode.StopEmittingAndClear) {
40251
- // Move the pointer to free immediately
40252
- var firstFreeElement = this._firstFreeElement;
40253
- this._firstRetiredElement = firstFreeElement;
40254
- this._firstActiveElement = firstFreeElement;
40255
- this._firstNewElement = firstFreeElement;
41094
+ this._clearActiveParticles();
40256
41095
  this._playTime = 0;
40257
41096
  this._firstActiveTransformedBoundingBox = this._firstFreeTransformedBoundingBox;
40258
41097
  this.emission._reset();
@@ -40336,6 +41175,16 @@
40336
41175
  this._isPlaying = false;
40337
41176
  }
40338
41177
  }
41178
+ // Retire all particles on device restore before bounds/volume bookkeeping
41179
+ var isContentLost = this._instanceVertexBufferBinding._buffer.isContentLost;
41180
+ if (isContentLost) {
41181
+ this._firstActiveElement = 0;
41182
+ this._firstNewElement = 0;
41183
+ this._firstFreeElement = 0;
41184
+ this._firstRetiredElement = 0;
41185
+ this._waitProcessRetiredElementCount = 0;
41186
+ this._firstActiveTransformedBoundingBox = this._firstFreeTransformedBoundingBox;
41187
+ }
40339
41188
  if (this.isAlive) {
40340
41189
  if (main.simulationSpace === ParticleSimulationSpace.World) {
40341
41190
  this._generateTransformedBounds();
@@ -40349,16 +41198,21 @@
40349
41198
  if (this.isAlive !== lastAlive) {
40350
41199
  this._renderer._onWorldVolumeChanged();
40351
41200
  }
40352
- // Add new particles to vertex buffer when has wait process retired element or new particle
40353
- //
40354
- // Another choice is just add new particles to vertex buffer and render all particles ignore the retired particle in shader, especially billboards
40355
- // But webgl don't support map buffer range, so this choice don't have performance advantage even less set data to GPU
40356
- if (this._firstNewElement != this._firstFreeElement || this._waitProcessRetiredElementCount > 0 || this._instanceBufferResized || this._instanceVertexBufferBinding._buffer.isContentLost) {
41201
+ if (this._firstNewElement != this._firstFreeElement || this._waitProcessRetiredElementCount > 0 || this._instanceBufferResized) {
40357
41202
  this._addActiveParticlesToVertexBuffer();
40358
41203
  }
40359
41204
  };
40360
41205
  /**
40361
41206
  * @internal
41207
+ * Run Transform Feedback simulation pass.
41208
+ */ _proto._updateFeedback = function _updateFeedback(shaderData, deltaTime) {
41209
+ this._feedbackSimulator.update(shaderData, this._currentParticleCount, this._firstActiveElement, this._firstFreeElement, deltaTime);
41210
+ // After swap, update the render pass buffer binding to point to the latest output.
41211
+ // VAO is disabled in TF mode so direct assignment is safe (no stale VAO issue).
41212
+ this._primitive.vertexBufferBindings[this._feedbackBindingIndex] = this._feedbackSimulator.readBinding;
41213
+ };
41214
+ /**
41215
+ * @internal
40362
41216
  */ _proto._reorganizeGeometryBuffers = function _reorganizeGeometryBuffers() {
40363
41217
  var _this = this, renderer = _this._renderer, primitive = _this._primitive, vertexBufferBindings = _this._vertexBufferBindings;
40364
41218
  var _renderer_engine = renderer.engine, particleUtils = _renderer_engine._particleBufferUtils;
@@ -40410,6 +41264,15 @@
40410
41264
  if (this._instanceVertexBufferBinding) {
40411
41265
  vertexBufferBindings.push(this._instanceVertexBufferBinding);
40412
41266
  }
41267
+ // Add feedback buffer binding for render pass
41268
+ if (this._useTransformFeedback) {
41269
+ this._feedbackBindingIndex = vertexBufferBindings.length;
41270
+ primitive.addVertexElement(new VertexElement(ParticleFeedbackVertexAttribute.Position, 0, VertexElementFormat.Vector3, this._feedbackBindingIndex, 1));
41271
+ primitive.addVertexElement(new VertexElement(ParticleFeedbackVertexAttribute.Velocity, 12, VertexElementFormat.Vector3, this._feedbackBindingIndex, 1));
41272
+ vertexBufferBindings.push(this._feedbackSimulator.readBinding);
41273
+ } else {
41274
+ this._feedbackBindingIndex = -1;
41275
+ }
40413
41276
  primitive.setVertexBufferBindings(vertexBufferBindings);
40414
41277
  };
40415
41278
  /**
@@ -40425,18 +41288,28 @@
40425
41288
  vertexInstanceBuffer.isGCIgnored = true;
40426
41289
  var vertexBufferBindings = this._primitive.vertexBufferBindings;
40427
41290
  var vertexBufferBinding = new VertexBufferBinding(vertexInstanceBuffer, stride);
40428
- var instanceVertices = new Float32Array(newByteLength / 4);
40429
41291
  var lastInstanceVertices = this._instanceVertices;
41292
+ var useFeedback = this._useTransformFeedback;
41293
+ var instanceVertices = new Float32Array(newByteLength / 4);
41294
+ if (useFeedback) {
41295
+ this._feedbackSimulator.resize(newParticleCount, vertexBufferBinding);
41296
+ }
40430
41297
  if (lastInstanceVertices) {
40431
- var floatStride = ParticleBufferUtils.instanceVertexFloatStride;
41298
+ var floatStride = ParticleBufferUtils.instanceVertexFloatStride, feedbackVertexStride = ParticleBufferUtils.feedbackVertexStride;
40432
41299
  var firstFreeElement = this._firstFreeElement;
40433
41300
  var firstRetiredElement = this._firstRetiredElement;
40434
41301
  if (isIncrease) {
41302
+ // Copy front segment [0, firstFreeElement)
40435
41303
  instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, 0, firstFreeElement * floatStride));
41304
+ // Copy tail segment shifted by increaseCount
40436
41305
  var nextFreeElement = firstFreeElement + 1;
40437
- var freeEndOffset = (nextFreeElement + increaseCount) * floatStride;
40438
- instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, nextFreeElement * floatStride * 4), freeEndOffset);
40439
- // Maintain expanded pointers
41306
+ var tailCount = this._currentParticleCount - nextFreeElement;
41307
+ var tailDstElement = nextFreeElement + increaseCount;
41308
+ instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, nextFreeElement * floatStride * 4), tailDstElement * floatStride);
41309
+ if (useFeedback) {
41310
+ this._feedbackSimulator.copyOldBufferData(0, 0, firstFreeElement * feedbackVertexStride);
41311
+ this._feedbackSimulator.copyOldBufferData(nextFreeElement * feedbackVertexStride, tailDstElement * feedbackVertexStride, tailCount * feedbackVertexStride);
41312
+ }
40440
41313
  this._firstNewElement > firstFreeElement && (this._firstNewElement += increaseCount);
40441
41314
  this._firstActiveElement > firstFreeElement && (this._firstActiveElement += increaseCount);
40442
41315
  firstRetiredElement > firstFreeElement && (this._firstRetiredElement += increaseCount);
@@ -40445,7 +41318,6 @@
40445
41318
  if (firstRetiredElement <= firstFreeElement) {
40446
41319
  migrateCount = firstFreeElement - firstRetiredElement;
40447
41320
  bufferOffset = 0;
40448
- // Maintain expanded pointers
40449
41321
  this._firstFreeElement -= firstRetiredElement;
40450
41322
  this._firstNewElement -= firstRetiredElement;
40451
41323
  this._firstActiveElement -= firstRetiredElement;
@@ -40453,20 +41325,29 @@
40453
41325
  } else {
40454
41326
  migrateCount = this._currentParticleCount - firstRetiredElement;
40455
41327
  bufferOffset = firstFreeElement;
40456
- // Maintain expanded pointers
40457
41328
  this._firstNewElement > firstFreeElement && (this._firstNewElement -= firstFreeElement);
40458
41329
  this._firstActiveElement > firstFreeElement && (this._firstActiveElement -= firstFreeElement);
40459
41330
  firstRetiredElement > firstFreeElement && (this._firstRetiredElement -= firstFreeElement);
40460
41331
  }
40461
41332
  instanceVertices.set(new Float32Array(lastInstanceVertices.buffer, firstRetiredElement * floatStride * 4, migrateCount * floatStride), bufferOffset * floatStride);
41333
+ if (useFeedback) {
41334
+ this._feedbackSimulator.copyOldBufferData(firstRetiredElement * feedbackVertexStride, bufferOffset * feedbackVertexStride, migrateCount * feedbackVertexStride);
41335
+ }
41336
+ }
41337
+ if (useFeedback) {
41338
+ this._feedbackSimulator.destroyOldBuffers();
40462
41339
  }
40463
41340
  this._instanceBufferResized = true;
40464
41341
  }
40465
- // Instance buffer always at last
40466
- this._primitive.setVertexBufferBinding(lastInstanceVertices ? vertexBufferBindings.length - 1 : vertexBufferBindings.length, vertexBufferBinding);
41342
+ // Update instance buffer binding
41343
+ var instanceBindingIndex = lastInstanceVertices ? vertexBufferBindings.length - 1 - (useFeedback ? 1 : 0) : vertexBufferBindings.length;
41344
+ this._primitive.setVertexBufferBinding(instanceBindingIndex, vertexBufferBinding);
40467
41345
  this._instanceVertices = instanceVertices;
40468
41346
  this._instanceVertexBufferBinding = vertexBufferBinding;
40469
41347
  this._currentParticleCount = newParticleCount;
41348
+ if (useFeedback) {
41349
+ this._primitive.setVertexBufferBinding(this._feedbackBindingIndex, this._feedbackSimulator.readBinding);
41350
+ }
40470
41351
  };
40471
41352
  /**
40472
41353
  * @internal
@@ -40474,6 +41355,7 @@
40474
41355
  this.main._updateShaderData(shaderData);
40475
41356
  this.velocityOverLifetime._updateShaderData(shaderData);
40476
41357
  this.forceOverLifetime._updateShaderData(shaderData);
41358
+ this.limitVelocityOverLifetime._updateShaderData(shaderData);
40477
41359
  this.textureSheetAnimation._updateShaderData(shaderData);
40478
41360
  this.sizeOverLifetime._updateShaderData(shaderData);
40479
41361
  this.rotationOverLifetime._updateShaderData(shaderData);
@@ -40488,11 +41370,41 @@
40488
41370
  this.textureSheetAnimation._resetRandomSeed(seed);
40489
41371
  this.velocityOverLifetime._resetRandomSeed(seed);
40490
41372
  this.forceOverLifetime._resetRandomSeed(seed);
41373
+ this.limitVelocityOverLifetime._resetRandomSeed(seed);
40491
41374
  this.rotationOverLifetime._resetRandomSeed(seed);
40492
41375
  this.colorOverLifetime._resetRandomSeed(seed);
40493
41376
  };
40494
41377
  /**
40495
41378
  * @internal
41379
+ */ _proto._setTransformFeedback = function _setTransformFeedback(enabled) {
41380
+ this._useTransformFeedback = enabled;
41381
+ // Switching TF mode invalidates all active particle state: feedback buffers and instance
41382
+ // buffer layout are incompatible between the two paths. Clear rather than show a one-frame
41383
+ // jump; new particles will fill in naturally from the next emit cycle.
41384
+ this._clearActiveParticles();
41385
+ if (enabled) {
41386
+ if (!this._feedbackSimulator) {
41387
+ this._feedbackSimulator = new ParticleTransformFeedbackSimulator(this._renderer.engine);
41388
+ }
41389
+ var simulator = this._feedbackSimulator;
41390
+ var readBinding = simulator.readBinding;
41391
+ if (!readBinding || readBinding.buffer.byteLength !== this._currentParticleCount * ParticleBufferUtils.feedbackVertexStride) {
41392
+ simulator.resize(this._currentParticleCount, this._instanceVertexBufferBinding);
41393
+ simulator.destroyOldBuffers();
41394
+ } else {
41395
+ simulator._instanceBinding = this._instanceVertexBufferBinding;
41396
+ }
41397
+ this._renderer.shaderData.enableMacro(ParticleGenerator._transformFeedbackMacro);
41398
+ // Feedback buffer swaps every frame; VAO caching would bake stale buffer handles.
41399
+ this._primitive.enableVAO = false;
41400
+ } else {
41401
+ this._renderer.shaderData.disableMacro(ParticleGenerator._transformFeedbackMacro);
41402
+ this._primitive.enableVAO = true;
41403
+ }
41404
+ this._reorganizeGeometryBuffers();
41405
+ };
41406
+ /**
41407
+ * @internal
40496
41408
  */ _proto._getAliveParticleCount = function _getAliveParticleCount() {
40497
41409
  if (this._firstActiveElement <= this._firstFreeElement) {
40498
41410
  return this._firstFreeElement - this._firstActiveElement;
@@ -40519,10 +41431,19 @@
40519
41431
  };
40520
41432
  /**
40521
41433
  * @internal
41434
+ */ _proto._cloneTo = function _cloneTo(target) {
41435
+ if (target.limitVelocityOverLifetime.enabled) {
41436
+ target._setTransformFeedback(true);
41437
+ }
41438
+ };
41439
+ /**
41440
+ * @internal
40522
41441
  */ _proto._destroy = function _destroy() {
41442
+ var _this__feedbackSimulator;
40523
41443
  this._instanceVertexBufferBinding.buffer.destroy();
40524
41444
  this._primitive.destroy();
40525
41445
  this.emission._destroy();
41446
+ (_this__feedbackSimulator = this._feedbackSimulator) == null ? void 0 : _this__feedbackSimulator.destroy();
40526
41447
  };
40527
41448
  /**
40528
41449
  * @internal
@@ -40754,8 +41675,34 @@
40754
41675
  instanceVertices[offset + 39] = rand1.random();
40755
41676
  instanceVertices[offset + 40] = rand1.random();
40756
41677
  }
41678
+ var limitVelocityOverLifetime = this.limitVelocityOverLifetime;
41679
+ if (limitVelocityOverLifetime.enabled && (limitVelocityOverLifetime._isLimitRandomMode() || limitVelocityOverLifetime._isDragRandomMode())) {
41680
+ instanceVertices[offset + 41] = limitVelocityOverLifetime._limitRand.random();
41681
+ }
41682
+ // Initialize feedback buffer for this particle
41683
+ if (this._useTransformFeedback) {
41684
+ this._addFeedbackParticle(firstFreeElement, position, direction, startSpeed, transform);
41685
+ }
40757
41686
  this._firstFreeElement = nextFreeElement;
40758
41687
  };
41688
+ _proto._addFeedbackParticle = function _addFeedbackParticle(index, shapePosition, direction, startSpeed, transform) {
41689
+ var position;
41690
+ if (this.main.simulationSpace === ParticleSimulationSpace.Local) {
41691
+ position = shapePosition;
41692
+ } else {
41693
+ position = ParticleGenerator._tempVector32;
41694
+ Vector3.transformByQuat(shapePosition, transform.worldRotationQuaternion, position);
41695
+ position.add(transform.worldPosition);
41696
+ }
41697
+ this._feedbackSimulator.writeParticleData(index, position, direction.x * startSpeed, direction.y * startSpeed, direction.z * startSpeed);
41698
+ };
41699
+ _proto._clearActiveParticles = function _clearActiveParticles() {
41700
+ var firstFreeElement = this._firstFreeElement;
41701
+ this._firstRetiredElement = firstFreeElement;
41702
+ this._firstActiveElement = firstFreeElement;
41703
+ this._firstNewElement = firstFreeElement;
41704
+ this._firstActiveTransformedBoundingBox = this._firstFreeTransformedBoundingBox;
41705
+ };
40759
41706
  _proto._retireActiveParticles = function _retireActiveParticles() {
40760
41707
  var engine = this._renderer.engine;
40761
41708
  var frameCount = engine.time.frameCount;
@@ -40799,16 +41746,19 @@
40799
41746
  return;
40800
41747
  }
40801
41748
  var byteStride = ParticleBufferUtils.instanceVertexStride;
40802
- var start = firstActiveElement * byteStride;
40803
41749
  var instanceBuffer = this._instanceVertexBufferBinding.buffer;
40804
41750
  var dataBuffer = this._instanceVertices.buffer;
41751
+ // Feedback mode: upload in-place (indices match feedback buffer slots)
41752
+ // Non-feedback mode: compact to GPU offset 0
41753
+ var compact = !this._useTransformFeedback;
41754
+ var start = firstActiveElement * byteStride;
40805
41755
  if (firstActiveElement < firstFreeElement) {
40806
- instanceBuffer.setData(dataBuffer, 0, start, (firstFreeElement - firstActiveElement) * byteStride, SetDataOptions.Discard);
41756
+ instanceBuffer.setData(dataBuffer, compact ? 0 : start, start, (firstFreeElement - firstActiveElement) * byteStride, SetDataOptions.Discard);
40807
41757
  } else {
40808
- var firstSegmentCount = (this._currentParticleCount - firstActiveElement) * byteStride;
40809
- instanceBuffer.setData(dataBuffer, 0, start, firstSegmentCount, SetDataOptions.Discard);
41758
+ var firstSegmentSize = (this._currentParticleCount - firstActiveElement) * byteStride;
41759
+ instanceBuffer.setData(dataBuffer, compact ? 0 : start, start, firstSegmentSize, SetDataOptions.Discard);
40810
41760
  if (firstFreeElement > 0) {
40811
- instanceBuffer.setData(dataBuffer, firstSegmentCount, 0, firstFreeElement * byteStride);
41761
+ instanceBuffer.setData(dataBuffer, compact ? firstSegmentSize : 0, 0, firstFreeElement * byteStride);
40812
41762
  }
40813
41763
  }
40814
41764
  this._firstNewElement = firstFreeElement;
@@ -41026,11 +41976,13 @@
41026
41976
  ParticleGenerator._tempVector22 = new Vector2();
41027
41977
  ParticleGenerator._tempVector30 = new Vector3();
41028
41978
  ParticleGenerator._tempVector31 = new Vector3();
41979
+ ParticleGenerator._tempVector32 = new Vector3();
41029
41980
  ParticleGenerator._tempMat = new Matrix();
41030
41981
  ParticleGenerator._tempColor0 = new Color();
41031
41982
  ParticleGenerator._tempParticleRenderers = new Array();
41032
41983
  ParticleGenerator._particleIncreaseCount = 128;
41033
41984
  ParticleGenerator._transformedBoundsIncreaseCount = 16;
41985
+ ParticleGenerator._transformFeedbackMacro = ShaderMacro.getByName("RENDERER_TRANSFORM_FEEDBACK");
41034
41986
  __decorate$1([
41035
41987
  deepClone
41036
41988
  ], ParticleGenerator.prototype, "main", void 0);
@@ -41043,6 +41995,9 @@
41043
41995
  __decorate$1([
41044
41996
  deepClone
41045
41997
  ], ParticleGenerator.prototype, "forceOverLifetime", void 0);
41998
+ __decorate$1([
41999
+ deepClone
42000
+ ], ParticleGenerator.prototype, "limitVelocityOverLifetime", void 0);
41046
42001
  __decorate$1([
41047
42002
  deepClone
41048
42003
  ], ParticleGenerator.prototype, "sizeOverLifetime", void 0);
@@ -41079,6 +42034,15 @@
41079
42034
  __decorate$1([
41080
42035
  ignoreClone
41081
42036
  ], ParticleGenerator.prototype, "_subPrimitive", void 0);
42037
+ __decorate$1([
42038
+ ignoreClone
42039
+ ], ParticleGenerator.prototype, "_feedbackSimulator", void 0);
42040
+ __decorate$1([
42041
+ ignoreClone
42042
+ ], ParticleGenerator.prototype, "_useTransformFeedback", void 0);
42043
+ __decorate$1([
42044
+ ignoreClone
42045
+ ], ParticleGenerator.prototype, "_feedbackBindingIndex", void 0);
41082
42046
  __decorate$1([
41083
42047
  ignoreClone
41084
42048
  ], ParticleGenerator.prototype, "_isPlaying", void 0);
@@ -43226,6 +44190,7 @@
43226
44190
  Layer: Layer,
43227
44191
  LayerPathMask: LayerPathMask,
43228
44192
  Light: Light,
44193
+ LimitVelocityOverLifetimeModule: LimitVelocityOverLifetimeModule,
43229
44194
  Loader: Loader,
43230
44195
  Logger: Logger,
43231
44196
  MSAASamples: MSAASamples,
@@ -43676,6 +44641,14 @@
43676
44641
  throw "Buffer is write-only on WebGL1.0 platforms.";
43677
44642
  }
43678
44643
  };
44644
+ _proto.copyFromBuffer = function copyFromBuffer(srcBuffer, srcByteOffset, dstByteOffset, byteLength) {
44645
+ var gl = this._gl;
44646
+ gl.bindBuffer(gl.COPY_READ_BUFFER, srcBuffer._glBuffer);
44647
+ gl.bindBuffer(gl.COPY_WRITE_BUFFER, this._glBuffer);
44648
+ gl.copyBufferSubData(gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, srcByteOffset, dstByteOffset, byteLength);
44649
+ gl.bindBuffer(gl.COPY_READ_BUFFER, null);
44650
+ gl.bindBuffer(gl.COPY_WRITE_BUFFER, null);
44651
+ };
43679
44652
  _proto.destroy = function destroy() {
43680
44653
  this._gl.deleteBuffer(this._glBuffer);
43681
44654
  this._gl = null;
@@ -45166,6 +46139,150 @@
45166
46139
  };
45167
46140
  return GLTextureCube;
45168
46141
  }(GLTexture);
46142
+ /**
46143
+ * @internal
46144
+ * WebGL2 implementation of Transform Feedback.
46145
+ */ var GLTransformFeedback = /*#__PURE__*/ function() {
46146
+ function GLTransformFeedback(rhi) {
46147
+ var gl = rhi.gl;
46148
+ this._gl = gl;
46149
+ this._glTransformFeedback = gl.createTransformFeedback();
46150
+ }
46151
+ var _proto = GLTransformFeedback.prototype;
46152
+ _proto.bindBufferRange = function bindBufferRange(index, buffer, byteOffset, byteSize) {
46153
+ var gl = this._gl;
46154
+ gl.bindBufferRange(gl.TRANSFORM_FEEDBACK_BUFFER, index, buffer._glBuffer, byteOffset, byteSize);
46155
+ };
46156
+ _proto.unbindBuffer = function unbindBuffer(index) {
46157
+ var gl = this._gl;
46158
+ gl.bindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, index, null);
46159
+ };
46160
+ _proto.begin = function begin(primitiveMode) {
46161
+ this._gl.beginTransformFeedback(primitiveMode);
46162
+ };
46163
+ _proto.end = function end() {
46164
+ this._gl.endTransformFeedback();
46165
+ };
46166
+ _proto.bind = function bind() {
46167
+ var gl = this._gl;
46168
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, this._glTransformFeedback);
46169
+ };
46170
+ _proto.unbind = function unbind() {
46171
+ var gl = this._gl;
46172
+ gl.bindTransformFeedback(gl.TRANSFORM_FEEDBACK, null);
46173
+ };
46174
+ _proto.destroy = function destroy() {
46175
+ if (this._glTransformFeedback) {
46176
+ this._gl.deleteTransformFeedback(this._glTransformFeedback);
46177
+ this._glTransformFeedback = null;
46178
+ }
46179
+ };
46180
+ return GLTransformFeedback;
46181
+ }();
46182
+ function _array_like_to_array$1(arr, len) {
46183
+ if (len == null || len > arr.length) len = arr.length;
46184
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
46185
+ return arr2;
46186
+ }
46187
+ function _unsupported_iterable_to_array$1(o, minLen) {
46188
+ if (!o) return;
46189
+ if (typeof o === "string") return _array_like_to_array$1(o, minLen);
46190
+ var n = Object.prototype.toString.call(o).slice(8, -1);
46191
+ if (n === "Object" && o.constructor) n = o.constructor.name;
46192
+ if (n === "Map" || n === "Set") return Array.from(n);
46193
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
46194
+ }
46195
+ function _create_for_of_iterator_helper_loose$1(o, allowArrayLike) {
46196
+ var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
46197
+ if (it) return (it = it.call(o)).next.bind(it);
46198
+ // Fallback for engines without symbol support
46199
+ if (Array.isArray(o) || (it = _unsupported_iterable_to_array$1(o)) || allowArrayLike && o && typeof o.length === "number") {
46200
+ if (it) o = it;
46201
+ var i = 0;
46202
+ return function() {
46203
+ if (i >= o.length) return {
46204
+ done: true
46205
+ };
46206
+ return {
46207
+ done: false,
46208
+ value: o[i++]
46209
+ };
46210
+ };
46211
+ }
46212
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
46213
+ }
46214
+ /**
46215
+ * @internal
46216
+ * WebGL2 implementation of Transform Feedback primitive.
46217
+ * Maintains two VAOs (one per read direction), auto-rebuilds when program changes.
46218
+ */ var GLTransformFeedbackPrimitive = /*#__PURE__*/ function() {
46219
+ function GLTransformFeedbackPrimitive(gl) {
46220
+ this._lastProgramId = -1;
46221
+ this._gl = gl;
46222
+ }
46223
+ var _proto = GLTransformFeedbackPrimitive.prototype;
46224
+ _proto.updateVertexLayout = function updateVertexLayout(program, readBinding, writeBinding, feedbackElements, inputBinding, inputElements) {
46225
+ if (program.id === this._lastProgramId) return;
46226
+ this._deleteVAOs();
46227
+ var attribs = program.attributeLocation;
46228
+ this._vaoA = this._createVAO(attribs, readBinding, feedbackElements, inputBinding, inputElements);
46229
+ this._vaoB = this._createVAO(attribs, writeBinding, feedbackElements, inputBinding, inputElements);
46230
+ this._lastProgramId = program.id;
46231
+ this._gl.bindVertexArray(null);
46232
+ };
46233
+ _proto.bind = function bind(readIsA) {
46234
+ this._gl.bindVertexArray(readIsA ? this._vaoA : this._vaoB);
46235
+ };
46236
+ _proto.unbind = function unbind() {
46237
+ this._gl.bindVertexArray(null);
46238
+ };
46239
+ _proto.draw = function draw(mode, first, count) {
46240
+ this._gl.drawArrays(mode, first, count);
46241
+ };
46242
+ _proto.invalidate = function invalidate() {
46243
+ this._deleteVAOs();
46244
+ };
46245
+ _proto.destroy = function destroy() {
46246
+ this._deleteVAOs();
46247
+ };
46248
+ _proto._deleteVAOs = function _deleteVAOs() {
46249
+ var gl = this._gl;
46250
+ if (this._vaoA) {
46251
+ gl.deleteVertexArray(this._vaoA);
46252
+ this._vaoA = null;
46253
+ }
46254
+ if (this._vaoB) {
46255
+ gl.deleteVertexArray(this._vaoB);
46256
+ this._vaoB = null;
46257
+ }
46258
+ this._lastProgramId = -1;
46259
+ };
46260
+ _proto._createVAO = function _createVAO(attribs, feedbackBinding, feedbackElements, inputBinding, inputElements) {
46261
+ var gl = this._gl;
46262
+ var vao = gl.createVertexArray();
46263
+ gl.bindVertexArray(vao);
46264
+ // @ts-ignore: Access internal _platformBuffer across packages
46265
+ gl.bindBuffer(gl.ARRAY_BUFFER, feedbackBinding.buffer._platformBuffer._glBuffer);
46266
+ this._bindElements(gl, attribs, feedbackElements, feedbackBinding.stride);
46267
+ // @ts-ignore: Access internal _platformBuffer across packages
46268
+ gl.bindBuffer(gl.ARRAY_BUFFER, inputBinding.buffer._platformBuffer._glBuffer);
46269
+ this._bindElements(gl, attribs, inputElements, inputBinding.stride);
46270
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
46271
+ return vao;
46272
+ };
46273
+ _proto._bindElements = function _bindElements(gl, attribs, elements, stride) {
46274
+ for(var _iterator = _create_for_of_iterator_helper_loose$1(elements), _step; !(_step = _iterator()).done;){
46275
+ var element = _step.value;
46276
+ var loc = attribs[element.attribute];
46277
+ if (loc !== undefined && loc !== -1) {
46278
+ var info = element._formatMetaInfo;
46279
+ gl.enableVertexAttribArray(loc);
46280
+ gl.vertexAttribPointer(loc, info.size, info.type, info.normalized, stride, element.offset);
46281
+ }
46282
+ }
46283
+ };
46284
+ return GLTransformFeedbackPrimitive;
46285
+ }();
45169
46286
  /**
45170
46287
  * WebGL mode.
45171
46288
  */ var WebGLMode = /*#__PURE__*/ function(WebGLMode) {
@@ -45287,6 +46404,37 @@
45287
46404
  if (bufferUsage === void 0) bufferUsage = BufferUsage.Static;
45288
46405
  return new GLBuffer(this, type, byteLength, bufferUsage, data);
45289
46406
  };
46407
+ _proto.createPlatformTransformFeedback = function createPlatformTransformFeedback() {
46408
+ return new GLTransformFeedback(this);
46409
+ };
46410
+ _proto.createPlatformTransformFeedbackPrimitive = function createPlatformTransformFeedbackPrimitive() {
46411
+ return new GLTransformFeedbackPrimitive(this._gl);
46412
+ };
46413
+ /**
46414
+ * Enable GL_RASTERIZER_DISCARD (WebGL2 only).
46415
+ */ _proto.enableRasterizerDiscard = function enableRasterizerDiscard() {
46416
+ if (this._isWebGL2) {
46417
+ var gl = this._gl;
46418
+ gl.enable(gl.RASTERIZER_DISCARD);
46419
+ }
46420
+ };
46421
+ /**
46422
+ * Disable GL_RASTERIZER_DISCARD (WebGL2 only).
46423
+ */ _proto.disableRasterizerDiscard = function disableRasterizerDiscard() {
46424
+ if (this._isWebGL2) {
46425
+ var gl = this._gl;
46426
+ gl.disable(gl.RASTERIZER_DISCARD);
46427
+ }
46428
+ };
46429
+ /**
46430
+ * Invalidate the cached shader program state.
46431
+ * Call this after using a custom program (e.g., Transform Feedback) outside the engine's pipeline.
46432
+ */ _proto.invalidateShaderProgramState = function invalidateShaderProgramState() {
46433
+ if (this._currentBindShaderProgram) {
46434
+ this._gl.useProgram(null);
46435
+ this._currentBindShaderProgram = null;
46436
+ }
46437
+ };
45290
46438
  _proto.requireExtension = function requireExtension(ext) {
45291
46439
  return this._extensions.requireExtension(ext);
45292
46440
  };
@@ -52910,7 +54058,7 @@
52910
54058
  ], EXT_texture_webp);
52911
54059
 
52912
54060
  //@ts-ignore
52913
- var version = "2.0.0-alpha.16";
54061
+ var version = "2.0.0-alpha.17";
52914
54062
  console.log("Galacean Engine Version: " + version);
52915
54063
  for(var key in CoreObjects){
52916
54064
  Loader.registerClass(key, CoreObjects[key]);
@@ -53057,6 +54205,7 @@
53057
54205
  exports.Layer = Layer;
53058
54206
  exports.LayerPathMask = LayerPathMask;
53059
54207
  exports.Light = Light;
54208
+ exports.LimitVelocityOverLifetimeModule = LimitVelocityOverLifetimeModule;
53060
54209
  exports.Loader = Loader;
53061
54210
  exports.Logger = Logger;
53062
54211
  exports.MSAASamples = MSAASamples;