Inheritance: MonoBehaviour
Exemple #1
0
 public IEnumerable GetNeighbourIndex(FluidParticle particle)
 {
     for (int xOff = -1; xOff < 2; xOff++)
     {
         for (int yOff = -1; yOff < 2; yOff++)
         {
             // Own index
             // Neighbour index
             int x = GetGridIndexX(ref particle) + xOff;
             int y = GetGridIndexY(ref particle) + yOff;
             // Clamp
             if (x > -1 && x < this.Width && y > -1 && y < this.Height)
             {
                 if (m_grid[x] != null)
                 {
                     if (m_grid[x][y] != null)
                     {
                         ArrayList idxList = (ArrayList)m_grid[x][y].Clone();
                         if (idxList != null)
                         {
                             // Return neighbours index
                             foreach (int idx in m_grid[x][y])
                             {
                                 yield return(idx);
                             }
                             idxList.Clear();
                         }
                     }
                 }
             }
         }
     }
 }
Exemple #2
0
    Vector3 calcPressure(FluidParticle p)
    {
        //calcWeight = p.CalcMatrixValue;
        //calcResult = p.calcRightSideValue;

        //A = SparseMatrix.Create(p.nearbyParticles.Length-1, p.nearbyParticles.Length-1, calcWeight);
        //B = Vector<double>.Build.Dense(p.nearbyParticles.Length-1, calcResult);
        //X = Vector<double>.Build.Dense(p.nearbyParticles.Length);
        //X = Solve(A, B, X);
        //X = A.Solve(B);

        /* calcWeight = p.CalcMatrixValue2;
         * calcResult = p.calcRightSideValue2;
         * A = SparseMatrix.Create(p.nearbyParticles.Length-1, p.nearbyParticles.Length, calcWeight);
         * B = Vector<double>.Build.Dense(p.nearbyParticles.Length-1, calcResult);
         */// = Vector<double>.Build.Dense(p.nearbyParticles.Length);

        //X = A.SolveIterative(B, new BiCgStab());
        Vector3 result = new Vector3();

        for (int i = 1; i < p.nearbyParticles.Length; i++)
        {
            temp   = p.nearbyParticles[i].Pos() - p.Pos();
            result = resultP + ((float)(((X.At(p.nearbyParticles[i].ID) - X.At(p.ID)) / Mathf.Pow(temp.magnitude, 2) * p.weights[i])) * temp);
        }

        result = result * (float)(3d / p.defaultParticleDensity);


        return(result);
    }
Exemple #3
0
    /*Go through all the Blobs, and travel from the center outwards in a negative Z direction
     * until we reach the surface, then begin to recurse around the surface. This isn't flawless
     * if the blob isn't completely within the lattice boundaries in the minimal Z axis and no
     * other blob that does check out is in contact with it. The blob will dissapear, but otherwise
     * works well*/
    private void march()
    {
        int i, jx, jy, jz;

        for (i = 0; i < this.GetComponent <FluidBehaviour>().Particles.Count; i++)
        {
            FluidParticle pb = this.GetComponent <FluidBehaviour>().Particles[i];
            jx = (int)((pb.Position.x + .5f) * dimX);
            jy = (int)((pb.Position.y + .5f) * dimY);
            jz = (int)((pb.Position.z + .5f) * dimZ);


            while (jz >= 0)
            {
                mcCube cube = getCube(jx, jy, jz);
                if (cube != null && cube.cntr < pctr)
                {
                    cube.cntr = pctr;
                    if (doCube(cube))
                    {
                        recurseCube(cube);
                        jz = -1;
                    }
                }
                else
                {
                    jz = -1;
                }
                jz -= 1;
            }
        }
    }
    // Start is called before the first frame update
    public void Initialze()
    {
        size      = (int)((resolution.x) * (resolution.y) * (resolution.z));
        particles = new FluidParticle[size];
        int x = 0, y = 0, z = 0;

        for (int i = 0; i < size; i++)
        {
            particles[i]          = new FluidParticle();
            particles[i].position = new Vector3(x, y, z);
            x++;
            if (x % resolution.x == 0)
            {
                x = 0;
                y++;
                if (y % resolution.y == 0)
                {
                    y = 0;
                    z++;
                    if (z % resolution.z == 0)
                    {
                        z = 0;
                    }
                }
            }
        }
    }
