// // ClampVelocityModule.cpp // cocos2d_libs // // Created by 徐俊杰 on 2020/4/24. // #include "rparticle/Modules/ClampVelocityModule.h" //#include "UnityPrefix.h" //#include "Runtime/BaseClasses/ObjectDefines.h" #include "rparticle/Serialize/TransferFunctions/SerializeTransfer.h" //#include "rparticle/Modules/ClampVelocityModule.h" #include "rparticle/ParticleSystemUtils.h" //#include "Runtime/Misc/BuildSettings.h" NS_RRP_BEGIN inline float DampenOutsideLimit (float v, float limit, float dampen) { float sgn = Sign (v); float abs = Abs (v); if (abs > limit) abs = Lerp(abs, limit, dampen); return abs * sgn; } ClampVelocityModule::ClampVelocityModule () : ParticleSystemModule(false) , m_SeparateAxis (false) , m_InWorldSpace (false) , m_Dampen (1.0f) { } template void MagnitudeUpdateTpl(const MinMaxCurve& magnitude, const ParticleSystemReadOnlyState& roState, ParticleSystemParticles& ps, size_t fromIndex, size_t toIndex, float dampen) { for (size_t q = fromIndex; q < toIndex; ++q) { float limit = Evaluate (magnitude, NormalizedTime(ps, q), GenerateRandom(ps.randomSeed[q] + kParticleSystemClampVelocityCurveId)) * roState.GetRenderScale(); Vector3f vel = ps.velocity[q] + ps.animatedVelocity[q]; vel = NormalizeSafe (vel) * DampenOutsideLimit (Magnitude (vel), limit, dampen); ps.velocity[q] = vel - ps.animatedVelocity[q]; } } template void MagnitudeUpdatePerAxisTpl(const MinMaxCurve& x, const MinMaxCurve& y, const MinMaxCurve& z, const ParticleSystemReadOnlyState& roState, const ParticleSystemState& state, ParticleSystemParticles& ps, size_t fromIndex, size_t toIndex, float dampen, bool worldSpace) { Matrix4x4f matrix; Matrix4x4f invMatrix; bool transform; // if(IS_CONTENT_NEWER_OR_SAME (kUnityVersion4_0_a1)) if(true) transform = GetTransformationMatrices(matrix, invMatrix, !roState.useLocalSpace, worldSpace, state.localToWorld); else transform = false; // Revert to old broken behavior for (size_t q = fromIndex; q < toIndex; ++q) { Vector3f random; GenerateRandom3(random, ps.randomSeed[q] + kParticleSystemClampVelocityCurveId); float time = NormalizedTime(ps, q); Vector3f vel = ps.velocity[q] + ps.animatedVelocity[q]; if (transform) vel = matrix * vel; float scale = roState.GetRenderScale(); float limitX = Evaluate(x, time, random.x) * scale; float limitY = Evaluate(y, time, random.y) * scale; float limitZ = Evaluate(z, time, random.z) * scale; vel.x = DampenOutsideLimit(vel.x, limitX, dampen); vel.y = DampenOutsideLimit(vel.y, limitY, dampen); vel.z = DampenOutsideLimit(vel.z, limitZ, dampen); vel -= ps.animatedVelocity[q]; if (transform) vel = invMatrix * vel; ps.velocity[q] = vel; } } template void DragUpdateTpl(const MinMaxCurve& drag, bool useParticleSize, bool useParticleVelocity, ParticleSystemParticles& ps, size_t fromIndex, size_t toIndex, float dt) { int useSize = useParticleSize ? 0xffffffff : 0; int useVelocity = useParticleVelocity ? 0xffffffff : 0; for (size_t q = fromIndex; q < toIndex; ++q) { float time = NormalizedTime(ps, q); float random = GenerateRandom(ps.randomSeed[q] + kParticleSystemDragCurveId); float dragCoefficient = Evaluate(drag, time, random); Vector3f vel = ps.velocity[q] + ps.animatedVelocity[q]; float velMagSqr = SqrMagnitude(vel); float maxDimension = ps.size[q]; // if (ps.uses3DSize) // { // maxDimension = math::max(maxDimension, math::max(particleSizes[1].load(q), particleSizes[2].load(q))); // } maxDimension *= 0.5f; float circleArea = (M_PI * maxDimension * maxDimension); float dragValue = dragCoefficient; if (useSize) dragValue *= circleArea; if (useVelocity) dragValue *= velMagSqr; float velMag = sqrt(velMagSqr); // Vector3f normalizedVel = select(Vector3f(ZERO, ZERO, ZERO), div(vel, velMag), velMag > epsilon_normal_sqrt()); Vector3f normalizedVel; if (velMag > 0) normalizedVel = vel / velMag; velMag = std::max(0, velMag - dragValue * dt); vel = normalizedVel * velMag; ps.velocity[q] = vel - ps.animatedVelocity[q]; } } void ClampVelocityModule::Update (const ParticleSystemReadOnlyState& roState, const ParticleSystemState& state, ParticleSystemParticles& ps, const size_t fromIndex, const size_t toIndex, float dt) { if (m_Dampen > 0.0f) { const bool isOptimized = m_X.IsOptimized() && m_Y.IsOptimized() && m_Z.IsOptimized(); float dampen = 1.0f - pow(1.0f - m_Dampen, dt * 30.0f); // use a reference fps of 30, as damping is set between 0 and 1, and without the reference fps, applied damping // is far too small. if we don't apply dt at all, we get FogBugz case 606420, where damping is fps dependent if (m_SeparateAxis) { if (m_X.minMaxState == kMMCScalar) MagnitudeUpdatePerAxisTpl(m_X, m_Y, m_Z, roState, state, ps, fromIndex, toIndex, dampen, m_InWorldSpace); else if (isOptimized && m_X.UsesMinMax()) MagnitudeUpdatePerAxisTpl(m_X, m_Y, m_Z, roState, state, ps, fromIndex, toIndex, dampen, m_InWorldSpace); else if (isOptimized) MagnitudeUpdatePerAxisTpl(m_X, m_Y, m_Z, roState, state, ps, fromIndex, toIndex, dampen, m_InWorldSpace); else MagnitudeUpdatePerAxisTpl(m_X, m_Y, m_Z, roState, state, ps, fromIndex, toIndex, dampen, m_InWorldSpace); } else { if (m_Magnitude.minMaxState == kMMCScalar) MagnitudeUpdateTpl(m_Magnitude, roState, ps, fromIndex, toIndex, dampen); else if (m_Magnitude.IsOptimized() && m_Magnitude.UsesMinMax()) MagnitudeUpdateTpl(m_Magnitude, roState, ps, fromIndex, toIndex, dampen); else if (m_Magnitude.IsOptimized()) MagnitudeUpdateTpl(m_Magnitude, roState, ps, fromIndex, toIndex, dampen); else MagnitudeUpdateTpl(m_Magnitude, roState, ps, fromIndex, toIndex, dampen); } } // apply air drag if (m_Drag.GetScalar() != 0.0f) { if (m_Drag.minMaxState == kMMCScalar) DragUpdateTpl(m_Drag, m_MultiplyDragByParticleSize, m_MultiplyDragByParticleVelocity, ps, fromIndex, toIndex, dt); else if (m_Drag.IsOptimized() && m_Drag.UsesMinMax()) DragUpdateTpl(m_Drag, m_MultiplyDragByParticleSize, m_MultiplyDragByParticleVelocity, ps, fromIndex, toIndex, dt); else if (m_Drag.IsOptimized()) DragUpdateTpl(m_Drag, m_MultiplyDragByParticleSize, m_MultiplyDragByParticleVelocity, ps, fromIndex, toIndex, dt); else DragUpdateTpl(m_Drag, m_MultiplyDragByParticleSize, m_MultiplyDragByParticleVelocity, ps, fromIndex, toIndex, dt); } } void ClampVelocityModule::CheckConsistency () { m_Dampen = clamp (m_Dampen, 0.0f, 1.0f); m_X.SetScalar(std::max (0.0f, m_X.GetScalar())); m_Y.SetScalar(std::max (0.0f, m_Y.GetScalar())); m_Z.SetScalar(std::max (0.0f, m_Z.GetScalar())); m_Magnitude.SetScalar(std::max (0.0f, m_Magnitude.GetScalar())); m_Drag.SetScalar(clamp (m_Drag.GetScalar(), 0.0f, 100000.0f)); } template void ClampVelocityModule::Transfer (TransferFunction& transfer) { ParticleSystemModule::Transfer (transfer); transfer.Transfer (m_X, "x"); transfer.Transfer (m_Y, "y"); transfer.Transfer (m_Z, "z"); transfer.Transfer (m_Magnitude, "magnitude"); transfer.Transfer (m_SeparateAxis, "separateAxis"); transfer.Transfer (m_InWorldSpace, "inWorldSpace"); transfer.Transfer (m_MultiplyDragByParticleSize, "multiplyDragByParticleSize"); transfer.Transfer (m_MultiplyDragByParticleVelocity, "multiplyDragByParticleVelocity"); transfer.Align (); transfer.Transfer (m_Dampen, "dampen"); transfer.Transfer (m_Drag, "drag"); } INSTANTIATE_TEMPLATE_TRANSFER(ClampVelocityModule) NS_RRP_END