示例#1
0
    public void calcNearByParticles(RoiParticle particle, ref List <RoiParticle> nearParticles)
    {
        nearParticles.Clear();
        Vector2 gridIndex = toGridIndex(particle.position);

        // search for near particles in 9x9 grid
        for (int i = (int)gridIndex.x - 1; i <= gridIndex.x + 1; i++)
        {
            for (int j = (int)gridIndex.y - 1; j <= gridIndex.y + 1; j++)
            {
                // sanity check: we are not outside the simulation bounds
                if (i < 0 || j < 0 || i > xCells || j > yCells)
                {
                    continue;
                }

                int key = toKey(i, j);
                if (hashMap.ContainsKey(key))
                {
                    List <RoiParticle> _paticles = hashMap[key];
                    for (var k = 0; k < _paticles.Count; k++)
                    {
                        var d = (particle.position - _paticles[k].position).sqrMagnitude;
                        if (d < this.squaredSupportRadius && d > 0)  // if within support radius, add
                        {
                            nearParticles.Add(_paticles[k]);
                        }
                    }
                }
            }
        }
    }
示例#2
0
    public void emitParticles(float deltaTime, List <RoiParticle> particles,
                              ObjectPooler <RoiParticle> objectPooler, int maxParticles)
    {
        // acumulate time till we exceed frequency
        timer = timer + deltaTime;
        float period = 1.0f / frequency;

        if (timer > period)
        {
            // get current emit angle
            if (angularVelocity == 0)
            {
                // if not angle velocity, just use emit angle
                currentAngle = emitAngle;
            }
            else
            {
                // if we have angle velocity, ignore emit angle, and rotate by angular velocity.
                currentAngle += angularVelocity;
            }

            // get base velocity and color of emitting particle
            Vector2 velocity = Utils.getVector2(strength, currentAngle);
            Vector2 perpendicularVelocity = new Vector2(-velocity.y, velocity.x).normalized;
            float   a = velocityRandomness * 0.01f;

            for (var j = -1; j <= 1; j++)
            {
                Vector2 pos = (Vector2)_transform.position + 0.04f * j * perpendicularVelocity;

                if (particles.Count < maxParticles)
                {
                    RoiParticle roiParticle = objectPooler.GetObject();
                    roiParticle.Update(
                        pos,
                        new Vector2(velocity.x + Random.Range(-a, a), velocity.y + Random.Range(-a, a)),
                        particleSize,
                        fluidColor
                        );
                    particles.Add(roiParticle);
                }
                else
                {
                    break;
                }
            }

            // reset timer, instead of zero take difference
            timer = timer - period;
        }
    }
示例#3
0
    private void FixedUpdate()
    {
        float deltaTime = Time.fixedDeltaTime;

        removeOutOfBoundsParticles();         // remove out of bound particles
        spatialHash.updateGrid(roiParticles);

        // change speed of simulation
        deltaTime = deltaTime * timeScale;

        // update the number of particles
        numberOfParticles = roiParticles.Count;

        if (numberOfParticles > _nearParticles.Length)
        {
            setUpNearParticlesArray();
        }

        for (int i = 0; i < numberOfParticles; i++)
        {
            RoiParticle iParticle = roiParticles[i];
            if (!iParticle.isNew)
            {
                // apply prediction relaxation scheme
                // section 3.0 of the paper - "Particle-based Viscoelastic Fluid Simulation"
                iParticle.velocity = (iParticle.position - iParticle.originalPosition) / deltaTime;
            }
            iParticle.isNew = false;

            // apply gravity
            iParticle.velocity = new Vector2(iParticle.velocity.x, iParticle.velocity.y - this.gravity * deltaTime);
            spatialHash.calcNearByParticles(iParticle, ref _nearParticles[i]);

            applyViscosity(iParticle, deltaTime, _nearParticles[i]);
        }

        for (int i = 0; i < numberOfParticles; i++)
        {
            RoiParticle iParticle = roiParticles[i];
            // save the original particle position, then apply velocity.
            iParticle.originalPosition = iParticle.position;
            iParticle.position         = iParticle.position + iParticle.velocity * deltaTime;
        }

        if (enableDensityRelaxation)
        {
            doubleDensityRelaxation(deltaTime, _nearParticles);
        }
    }