Exemple #5
0
        /// <summary>
        /// Sets initial particles
        /// </summary>
        /// <returns></returns>
        public static List <FluidParticle> InitSPH()
        {
            var particles = new List <FluidParticle>();

            var xStart = 5;
            var yStart = 9;

            var columns = 5;
            var rows    = 5;

            for (int i = 0; i < columns; i++)
            {
                for (int j = 0; j < rows; j++)
                {
                    FluidParticle particle;

                    // Adds a bit of jitter to allow particles to flow out
                    if (j % 2 == 0)
                    {
                        particle = new FluidParticle(xStart + i + 0.3f, yStart - j);
                        particles.Add(particle);
                    }
                    else
                    {
                        particle = new FluidParticle(xStart + i, yStart - j);
                        particles.Add(particle);
                    }
                }
            }

            return(particles);
        }
        void Update()
        {
            if (m_Rigidbodies == null)
            {
                return;
            }

            if (!fluid.isPlaying && !m_Paused)
            {
                m_Paused = true;

                int l = Mathf.Min(m_Rigidbodies.Length, fluid.particleCount);

                for (int i = 0; i < l; ++i)
                {
                    // Get objects
                    Rigidbody2D   body     = m_Rigidbodies[i];
                    FluidParticle particle = fluid.GetParticle(i);

                    body.transform.position = particle.position;
                    body.velocity           = Vector3.zero;
                    body.isKinematic        = true;
                    body.Sleep();
                }
            }
            else if (fluid.isPlaying && m_Paused)
            {
                m_Paused = false;
            }
        }
Exemple #7
0
    public static ArrayList Create(int nParticles, float cellSpace, Rect domain, float particleMass)
    {
        ArrayList particles = new ArrayList(nParticles);
        float     x0        = domain.x + cellSpace;
        float     x         = x0;
        float     y         = domain.y;
        float     z         = domain.width;
        float     z0        = domain.width + cellSpace;
        float     z0m       = -domain.width + cellSpace;

        for (int i = 0; i < nParticles; i++)
        {
            if (x == x0)
            {
                y += cellSpace;
            }

            if (z == z0 || z == z0m)
            {
                x += cellSpace;
            }

            Vector3       pos = new Vector3(x, y, z);
            FluidParticle p   = new FluidParticle();
            p.Position    = pos;
            p.PositionOld = pos;
            p.Mass        = particleMass;
            particles.Add(p);
            x = x + cellSpace < domain.width ? x + cellSpace : x0;
        }
        return(particles);
    }
Exemple #8
0
 public void GetNeighbourIndex(ref FluidParticle particle, out ArrayList neighbours)
 {
     neighbours = null;
     for (int xOff = -1; xOff < 2; xOff++)
     {
         for (int yOff = -1; yOff < 2; yOff++)
         {
             // Own index
             // Neighbour index
             int x = GetGridIndexX(ref particle) + xOff;
             int y = GetGridIndexY(ref particle) + yOff;
             // Clamp
             if (x > -1 && x < this.Width && y > -1 && y < this.Height)
             {
                 if (m_grid[x] != null)
                 {
                     ArrayList idxList = m_grid[x][y];
                     if (idxList != null)
                     {
                         // Return neighbours index
                         neighbours = (ArrayList)idxList.Clone();
                         return;
                     }
                 }
             }
         }
     }
 }
