Пример #1
0
        private void CreateSprings(FluidParticle p)
        {
            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index >= neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                SpringHash hash = new SpringHash {
                    P0 = p, P1 = neighbour
                };

                if (!_springs.ContainsKey(hash))
                {
                    //TODO: Use pool?
                    Spring spring = new Spring(p, neighbour)
                    {
                        RestLength = (float)Math.Sqrt(q)
                    };
                    _springs.Add(hash, spring);
                }
            }
        }
Пример #2
0
        public void Update(float deltaTime)
        {
            if (deltaTime == 0)
            {
                return;
            }

            float deltaTime2 = 0.5f * deltaTime * deltaTime;

            ComputeNeighbours();
            ApplyForces();

            if (Definition.UseViscosity)
            {
                for (int i = 0; i < Particles.Count; ++i)
                {
                    FluidParticle p = Particles[i];
                    if (p.IsActive)
                    {
                        ApplyViscosity(p, deltaTime);
                    }
                }
            }

            for (int i = 0; i < Particles.Count; ++i)
            {
                FluidParticle p = Particles[i];
                if (p.IsActive)
                {
                    p.Update(deltaTime);
                }
            }

            for (int i = 0; i < Particles.Count; ++i)
            {
                FluidParticle p = Particles[i];
                if (p.IsActive)
                {
                    DoubleDensityRelaxation(p, deltaTime2);
                }
            }

            if (Definition.UsePlasticity)
            {
                for (int i = 0; i < Particles.Count; ++i)
                {
                    FluidParticle p = Particles[i];
                    if (p.IsActive)
                    {
                        CreateSprings(p);
                    }
                }
            }

            AdjustSprings(deltaTime);

            UpdateVelocities(deltaTime);
        }
Пример #3
0
        public FluidParticle AddParticle(Vector2 position)
        {
            FluidParticle particle = new FluidParticle(position)
            {
                Index = Particles.Count
            };

            Particles.Add(particle);
            return(particle);
        }
Пример #4
0
        public void Update(float timeStep)
        {
            _timeStep2 = 0.5f * timeStep * timeStep;

            ComputeNeighbours();
            ApplyForces();

            if (Definition.UseViscosity)
            {
                for (int i = 0; i < Particles.Count; ++i)
                {
                    FluidParticle p = Particles[i];
                    if (p.IsActive)
                    {
                        ApplyViscosity(p, timeStep);
                    }
                }
            }

            for (int i = 0; i < Particles.Count; ++i)
            {
                FluidParticle p = Particles[i];
                if (p.IsActive)
                {
                    p.Update(timeStep);
                }
            }

            for (int i = 0; i < Particles.Count; ++i)
            {
                FluidParticle p = Particles[i];
                if (p.IsActive)
                {
                    DoubleDensityRelaxation(p);
                }
            }

            if (Definition.UsePlasticity)
            {
                for (int i = 0; i < Particles.Count; ++i)
                {
                    FluidParticle p = Particles[i];
                    if (p.IsActive)
                    {
                        CreateSprings(p);
                    }
                }
            }

            AdjustSprings(timeStep);

            UpdateVelocities(timeStep);
        }
Пример #5
0
        private void ApplyViscosity(FluidParticle p, float timeStep)
        {
            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index >= neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                Vector2 direction;
                Vector2.Subtract(ref neighbour.Position, ref p.Position, out direction);

                if (direction.LengthSquared() < float.Epsilon)
                {
                    continue;
                }

                direction.Normalize();

                Vector2 deltaVelocity;
                Vector2.Subtract(ref p.Velocity, ref neighbour.Velocity, out deltaVelocity);

                float u;
                Vector2.Dot(ref deltaVelocity, ref direction, out u);

                if (u > 0.0f)
                {
                    q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                    float impulseFactor = 0.5f * timeStep * q * (u * (Definition.ViscositySigma + Definition.ViscosityBeta * u));

                    Vector2 impulse;

                    Vector2.Multiply(ref direction, -impulseFactor, out impulse);
                    p.ApplyImpulse(ref impulse);

                    Vector2.Multiply(ref direction, impulseFactor, out impulse);
                    neighbour.ApplyImpulse(ref impulse);
                }
            }
        }
