void solveColorMixing() { float strength = fluidSystemDef.colorMixingStrength; if (strength > 0) { for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; if ((contact.a.flags & contact.b.flags & FluidParticleType.ColorMixingParticle) > 0) { Color a = contact.a.color; Color b = contact.b.color; float dr = (b.r - a.r) * strength; float dg = (b.g - a.g) * strength; float db = (b.b - a.b) * strength; float da = (b.a - a.a) * strength; a.r += dr; a.g += dg; a.b += db; a.a += da; b.r -= dr; b.g -= dg; b.b -= db; b.a -= da; contact.a.color = a; contact.b.color = b; float dm = (contact.b.mass - contact.a.mass) * strength; contact.a.mass += dm; contact.b.mass -= dm; } } } }
void solveViscous() { float viscousStrength = fluidSystemDef.viscousStrength; for (int i = 0; i < bodyContactBuffer.Count; i++) { FluidParticleBodyContact contact = bodyContactBuffer [i]; if ((contact.fp.flags & FluidParticleType.ViscousParticle) > 0) { // b2Vec2 v = b->GetLinearVelocityFromWorldPoint(p) - // m_velocityBuffer.data[a]; Vector2 v = contact.body.velocity - contact.fp.velocity; Vector2 f = viscousStrength * contact.mass * contact.weight * v; contact.fp.velocity += getParticleInvMass() * f; // b->ApplyLinearImpulse(-f, p, true); } } for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; if ((contact.flags & FluidParticleType.ViscousParticle) > 0) { Vector2 v = contact.b.velocity - contact.a.velocity; Vector2 f = viscousStrength * contact.weight * v; contact.a.velocity += f; contact.b.velocity -= f; } } }
void solveDamping(float dt) { // reduces normal velocity of each contact float linearDamping = fluidSystemDef.dampingStrength; float quadraticDamping = 1 / getCriticalVelocity(dt); for (int i = 0; i < bodyContactBuffer.Count; i++) { FluidParticleBodyContact contact = bodyContactBuffer [i]; FluidParticle a = contact.fp; Vector2 p = a.position; Vector2 v = contact.body.velocity - a.velocity; float vn = Vector2.Dot(v, contact.normal); if (vn < 0) { float damping = Mathf.Max(linearDamping * contact.weight, Mathf.Min(-quadraticDamping * vn, 0.5f)); Vector2 f = damping * contact.mass * vn * contact.normal; a.velocity += getParticleInvMass() * f; contact.body.AddForceAtPosition(-f / dt, p); } } for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; Vector2 v = contact.b.velocity - contact.a.velocity; float vn = Vector2.Dot(v, contact.normal); if (vn < 0) { float damping = Mathf.Max(linearDamping * contact.weight, Mathf.Min(-quadraticDamping * vn, 0.5f)); Vector2 f = damping * vn * contact.normal; contact.a.velocity += f; contact.b.velocity -= f; } } }
void addContact(FluidParticle a, FluidParticle b) { Vector2 d = b.position - a.position; float distBtParticlesSq = d.sqrMagnitude; if (distBtParticlesSq < squaredDiameter) { float dist = Mathf.Sqrt(distBtParticlesSq); FluidParticleContact contact = new FluidParticleContact(); contactBuffer.Add(contact); contact.a = a; contact.b = b; contact.flags = a.flags | b.flags; contact.weight = 1 - dist * inverseDiameter; // * (b.mass / a.mass); contact.normal = d / dist; } }
void computeWeight() { for (int i = 0; i < count; i++) { particleBuffer [i].weight = 0; } for (int i = 0; i < bodyContactBuffer.Count; i++) { FluidParticleBodyContact contact = bodyContactBuffer [i]; contact.fp.weight += contact.weight; } for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; contact.a.weight += contact.weight; contact.b.weight += contact.weight; } }
void solvePowder(float dt) { float powderStrength = fluidSystemDef.powderStrength * getCriticalVelocity(dt); float minWeight = 1.0f - particleStride; for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; if ((contact.flags & FluidParticleType.PowderParticle) > 0) { if (contact.weight > minWeight) { Vector2 f = powderStrength * (contact.weight - minWeight) * contact.normal; contact.a.velocity -= f; contact.b.velocity += f; } } } }
void solveTensile(float dt) { for (int i = 0; i < count; i++) { particleBuffer [i].accumulation2 = Vector2.zero; } for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; if ((contact.flags & FluidParticleType.TensileParticle) > 0) { Vector2 weightedNormal = (1 - contact.weight) * contact.weight * contact.normal; contact.a.accumulation2 -= weightedNormal; contact.b.accumulation2 += weightedNormal; } } float criticalVelocity = getCriticalVelocity(dt); float pressureStrength = fluidSystemDef.surfaceTensionPressureStrength * criticalVelocity; float normalStrength = fluidSystemDef.surfaceTensionNormalStrength * criticalVelocity; float maxVelocityVariation = maxParticleForce * criticalVelocity; for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; if ((contact.flags & FluidParticleType.TensileParticle) > 0) { float h = contact.a.weight + contact.b.weight; Vector2 s = contact.b.accumulation2 - contact.a.accumulation2; float fn = Mathf.Min( pressureStrength * (h - 2) + normalStrength * Vector2.Dot(s, contact.normal), maxVelocityVariation ) * contact.weight; Vector2 f = fn * contact.normal; contact.a.velocity -= f; contact.b.velocity += f; } } }
void solveStaticPressure(float dt) { float criticalPressure = getCriticalPressure(dt); float pressurePerWeight = fluidSystemDef.staticPressureStrength * criticalPressure; float maxPressure = maxParticlePressure * criticalPressure; float relaxation = fluidSystemDef.staticPressureRelaxation; for (int t = 0; t < fluidSystemDef.staticPressureIterations; t++) { for (int i = 0; i < count; i++) { particleBuffer [i].accumulation = 0; } for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; if ((contact.flags & FluidParticleType.StaticPressureParticle) > 0) { contact.a.accumulation += contact.weight * contact.b.staticPressure; contact.b.accumulation += contact.weight * contact.a.staticPressure; } } for (int i = 0; i < count; i++) { FluidParticle fp = particleBuffer [i]; if ((fp.flags & FluidParticleType.StaticPressureParticle) > 0) { float h = (fp.accumulation + pressurePerWeight * (fp.weight - minParticleWeight)) / (fp.weight + relaxation); fp.staticPressure = Mathf.Clamp(h, 0.0f, maxPressure); } else { fp.staticPressure = 0; } } } }
void solvePressure(float dt) { // calculates pressure as a linear function of density float criticalPressure = getCriticalPressure(dt); float pressurePerWeight = fluidSystemDef.pressureStrength * criticalPressure; float maxPressure = maxParticlePressure * criticalPressure; for (int i = 0; i < count; i++) { FluidParticle fp = particleBuffer [i]; float h = pressurePerWeight * Mathf.Max(0f, fp.weight - minParticleWeight); fp.accumulation = Mathf.Min(h, maxPressure); } // // ignores particles which have their own repulsive force // if (m_allParticleFlags & k_noPressureFlags) // { // for (int32 i = 0; i < m_count; i++) // { // if (m_flagsBuffer.data[i] & k_noPressureFlags) // { // m_accumulationBuffer[i] = 0; // } // } // } // static pressure if ((allParticleFlags & FluidParticleType.StaticPressureParticle) > 0) { for (int i = 0; i < count; i++) { FluidParticle fp = particleBuffer [i]; if ((fp.flags & FluidParticleType.StaticPressureParticle) > 0) { fp.accumulation += fp.staticPressure; } } } // applies pressure between each particles in contact float velocityPerPressure = dt / (fluidSystemDef.density * particleDiameter); for (int i = 0; i < bodyContactBuffer.Count; i++) { FluidParticleBodyContact contact = bodyContactBuffer [i]; FluidParticle a = contact.fp; Rigidbody2D b = contact.body; Vector2 p = a.position; float h = a.accumulation + pressurePerWeight * contact.weight; Vector2 f = velocityPerPressure * contact.weight * contact.mass * h * contact.normal; a.velocity -= getParticleInvMass() * f; b.AddForceAtPosition(f / dt, p); } float strength = fluidSystemDef.temperaturMixingStrength; for (int i = 0; i < contactBuffer.Count; i++) { FluidParticleContact contact = contactBuffer [i]; FluidParticle a = contact.a; FluidParticle b = contact.b; float h = a.accumulation + b.accumulation; Vector2 f = velocityPerPressure * contact.weight * h * contact.normal; a.velocity -= f; b.velocity += f; float t = (b.temperature - a.temperature) * strength; a.temperature += t; b.temperature -= t; if (Mathf.Abs(a.mass - b.mass) >= 0.01f) { if (b.mass < a.mass) { a = contact.b; b = contact.a; } a.velocity.y += fluidSystemDef.densityStrength; b.velocity.y -= fluidSystemDef.densityStrength; } else if (Mathf.Abs(a.temperature - b.temperature) >= 0.1f) { if (b.temperature > a.temperature) { a = contact.b; b = contact.a; } a.velocity.y += fluidSystemDef.temperatureStrength; b.velocity.y -= fluidSystemDef.temperatureStrength; } } }