Exemple #9
0
    public void Refresh(ref ArrayList particles)
    {
        m_grid = null;
        m_grid = new ArrayList[Width][];

        if (particles != null)
        {
            for (int i = 0; i < particles.Count; i++)
            {
                FluidParticle p          = (FluidParticle)particles[i];
                int           gridIndexX = GetGridIndexX(ref p);
                int           gridIndexY = GetGridIndexY(ref p);


                if (m_grid[gridIndexX] == null)
                {
                    m_grid[gridIndexX] = new ArrayList[Height];
                }

                if (m_grid[gridIndexX][gridIndexY] == null)
                {
                    m_grid[gridIndexX][gridIndexY] = new ArrayList();
                }
                m_grid[gridIndexX][gridIndexY].Add(i);
            }
        }
    }
    public void ShootFluidParticle(Transform transform)
    {
        FluidParticle p = new FluidParticle(
            transform.TransformPoint(new Vector3(0, 0, 0.5f)) + new Vector3(0, 0.5f, 0),
            transform.forward * ParticleVelocityScaling,
            random);

        newParticles.Add(p);
    }
    private float DerivativeCSum(FluidParticle p, List <FluidParticle> neigbours)
    {
        float sum = 0;

        foreach (FluidParticle neighbour in neigbours)
        {
            // Use  the derivative of the spiky kernel.
            float derivative = SpikyDerivative(p, neighbour);
            sum += Mathf.Pow(derivative, 2);
        }
        return(sum + RelaxationConstant);
    }
    private float StdSPHDensityEstimator(FluidParticle p, List <FluidParticle> neighbours)
    {
        float pi = 0;

        foreach (FluidParticle neighbour in neighbours)
        {
            // Use the Poly6 kernel
            pi += (315f / 64 * Mathf.PI * Mathf.Pow(NeighbourDistance, 4))
                  * Mathf.Pow(Mathf.Pow(NeighbourDistance, 2) - Mathf.Pow(Vector3.Distance(p.PredictedPosition, neighbour.PredictedPosition), 2), 3);
        }
        return(pi);
    }
    void Init()
    {
        switch (ParticleNum)
        {
        case NumParticlesSet.NUM_8K:
            _numParticles = NUM_PARTICLES_8K;
            break;

        case NumParticlesSet.NUM_16K:
            _numParticles = NUM_PARTICLES_16K;
            break;

        case NumParticlesSet.NUM_32K:
            _numParticles = NUM_PARTICLES_32K;
            break;

        case NumParticlesSet.NUM_64K:
            _numParticles = NUM_PARTICLES_64K;
            break;

        default:
            _numParticles = 64;
            break;
        }

        Debug.Log("numParticles : " + _numParticles);

        _particlesBuffer = new ComputeBuffer(_numParticles, Marshal.SizeOf(typeof(FluidParticle)));
        int startingWidth = (int)Mathf.Sqrt((float)_numParticles);

        var particles = new FluidParticle[_numParticles];

        for (int i = 0; i < _numParticles; i++)
        {
            particles[i].Velocity = Vector3.zero;
            particles[i].Position = _containerCenter + Random.insideUnitSphere * ballRadius;
        }
        _particlesBuffer.SetData(particles);

        _sortedParticlesBuffer = new ComputeBuffer(_numParticles, Marshal.SizeOf(typeof(FluidParticle)));
        _particleForcesBuffer  = new ComputeBuffer(_numParticles, Marshal.SizeOf(typeof(FluidParticleForces)));
        _particleDensityBuffer = new ComputeBuffer(_numParticles, Marshal.SizeOf(typeof(FluidParticleDensity)));

        _gridBuffer         = new ComputeBuffer(_numParticles, Marshal.SizeOf(typeof(Uint2)));
        _gridPingPongBuffer = new ComputeBuffer(_numParticles, Marshal.SizeOf(typeof(Uint2)));

        _gridIndicesBuffer = new ComputeBuffer(NUM_GRID_INDICES, Marshal.SizeOf(typeof(Uint2)));

        particles = null;
    }
Exemple #14
0
    private int GetGridIndexY(ref FluidParticle particle)
    {
        int gridIndexY = (int)(particle.Position.y / CellSpace);

        // Clamp Y
        if (gridIndexY < 0)
        {
            gridIndexY = 0;
        }
        if (gridIndexY >= Height)
        {
            gridIndexY = Height - 1;
        }
        return(gridIndexY);
    }