示例#4
0
    //-------------------------------------------------------------------------------------
    // APPLY DOUBLE DENSITY RELAXATION
    // section 4 of the paper - "Particle-based Viscoelastic Fluid Simulation"
    // Simon Clavet, Philippe Beaudoin, and Pierre Poulin
    // ------------------------------------------------------------------------------------
    private void doubleDensityRelaxation(float deltaTime, List <RoiParticle>[] nearParticles)
    {
        for (int i = 0; i < numberOfParticles; i++)
        {
            RoiParticle        iParticle      = roiParticles[i];
            List <RoiParticle> iNearParticles = nearParticles[i];

            float density     = 0;
            float nearDensity = 0;

            for (int j = 0; j < iNearParticles.Count; j++)
            {
                float r = (iParticle.position - iNearParticles[j].position).magnitude;
                if (r <= 0 || r > particleRadius)
                {
                    continue;
                }

                float q = 1 - (r / particleRadius);
                density     += q * q;
                nearDensity += q * q * q;
            }

            float   pressure       = stiffness * (density - restDensity);
            float   nearPressure   = nearStiffness * nearDensity;
            Vector2 iFinalPosition = Vector2.zero;

            for (int j = 0; j < iNearParticles.Count; j++)
            {
                Vector2 dp = (iParticle.position - iNearParticles[j].position);
                float   r  = dp.magnitude;
                if (r <= 0 || r > particleRadius)
                {
                    continue;
                }

                float   q       = 1 - (r / particleRadius);
                float   Dij     = deltaTime * deltaTime * (pressure * q + nearPressure * q * q) * 0.5f;
                Vector2 finalDp = (Dij / r) * dp;

                iNearParticles[j].position += finalDp;
                iFinalPosition             -= finalDp;
            }
            iParticle.position += iFinalPosition;
        }
    }
示例#5
0
    //-------------------------------------------------------------------------------------
    // APPLY VISCOSITY
    // section 5.3 of the paper - "Particle-based Viscoelastic Fluid Simulation"
    // Simon Clavet, Philippe Beaudoin, and Pierre Poulin
    // ------------------------------------------------------------------------------------
    // Some modifications are done which is inspired from,
    // https://github.com/Erkaman/gl-water2d
    private void applyViscosity(RoiParticle iParticle, float deltaTime, List <RoiParticle> nearParticles)
    {
        for (int j = 0; j < nearParticles.Count; j++)
        {
            RoiParticle jParticle = nearParticles[j];

            Vector2 dp      = iParticle.position - jParticle.position;
            float   r       = dp.magnitude;
            Vector2 dp_norm = dp / r;

            if (r <= 0 || r > particleRadius)
            {
                continue;
            }

            float u          = Vector2.Dot(iParticle.velocity - jParticle.velocity, dp_norm);
            float I_div2_mag = 0;
            if (u > 0)
            {
                I_div2_mag = deltaTime * (1 - (r / particleRadius)) * (sigma * u + beta * u * u) * 0.5f;
                if (I_div2_mag > u)
                {
                    I_div2_mag = u;
                }
            }
            else
            {
                I_div2_mag = deltaTime * (1 - (r / particleRadius)) * (sigma * u - beta * u * u) * 0.5f;
                if (I_div2_mag < u)
                {
                    I_div2_mag = u;
                }
            }
            iParticle.velocity = iParticle.velocity - I_div2_mag * dp_norm;
            jParticle.velocity = jParticle.velocity + I_div2_mag * dp_norm;
        }
    }