Пример #6
0
        private void ApplyViscosity(FluidParticle p, float timeStep)
        {
            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index >= neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                Vector2 direction;
                Vector2.Subtract(ref neighbour.Position, ref p.Position, out direction);

                if (direction.LengthSquared() < float.Epsilon)
                {
                    continue;
                }

                direction.Normalize();

                Vector2 deltaVelocity;
                Vector2.Subtract(ref p.Velocity, ref neighbour.Velocity, out deltaVelocity);

                float u;
                Vector2.Dot(ref deltaVelocity, ref direction, out u);

                if (u > 0.0f)
                {
                    q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                    float impulseFactor = 0.5f * timeStep * q * (u * (Definition.ViscositySigma + Definition.ViscosityBeta * u));

                    Vector2 impulse;

                    Vector2.Multiply(ref direction, -impulseFactor, out impulse);
                    p.ApplyImpulse(ref impulse);

                    Vector2.Multiply(ref direction, impulseFactor, out impulse);
                    neighbour.ApplyImpulse(ref impulse);
                }
            }
        }
Пример #7
0
 public void Add(FluidParticle particle)
 {
     ulong key = HashKey(particle.Position);
     List<FluidParticle> bucket;
     if (!_hash.TryGetValue(key, out bucket))
     {
         if (_bucketPool.Count > 0)
         {
             bucket = _bucketPool.Pop();
         }
         else
         {
             bucket = new List<FluidParticle>();
         }
         _hash.Add(key, bucket);
     }
     bucket.Add(particle);
 }
Пример #8
0
 public void Add(FluidParticle particle)
 {
     ulong key = HashKey(particle.Position);
     List<FluidParticle> bucket;
     if (!_hash.TryGetValue(key, out bucket))
     {
         if (_bucketPool.Count > 0)
         {
             bucket = _bucketPool.Pop();
         }
         else
         {
             bucket = new List<FluidParticle>();
         }
         _hash.Add(key, bucket);
     }
     bucket.Add(particle);
 }
Пример #9
0
        private void ComputeNeighbours()
        {
            _hashGrid.GridSize = Definition.InfluenceRadius;
            _hashGrid.Clear();

            for (int i = 0; i < Particles.Count; ++i)
            {
                FluidParticle p = Particles[i];

                if (p.IsActive)
                {
                    _hashGrid.Add(p);
                }
            }

            for (int i = 0; i < Particles.Count; ++i)
            {
                FluidParticle p = Particles[i];
                p.Neighbours.Clear();
                _hashGrid.Find(ref p.Position, p.Neighbours);
            }
        }