Exemple #15
0
    private int GetGridIndexX(ref FluidParticle particle)
    {
        int gridIndexX = (int)(particle.Position.x / CellSpace);

        // Clamp X
        if (gridIndexX < 0)
        {
            gridIndexX = 0;
        }
        if (gridIndexX >= Width)
        {
            gridIndexX = Width - 1;
        }
        return(gridIndexX);
    }
Exemple #16
0
        /*Calculate the power of a point only if it hasn't been calculated already for this frame*/
        public float i()
        {
            float pwr;

            if (cntr < mcblob.pctr)
            {
                cntr = mcblob.pctr;
                pwr  = 0f;
                for (int jc = 0; jc < this.mcblob.GetComponent <FluidBehaviour>().Particles.Count; jc++)
                {
                    FluidParticle pb = this.mcblob.GetComponent <FluidBehaviour>().Particles[jc];
                    pwr += (1.0f / Mathf.Sqrt(((pb.Position.x - this.x) * (pb.Position.x - this.x)) + ((pb.Position.y - this.y) * (pb.Position.y - this.y)) + ((pb.Position.z - this.z) * (pb.Position.z - this.z)))) * MCBlob.POWER;
                }
                this._i = pwr;
            }
            return(this._i);
        }
Exemple #17
0
    private void UpdateParticles(ref ArrayList particles, float dTime)
    {
        float r = Domain.xMax;
        float l = Domain.x;
        float t = Domain.yMax;
        float b = Domain.y;

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

            if (particle.Position.x < l)
            {
                particle.Position.x = l + Mathf.Epsilon;
            }
            else if (particle.Position.x > r)
            {
                particle.Position.x = r - Mathf.Epsilon;
            }


            if (particle.Position.y < b)
            {
                particle.Position.y = b + Mathf.Epsilon;
            }
            else if (particle.Position.y > t)
            {
                particle.Position.y = t - Mathf.Epsilon;
            }

            if (particle.Position.z < -1)
            {
                particle.Position.z = particle.Position.z + 0.0005f;
            }
            else if (particle.Position.z > 1.5)
            {
                particle.Position.z = particle.Position.z - 0.0005f;
            }

            // Update velocity + position using forces
            particle.Update(dTime);
            // Reset force
            particle.Force = Vector2.zero;
        }
    }
Exemple #18
0
    private void CheckParticleDistance(ref ArrayList particles, ref IndexGrid grid)
    {
        float minDist   = 0.5f * CellSpace;
        float minDistSq = minDist * minDist;

        Vector3 dist;

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

            foreach (int nIdx in grid.GetNeighbourIndex(p))
            {
                FluidParticle pn = (FluidParticle)particles[nIdx];

                if (p != pn)
                {
                    dist = pn.Position - p.Position;
                    float distLenSq = dist.sqrMagnitude;

                    if (distLenSq < minDistSq)
                    {
                        if (distLenSq > Mathf.Epsilon)
                        {
                            float distLen = (float)Math.Sqrt((double)distLenSq);
                            dist           = dist * 0.5f * (distLen - minDist) / distLen;
                            pn.Position    = pn.Position - dist;
                            pn.PositionOld = pn.PositionOld - dist;
                            p.Position     = p.Position + dist;
                            p.PositionOld  = p.PositionOld + dist;
                        }
                        else
                        {
                            float diff = 0.5f * minDist;
                            pn.Position.x   -= diff;
                            pn.Position.y   -= diff;
                            p.Position.x    += diff;
                            p.PositionOld.y += diff;
                        }
                    }
                }
            }
        }
    }
        void InitResources()
        {
            _particlesBufferRead    = new ComputeBuffer((int)_numParticles, Marshal.SizeOf(typeof(FluidParticle)));
            _particlesBufferWrite   = new ComputeBuffer((int)_numParticles, Marshal.SizeOf(typeof(FluidParticle)));
            _particlesForceBuffer   = new ComputeBuffer((int)_numParticles, Marshal.SizeOf(typeof(FluidParticleForces)));
            _particlesDensityBuffer = new ComputeBuffer((int)_numParticles, Marshal.SizeOf(typeof(FluidParticleDensity)));

            FluidParticle[] particles = new FluidParticle[_numParticles];

            for (var i = 0; i < _numParticles; i++)
            {
                particles[i].Position = Random.insideUnitSphere * 0.01f;
                particles[i].Velocity = Vector3.zero;
            }

            _particlesBufferRead.SetData(particles);
            _particlesBufferWrite.SetData(particles);

            particles = null;
        }
