以下是我个人流体引擎粒子系统动画系统的部分头文件
class ParticleSystemData3 { public: typedef std::vector<double> ScalarData; typedef std::vector<Vector3D> VectorData; ParticleSystemData3(); virtual ~ParticleSystemData3(); explicit ParticleSystemData3(size_t numberOfParticles); void Resize(size_t newNumberOfParticles); size_t GetNumberOfParticles() const; size_t AddVectorData(const Vector3D& initialVal = Vector3D::zero); size_t AddScalarData(double initialVal = 0.0); const std::vector<Vector3D>& GetPositions() const; std::vector<Vector3D>& GetPositions(); const std::vector<Vector3D>& GetVelocities() const; std::vector<Vector3D>& GetVelocities(); const std::vector<Vector3D>& GetForces() const; std::vector<Vector3D>& GetForces(); void AddParticle( const Vector3D& newPosition, const Vector3D& newVelocity, const Vector3D& newForce = Vector3D::zero); void AddParticles( const std::vector<Vector3D>& newPositions, const std::vector<Vector3D>& newVelocities, const std::vector<Vector3D>& newForces); const std::vector<double>& ScalarDataAt(size_t idx) const; std::vector<double>& ScalarDataAt(size_t idx); const std::vector<Vector3D>& VectorDataAt(size_t idx) const; std::vector<Vector3D>& VectorDataAt(size_t idx); double GetParticleRadius() const; void SetParticleRadius(double newRadius); double GetParticleMass() const; virtual void SetParticleMass(double newMass); void BuildNeighborSearcher(double maxSearchRadius); void BuildNeighborLists(double maxSearchRadius); const std::shared_ptr<PointNeighborSearcher3> & GetNeighborSearcher() const; const std::vector<std::vector<size_t>>& GetNeighborLists() const; protected: size_t _positionIdx; size_t _velocityIdx; size_t _forceIdx; size_t _numberOfParticles = 0; double _radius = 1e-3; double _mass = 1e-3; std::vector<ScalarData> _scalarDataList; std::vector<VectorData> _vectorDataList; std::shared_ptr<PointNeighborSearcher3> _neighborSearcher; std::vector<std::vector<size_t>>_neighborLists; }; class ParticleSystemSolver3 : public PhysicsAnimation{ private: void timeStepStart(double timeStepInSeconds); void timeStepEnd(double timeStepInSeconds); void timeIntegration(double timeIntervalInSeconds); void resolveCollision(); void updateCollider(double timeStepInSeconds); void updateEmitter(double timeStepInSeconds); ParticleSystemData3::VectorData _newPositions; ParticleSystemData3::VectorData _newVelocities; protected: void onTimeStep(double timeIntervalInSeconds) override; virtual void onInitialize() override; //********************************************** //the function is called in ParticleSystemSolver3:timeStepStart(double); // Called when a time-step is about to begin; //********************************************** virtual void onTimeStepStart(double timeStepInSeconds); //********************************************** //the function is called in ParticleSystemSolver3:timeStepEnd(double); // Called when a time-step is about to end; //********************************************** virtual void onTimeStepEnd(double timeStepInSeconds); //********************************************** //the function is called in ParticleSystemSolver3:onTimeStep(double); //accumulate forces //********************************************** virtual void accumulateForces(double timeIntervalInSeconds); std::shared_ptr<ParticleSystemData3> _particleSystemData; std::shared_ptr<VectorField3> _wind; Vector3D _gravity = Vector3D(0.0, -9.8, 0.0); double _dragCoefficient = 1e-4; std::shared_ptr<Collider3> _collider; double _restitutionCoefficient = 0.0; std::shared_ptr<ParticleEmitter3> _emitter; };主要看粒子系统重写的onTimeStep函数,它用以更新粒子系统,它依次调用了5个函数。
accumulateForces用以累加作用于粒子上的力,timeIntegration用以更新粒子速度和位置.resolveCollision处理碰撞,timeStepStart,timeStepEnd分别用作每帧逻辑更新前后的事件调用以及内部数据更新
void ParticleSystemSolver3::onTimeStep(double timeIntervalInSeconds) { timeStepStart(timeIntervalInSeconds); accumulateForces(timeIntervalInSeconds); timeIntegration(timeIntervalInSeconds); resolveCollision(); timeStepEnd(timeIntervalInSeconds); }具体实现如下
void CalfFluidEngine::ParticleSystemSolver3::timeStepStart(double timeStepInSeconds) { auto& forces = _particleSystemData->GetForces(); tbb::parallel_for( tbb::blocked_range<size_t>(0, forces.size()), [&](const tbb::blocked_range<size_t> & b) { for (size_t i = b.begin(); i != b.end(); ++i) forces[i] = Vector3D::zero; }); updateCollider(timeStepInSeconds); updateEmitter(timeStepInSeconds); size_t n = _particleSystemData->GetNumberOfParticles(); _newPositions.resize(n); _newVelocities.resize(n); onTimeStepStart(timeStepInSeconds); } void CalfFluidEngine::ParticleSystemSolver3::accumulateForces(double timeIntervalInSeconds) { size_t n = _particleSystemData->GetNumberOfParticles(); auto& forces = _particleSystemData->GetForces(); auto& velocities = _particleSystemData->GetVelocities(); auto& positions = _particleSystemData->GetPositions(); const double mass = _particleSystemData->GetParticleMass(); tbb::parallel_for( tbb::blocked_range<size_t>(0, n), [&](const tbb::blocked_range<size_t> & b) { for (size_t i = b.begin(); i != b.end(); ++i){ // Gravity Vector3D force = mass * _gravity; // Wind forces Vector3D relativeVel = velocities[i] - _wind->Sample(positions[i]); force += -_dragCoefficient * relativeVel; forces[i] += force; } }); } void CalfFluidEngine::ParticleSystemSolver3::timeIntegration(double timeIntervalInSeconds) { size_t n = _particleSystemData->GetNumberOfParticles(); auto& forces = _particleSystemData->GetForces(); auto& velocities = _particleSystemData->GetVelocities(); auto& positions = _particleSystemData->GetPositions(); const double mass = _particleSystemData->GetParticleMass(); tbb::parallel_for( tbb::blocked_range<size_t>(0, n), [&](const tbb::blocked_range<size_t> & b) { for (size_t i = b.begin(); i != b.end(); ++i) { Vector3D& newVelocity = _newVelocities[i]; newVelocity = velocities[i]; newVelocity.AddScaledVector(forces[i] / mass, timeIntervalInSeconds); Vector3D& newPosition = _newPositions[i]; newPosition = positions[i]; newPosition.AddScaledVector(newVelocity, timeIntervalInSeconds); } }); } void CalfFluidEngine::ParticleSystemSolver3::resolveCollision() { if (_collider != nullptr) { size_t numberOfParticles = _particleSystemData->GetNumberOfParticles(); const double radius = _particleSystemData->GetParticleRadius(); tbb::parallel_for( tbb::blocked_range<size_t>(size_t(0), numberOfParticles), [&](const tbb::blocked_range<size_t> & b) { for (size_t i = b.begin(); i != b.end(); ++i) { _collider->ResolveCollision( radius, _restitutionCoefficient, &_newPositions[i], &_newVelocities[i]); } }); } } void CalfFluidEngine::ParticleSystemSolver3::timeStepEnd(double timeStepInSeconds) { size_t n = _particleSystemData->GetNumberOfParticles(); auto& positions = _particleSystemData->GetPositions(); auto& velocities = _particleSystemData->GetVelocities(); tbb::parallel_for( tbb::blocked_range<size_t>(0, n), [&](const tbb::blocked_range<size_t> & b) { for (size_t i = b.begin(); i != b.end(); ++i) { positions[i] = _newPositions[i]; velocities[i] = _newVelocities[i]; } }); onTimeStepEnd(timeStepInSeconds); } 碰撞检测和处理上一节我们提到了碰撞,这个需要特别列出一节来讲。