Пример #10
0
        //private void DoubleDensityRelaxation1(FluidParticle p, float timeStep)
        //{
        //    _density = 0;
        //    _densityNear = 0;

        //    _len2 = p.Neighbours.Count;
        //    if (_len2 > MaxNeighbors)
        //        _len2 = MaxNeighbors;

        //    for (_j = 0; _j < _len2; _j++)
        //    {
        //        _q = Vector2.DistanceSquared(p.Position, p.Neighbours[_j].Position);
        //        _distanceCache[_j] = _q;
        //        if (_q < _influenceRadiusSquared && _q != 0)
        //        {
        //            _q = (float)Math.Sqrt(_q);
        //            _q /= Definition.InfluenceRadius;
        //            _qq = ((1 - _q) * (1 - _q));
        //            _density += _qq;
        //            _densityNear += _qq * (1 - _q);
        //        }
        //    }

        //    _pressure = Definition.Stiffness * (_density - Definition.DensityRest);
        //    _pressureNear = Definition.StiffnessNear * _densityNear;

        //    _dx = Vector2.Zero;

        //    for (_j = 0; _j < _len2; _j++)
        //    {
        //        _q = _distanceCache[_j];
        //        if (_q < _influenceRadiusSquared && _q != 0)
        //        {
        //            _q = (float)Math.Sqrt(_q);
        //            _rij = p.Neighbours[_j].Position;
        //            _rij -= p.Position;
        //            _rij *= 1 / _q;
        //            _q /= _influenceRadiusSquared;

        //            _d = ((timeStep * timeStep) * (_pressure * (1 - _q) + _pressureNear * (1 - _q) * (1 - _q)));
        //            _rij *= _d * 0.5f;
        //            p.Neighbours[_j].Position += _rij;
        //            _dx -= _rij;
        //        }
        //    }
        //    p.Position += _dx;
        //}

        private void DoubleDensityRelaxation(FluidParticle particle, float deltaTime2)
        {
            _density     = 0.0f;
            _densityNear = 0.0f;

            int neightborCount = particle.Neighbours.Count;

            if (neightborCount > MaxNeighbors)
            {
                neightborCount = MaxNeighbors;
            }

            for (int i = 0; i < neightborCount; ++i)
            {
                FluidParticle neighbour = particle.Neighbours[i];

                if (particle.Index == neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref particle.Position, ref neighbour.Position, out q);
                _distanceCache[i] = q;

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                float densityDelta = q * q;
                _density     += densityDelta;
                _densityNear += densityDelta * q;
            }

            _pressure     = Definition.Stiffness * (_density - Definition.DensityRest);
            _pressureNear = Definition.StiffnessNear * _densityNear;

            // For gameplay purposes
            particle.Density  = _density + _densityNear;
            particle.Pressure = _pressure + _pressureNear;

            Vector2 delta = Vector2.Zero;

            for (int i = 0; i < neightborCount; ++i)
            {
                FluidParticle neighbour = particle.Neighbours[i];

                if (particle.Index == neighbour.Index)
                {
                    continue;
                }

                float q = _distanceCache[i];

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                float dispFactor = deltaTime2 * (q * (_pressure + _pressureNear * q));

                Vector2 direction;
                Vector2.Subtract(ref neighbour.Position, ref particle.Position, out direction);

                if (direction.LengthSquared() < float.Epsilon)
                {
                    continue;
                }

                direction.Normalize();

                Vector2 disp;

                Vector2.Multiply(ref direction, dispFactor, out disp);
                Vector2.Add(ref neighbour.Position, ref disp, out neighbour.Position);

                Vector2.Multiply(ref direction, -dispFactor, out disp);
                Vector2.Add(ref delta, ref disp, out delta);
            }

            Vector2.Add(ref particle.Position, ref delta, out particle.Position);
        }
Пример #11
0
 public Spring(FluidParticle p0, FluidParticle p1)
 {
     Active = true;
     P0     = p0;
     P1     = p1;
 }
Пример #12
0
 public Spring(FluidParticle p0, FluidParticle p1)
 {
     Active = true;
     P0 = p0;
     P1 = p1;
 }
Пример #13
0
 public FluidParticle AddParticle(Vector2 p)
 {
     FluidParticle particle = new FluidParticle(p) { Index = Particles.Count };
     Particles.Add(particle);
     return particle;
 }
Пример #14
0
        private void CreateSprings(FluidParticle p)
        {
            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index >= neighbour.Index)
                    continue;

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                    continue;

                SpringHash hash = new SpringHash { P0 = p, P1 = neighbour };

                if (!_springs.ContainsKey(hash))
                {
                    //TODO: Use pool?
                    Spring spring = new Spring(p, neighbour) { RestLength = (float)Math.Sqrt(q) };
                    _springs.Add(hash, spring);
                }
            }
        }