Exemple #20
0
    /* Normals are calculated by 'averaging' all the derivatives of the Blob power functions*/
    private Vector3 calcNormal(Vector3 pnt)
    {
        int     jc;
        Vector3 result = tada[tadac++];

        result.x = 0; result.y = 0; result.z = 0;
        for (jc = 0; jc < this.GetComponent <FluidBehaviour>().Particles.Count; jc++)
        {
            FluidParticle pb = this.GetComponent <FluidBehaviour>().Particles[jc];

            Vector3 current = tada[tadac++];
            current.x = pnt.x - pb.Position.x;
            current.y = pnt.y - pb.Position.y;
            current.z = pnt.z - pb.Position.z;
            float mag = current.magnitude;
            float pwr = .5f * (1f / (mag * mag * mag)) * MCBlob.POWER;
            result = result + (current * pwr);
        }
        return(result.normalized);
    }
        void OnPreSolve(FluvioTimeStep timeStep)
        {
            if (m_Rigidbodies == null)
            {
                return;
            }

            int l = Mathf.Min(m_Rigidbodies.Length, fluid.particleCount);

            for (int i = 0; i < l; ++i)
            {
                // Get objects
                Rigidbody2D      body     = m_Rigidbodies[i];
                CircleCollider2D collider = m_Colliders[i];
                FluidParticle    particle = fluid.GetParticle(i);

                // Assign properties
                body.gameObject.SetActive(particle.enabled);

                if (body.isKinematic)
                {
                    body.isKinematic = false;
                }

                body.mass          = fluid.particleMass * m_MassModifier;
                body.interpolation = m_RigidbodyInterpolation;

                collider.radius         = fluid.smoothingDistance * m_ColliderSizeModifier;
                collider.sharedMaterial = m_PhysicMaterial;

                if (particle.lifetime < 1.0f)
                {
                    // Send physics information to particles (collisions)
                    particle.position = body.transform.position;
                    particle.velocity = body.velocity * timeStep.dt;

                    // Assign particle
                    fluid.SetParticle(ref particle, i);
                }
            }
        }
        void OnPostSolve(FluvioTimeStep timeStep)
        {
            if (m_Rigidbodies == null)
            {
                return;
            }

            int l = Mathf.Min(m_Rigidbodies.Length, fluid.particleCount);

            for (int i = 0; i < l; ++i)
            {
                // Get objects
                Rigidbody2D   body     = m_Rigidbodies[i];
                FluidParticle particle = fluid.GetParticle(i);

                if (body.isKinematic)
                {
                    body.isKinematic = false;
                }
                body.transform.position = particle.position;
                body.velocity           = particle.velocity * timeStep.inv_dt;
            }
        }
    public void Emit(ref ArrayList particles, double dTime)
    {
        if (this.Enabled)
        {
            m_time += dTime;
            int nParts = (int)(this.Frequency * m_time);

            if (nParts > 0)
            {
                for (int i = 0; i < nParts; i++)
                {
                    float   dist   = UnityEngine.Random.value * Distribution - Distribution * 0.5f;
                    Vector3 normal = new Vector3(Direction.y, -Direction.x, Direction.z);
                    normal = normal * dist;

                    Vector3 vel  = Direction + normal;
                    Vector3 vel3 = new Vector3(vel.x, vel.z, vel.y);
                    vel3.Normalize();

                    vel = new Vector3(vel3.x, vel3.y, vel3.z);

                    float velLen = UnityEngine.Random.value * (this.VelocityMax - this.VelocityMin) + this.VelocityMin;
                    vel = vel * velLen;

                    Vector3 oldPos = this.Position - vel * (float)m_time;

                    FluidParticle f = new FluidParticle();
                    f.Position    = Position;
                    f.PositionOld = oldPos;
                    f.Velocity    = vel;
                    f.Mass        = ParticleMass;
                    particles.Add(f);
                }
                m_time = 0.0;
            }
        }
    }
Exemple #24
0
    private void CalculateForces(ref ArrayList particles, ref IndexGrid grid, Vector3 globalForce)
    {
        Vector3 f, dist;
        float   scalar;

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

            foreach (int nIdx in grid.GetNeighbourIndex(p))
            {
                if (nIdx < i)
                {
                    FluidParticle pn = (FluidParticle)particles[nIdx];

                    if (pn.Density > Mathf.Epsilon && p != pn)
                    {
                        dist = p.Position - pn.Position;

                        scalar    = pn.Mass * (p.Pressure + pn.Pressure) / (2.0f * pn.Density);
                        f         = SKPressure.CalculateGradient(ref dist);
                        f         = f * scalar;
                        p.Force  -= f;
                        pn.Force += f;

                        scalar    = pn.Mass * (float)this.SKViscosity.CalculateLaplacian(ref dist) * Viscosity * 1 / pn.Density;
                        f         = pn.Velocity - p.Velocity;
                        f         = f * scalar;
                        p.Force  += f;
                        pn.Force -= f;
                    }
                }
            }
        }
    }
Exemple #25
0
    void OnPostSolve(FluvioTimeStep timeStep)
    {
        if (sleep)
        {
            sleep = false;
            return;
        }

        fluid.GetParticles(ref particles);

#if !(UNITY_IPHONE || UNITY_ANDROID) || UNITY_EDITOR
        bool doTouch = !requireClick ? true : (Input.GetMouseButton(0) || Input.GetMouseButton(1));
        if (doTouch)
        {
            if (Input.GetMouseButton(0) || !requireClick)
            {
                touchMode = invert ? TouchMode.Push : TouchMode.Pull;
            }
            else
            {
                touchMode = invert ? TouchMode.Pull : TouchMode.Push;
            }
            Vector3 point = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, z));
            float   f     = (int)touchMode * force;
            for (int i = 0; i < particles.Length; i++)
            {
                FluidParticle p = particles[i];

                if (!p.enabled)
                {
                    continue;
                }

                float dist = (p.position - point).sqrMagnitude;
                if (dist <= maxDistance * maxDistance)
                {
                    p.AddForce((point - p.position).normalized * f);
                }

                particles[i] = p;
            }
        }
#else
        foreach (Touch t in Input.touches)
        {
            Vector3 point = Camera.main.ScreenToWorldPoint(new Vector3(t.position.x, t.position.y, z));
            float   f     = force * (int)touchMode / (Input.touchCount * .5f);
            for (int i = 0; i < particles.Length; i++)
            {
                FluidParticle p = particles[i];

                if (!p.enabled)
                {
                    continue;
                }

                float dist = (p.position - point).sqrMagnitude;
                if (dist <= maxDistance * maxDistance)
                {
                    p.AddForce((point - p.position).normalized * f);
                }

                particles[i] = p;
            }
        }
#endif
        fluid.SetParticles(particles, particles.Length);
    }
 private float SpikyDerivative(FluidParticle p1, FluidParticle p2)
 {
     return(45 * Mathf.Pow(NeighbourDistance, 6) / Mathf.PI
            * Mathf.Pow(NeighbourDistance - Vector3.Distance(p1.PredictedPosition, p2.PredictedPosition), 2));
 }