Пример #15
0
        //private void DoubleDensityRelaxation1(FluidParticle p, float timeStep)
        //{
        //    _density = 0;
        //    _densityNear = 0;

        //    _len2 = p.Neighbours.Count;
        //    if (_len2 > MaxNeighbors)
        //        _len2 = MaxNeighbors;

        //    for (_j = 0; _j < _len2; _j++)
        //    {
        //        _q = Vector2.DistanceSquared(p.Position, p.Neighbours[_j].Position);
        //        _distanceCache[_j] = _q;
        //        if (_q < _influenceRadiusSquared && _q != 0)
        //        {
        //            _q = (float)Math.Sqrt(_q);
        //            _q /= Definition.InfluenceRadius;
        //            _qq = ((1 - _q) * (1 - _q));
        //            _density += _qq;
        //            _densityNear += _qq * (1 - _q);
        //        }
        //    }

        //    _pressure = Definition.Stiffness * (_density - Definition.DensityRest);
        //    _pressureNear = Definition.StiffnessNear * _densityNear;

        //    _dx = Vector2.Zero;

        //    for (_j = 0; _j < _len2; _j++)
        //    {
        //        _q = _distanceCache[_j];
        //        if (_q < _influenceRadiusSquared && _q != 0)
        //        {
        //            _q = (float)Math.Sqrt(_q);
        //            _rij = p.Neighbours[_j].Position;
        //            _rij -= p.Position;
        //            _rij *= 1 / _q;
        //            _q /= _influenceRadiusSquared;

        //            _d = ((timeStep * timeStep) * (_pressure * (1 - _q) + _pressureNear * (1 - _q) * (1 - _q)));
        //            _rij *= _d * 0.5f;
        //            p.Neighbours[_j].Position += _rij;
        //            _dx -= _rij;
        //        }
        //    }
        //    p.Position += _dx;
        //}

        private void DoubleDensityRelaxation(FluidParticle particle)
        {
            _density = 0.0f;
            _densityNear = 0.0f;

            int neightborCount = particle.Neighbours.Count;

            if (neightborCount > MaxNeighbors)
                neightborCount = MaxNeighbors;

            for (int i = 0; i < neightborCount; ++i)
            {
                FluidParticle neighbour = particle.Neighbours[i];

                if (particle.Index == neighbour.Index)
                    continue;

                float q;
                Vector2.DistanceSquared(ref particle.Position, ref neighbour.Position, out q);
                _distanceCache[i] = q;

                if (q > _influenceRadiusSquared)
                    continue;

                q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                float densityDelta = q * q;
                _density += densityDelta;
                _densityNear += densityDelta * q;
            }

            _pressure = Definition.Stiffness * (_density - Definition.DensityRest);
            _pressureNear = Definition.StiffnessNear * _densityNear;

            // For gameplay purposes
            particle.Density = _density + _densityNear;
            particle.Pressure = _pressure + _pressureNear;

            Vector2 delta = Vector2.Zero;

            for (int i = 0; i < neightborCount; ++i)
            {
                FluidParticle neighbour = particle.Neighbours[i];

                if (particle.Index == neighbour.Index)
                    continue;

                float q = _distanceCache[i];

                if (q > _influenceRadiusSquared)
                    continue;

                q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                float dispFactor = _timeStep2 * (q * (_pressure + _pressureNear * q));

                Vector2 direction;
                Vector2.Subtract(ref neighbour.Position, ref particle.Position, out direction);

                if (direction.LengthSquared() < float.Epsilon)
                    continue;

                direction.Normalize();

                Vector2 disp;

                Vector2.Multiply(ref direction, dispFactor, out disp);
                Vector2.Add(ref neighbour.Position, ref disp, out neighbour.Position);

                Vector2.Multiply(ref direction, -dispFactor, out disp);
                Vector2.Add(ref delta, ref disp, out delta);
            }

            Vector2.Add(ref particle.Position, ref delta, out particle.Position);
        }
Пример #16
0
        private void DoubleDensityRelaxation(FluidParticle p, float timeStep)
        {
            float density = 0.0f;
            float densityNear = 0.0f;

            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index == neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                float densityDelta = q * q;
                density += densityDelta;
                densityNear += densityDelta * q;
            }

            float pressure = Definition.Stiffness * (density - Definition.DensityRest);
            float pressureNear = Definition.StiffnessNear * densityNear;

            // For gameplay purposes
            p.Density = density + densityNear;
            p.Pressure = pressure + pressureNear;

            Vector2 delta = Vector2.Zero;

            for (int i = 0; i < p.Neighbours.Count; ++i)
            {
                FluidParticle neighbour = p.Neighbours[i];

                if (p.Index == neighbour.Index)
                {
                    continue;
                }

                float q;
                Vector2.DistanceSquared(ref p.Position, ref neighbour.Position, out q);

                if (q > _influenceRadiusSquared)
                {
                    continue;
                }

                q = 1.0f - (float)Math.Sqrt(q) / Definition.InfluenceRadius;

                float dispFactor = 0.5f * timeStep * timeStep * (q * (pressure + pressureNear * q));

                Vector2 direction;
                Vector2.Subtract(ref neighbour.Position, ref p.Position, out direction);

                if (direction.LengthSquared() < float.Epsilon)
                {
                    continue;
                }

                direction.Normalize();

                Vector2 disp;

                Vector2.Multiply(ref direction, dispFactor, out disp);
                Vector2.Add(ref neighbour.Position, ref disp, out neighbour.Position);

                Vector2.Multiply(ref direction, -dispFactor, out disp);
                Vector2.Add(ref delta, ref disp, out delta);
            }

            Vector2.Add(ref p.Position, ref delta, out p.Position);
        }