Exemple #27
0
 private float CalculateViscosity(FluidParticle particle, float f)
 {
     throw new NotImplementedException();
 }
    void FixedUpdate()
    {
        // Remove all particles that have fallen too low, have expired or hit fire
        if (RemoveExpiredParticles)
        {
            Particles.RemoveAll(p => p.ToBeRemoved || (p.Position.y < -1) || p.Expiry <= 0);
        }
        else
        {
            Particles.RemoveAll(p => p.ToBeRemoved || (p.Position.y < -1));
        }

        // Add new particles
        Particles.AddRange(newParticles);
        newParticles.Clear();

        int newParticleCount = Particles.Count;

        if (newParticleCount != particleCount)
        {
            particleCount = newParticleCount;
            Debug.Log(particleCount + " fluid particles.");
        }

        // Predict the positions of the particles
        // Lines 1-4 from the algorithm in the paper
        foreach (FluidParticle p in Particles)
        {
            // Apply gravity
            p.Velocity -= Gravity;

            Vector3    newPosition = p.Position + p.Velocity;
            RaycastHit hit         = new RaycastHit();
            if (Physics.Linecast(p.Position, newPosition + ParticleDiameter * (newPosition - p.Position).normalized, out hit))
            {
                if (hit.normal.y != 0)
                {
                    p.Velocity += Gravity;
                }
                p.Velocity  = Vector3.Reflect(p.Velocity * ParticleElasticity, hit.normal);
                newPosition = p.Position + p.Velocity;

                FireCell fireCell = hit.collider.GetComponent <FireCell>();
                if (fireCell != null)
                {
                    fireCell.Water();
                    p.ToBeRemoved = true;
                }
            }
            p.PredictedPosition = newPosition;
        }

        // Find neighbours of each particle
        // Lines 5-7 from the algorithm in the paper
        List <FluidParticle>[] neighbours = new List <FluidParticle> [Particles.Count];
        for (int i = 0; i < Particles.Count; i++)
        {
            FluidParticle p = Particles[i];
            p.Index = i;
            List <FluidParticle> foundNeighbours = new List <FluidParticle>();
            foreach (FluidParticle potentialNeighbour in Particles)
            {
                if (potentialNeighbour != p && Vector3.Distance(potentialNeighbour.Position, p.Position) < NeighbourDistance)
                {
                    foundNeighbours.Add(potentialNeighbour);
                }
            }
            neighbours[i] = foundNeighbours;
        }

        float[]   lambdas  = new float[Particles.Count];
        Vector3[] deltaPos = new Vector3[Particles.Count];

        // Refine the predicted positions by taking incompressibilty into account
        // Lines 8-19 from the algorithm in the paper
        for (int iteration = 0; iteration < SolverIterations; iteration++)
        {
            // Find lambda for each particle
            // Lines 9-11 from the algorithm in the paper
            for (int i = 0; i < Particles.Count; i++)
            {
                FluidParticle        p = Particles[i];
                List <FluidParticle> foundNeighbours = neighbours[i];
                float pi        = StdSPHDensityEstimator(p, foundNeighbours);
                float c         = pi / RestDensity - 1;
                float deltaCSum = DerivativeCSum(p, foundNeighbours);
                lambdas[i] = -c / deltaCSum;
            }

            // Find more finely predicted positions
            // Lines 12-15 from the algorithm in the paper
            for (int i = 0; i < Particles.Count; i++)
            {
                FluidParticle        p = Particles[i];
                List <FluidParticle> foundNeighbours = neighbours[i];
                deltaPos[i] = Vector3.zero;
                foreach (FluidParticle neigbour in foundNeighbours)
                {
                    deltaPos[i] += (lambdas[i] + lambdas[neigbour.Index]) * Vector3.Normalize(p.PredictedPosition - neigbour.Position) * SpikyDerivative(p, neigbour);
                }
                deltaPos[i] = 1 / RestDensity * deltaPos[i];
                Vector3 newPosition = p.PredictedPosition + deltaPos[i];
                if (Physics.Linecast(p.PredictedPosition, newPosition + ParticleDiameter * (newPosition - p.Position).normalized))
                {
                    deltaPos[i] = Vector3.zero;
                }
            }

            // Use the new positions
            // Lines 16-18 from the algorithm in the paper
            for (int i = 0; i < Particles.Count; i++)
            {
                FluidParticle p = Particles[i];
                p.PredictedPosition += deltaPos[i];
            }
        }

        // Actually set the new positions and count down the expiry of the particles.
        foreach (FluidParticle p in Particles)
        {
            p.Velocity = p.PredictedPosition - p.Position;
            p.Position = p.PredictedPosition;
            p.Expiry--;
        }
    }