示例#1
0
        void solveCollision(float dt)
        {
            // This function detects particles which are crossing boundary of bodies
            // and modifies velocities of them so that they will move just in front of
            // boundary. This function function also applies the reaction force to
            // bodies as precisely as the numerical stability is kept.
            FluidAABB aabb = new FluidAABB();

            aabb.lowerBound.x = +float.MaxValue;
            aabb.lowerBound.y = +float.MaxValue;
            aabb.upperBound.x = -float.MaxValue;
            aabb.upperBound.y = -float.MaxValue;
            for (int i = 0; i < count; i++)
            {
                FluidParticle fp = particleBuffer [i];
                Vector2       p1 = fp.position;
                Vector2       p2 = p1 + dt * fp.velocity;
                aabb.lowerBound = Vector2.Min(aabb.lowerBound, Vector2.Min(p1, p2));
                aabb.upperBound = Vector2.Max(aabb.upperBound, Vector2.Max(p1, p2));
            }

            SolveCollisionCallback callback = new SolveCollisionCallback(this, dt);

            queryAABB(callback, aabb);
        }
示例#2
0
        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;
                }
            }
        }
        public override void computeDistance(FluidParticle fp, out float distance, out Vector2 normal)
        {
            Vector2 center = new Vector2(transform.position.x, transform.position.y) + circle.offset;
            Vector2 d      = fp.position - center;
            float   d1     = d.magnitude;

            distance = d1 - radius;
            normal   = d / d1;
        }
示例#4
0
        public void destroyParticle(FluidParticle fp, bool callDestructionListener)
        {
            FluidParticleType flags = FluidParticleType.ZombieParticle;

            if (callDestructionListener)
            {
                flags |= FluidParticleType.DestructionListenerParticle;
            }
            setParticleFlags(fp, fp.flags | flags);
        }
示例#5
0
 void solveWall()
 {
     for (int i = 0; i < count; i++)
     {
         FluidParticle fp = particleBuffer [i];
         if ((fp.flags & FluidParticleType.WallParticle) > 0)
         {
             fp.velocity = Vector2.zero;
         }
     }
 }
示例#6
0
        void solveForce(float dt)
        {
            float velocityPerForce = dt * getParticleInvMass();

            for (int i = 0; i < count; i++)
            {
                FluidParticle fp = particleBuffer [i];
                fp.velocity += velocityPerForce * fp.force;
            }
            hasForce = false;
        }
示例#7
0
        void setParticleFlags(FluidParticle fp, FluidParticleType newFlags)
        {
            if ((fp.flags & ~newFlags) > 0)
            {
                needsUpdateAllParticleFlags = true;
            }

            if ((~allParticleFlags & newFlags) > 0)
            {
                allParticleFlags |= newFlags;
            }
            fp.flags = newFlags;
        }
示例#8
0
            public override void reportFixtureAndParticle(FluidFixtureShape fixture, FluidParticle fp)
            {
                //Rigidbody2D body = fixture.GetComponent<Rigidbody2D> ();
                Vector2 ap  = fp.position;
                Vector2 av  = fp.velocity;
                Ray2D   ray = new Ray2D();

                //RaycastHit2D hit;
                if (fluidSystem.iterationIndex == 0)
                {
                    //					// Put 'ap' in the local space of the previous frame
                    //					b2Vec2 p1 = b2MulT(body->m_xf0, ap);
                    //					if (fixture->GetShape()->GetType() == b2Shape::e_circle)
                    //					{
                    //						// Make relative to the center of the circle
                    //						p1 -= body->GetLocalCenter();
                    //						// Re-apply rotation about the center of the
                    //						// circle
                    //						p1 = b2Mul(body->m_xf0.q, p1);
                    //						// Subtract rotation of the current frame
                    //						p1 = b2MulT(body->m_xf.q, p1);
                    //						// Return to local space
                    //						p1 += body->GetLocalCenter();
                    //					}
                    //					// Return to global space and apply rotation of current frame
                    //					input.p1 = b2Mul(body->m_xf, p1);
                    ray.origin = fp.prevPosition;
                }
                else
                {
                    ray.origin = ap;
                }
                ray.direction = av;

                //hit = Physics2D.Raycast (ray.origin, ray.direction, av.magnitude * dt);
                Physics2D.Raycast(ray.origin, ray.direction, av.magnitude * dt);
                //if (hit) {
                //					b2Vec2 p =
                //						(1 - output.fraction) * input.p1 +
                //							output.fraction * input.p2 +
                //							b2_linearSlop * n;
                //Vector2 v = (hit.point - ap) / dt;
                //				fp.velocity = v;
                //Vector2 f = fluidSystem.getParticleMass () * (av - v);
                //				fluidSystem.particleApplyForce(fp, f);
                //}
            }
示例#9
0
            public override void reportFixtureAndParticle(FluidFixtureShape fixture, FluidParticle fp)
            {
                float   d;
                Vector2 n;

                fixture.computeDistance(fp, out d, out n);
                if ((d < fluidSystem.particleDiameter) &&
                    ((fp.flags & FluidParticleType.WallParticle) == 0))
                {
                    Rigidbody2D b = fixture.GetComponent <Rigidbody2D> ();
                    //Vector2 bp = b.transform.position;
                    float bm = b.mass;

                    //				b2Vec2 bp = b->GetWorldCenter();
                    //				float32 bI =
                    //				b->GetInertia() - bm * b->GetLocalCenter().LengthSquared();
                    float invBm = bm > 0 ? 1 / bm : 0;
                    //				float32 invBI = bI > 0 ? 1 / bI : 0;
                    float invAm = (fp.flags & FluidParticleType.WallParticle) > 0 ? 0 : fluidSystem.getParticleInvMass();
                    //Vector2 rp = fp.position - bp;
                    //				float rpn = rp * n;
                    //				float32 rpn = b2Cross(rp, n);
                    //				float32 invM = invAm + invBm + invBI * rpn * rpn;
                    float invM = invAm + invBm;

                    FluidParticleBodyContact contact = new FluidParticleBodyContact
                    {
                        fp      = fp,
                        body    = b,
                        fixture = fixture,
                        weight  = 1 - d * fluidSystem.inverseDiameter,
                        normal  = -n,
                        mass    = invM > 0 ? 1 / invM : 0
                    };

                    if (fixture.isTrigger())
                    {
                        fluidSystem.triggerContactBuffer.Add(contact);
                        fixture.notifyOnTrigger(contact);
                    }
                    else
                    {
                        fluidSystem.bodyContactBuffer.Add(contact);
                    }
                    //				m_system->DetectStuckParticle(a);
                }
            }
示例#10
0
//		void OnGUI () {
//			GUI.Label (new Rect (10, 50, 100, 100), count + "");
//
////		for (int i=0;i<count;i++) {
////			Handles.Label(proxyBuffer[i].fp.position, i+"");
////		}
//		}

#if UNITY_EDITOR && FLUID_DEBUG
        void OnDrawGizmos()
        {
            if (proxyBuffer != null && count > 0)
            {
                int i = 0;
                foreach (FluidProxy proxy in proxyBuffer)
                {
                    FluidParticle fp = proxy.fp;
                    Handles.color = fp.color;

                    //Handles.DrawSolidDisc(new Vector3 (fp.position.x, fp.position.y, 0), Vector3.back, 0.05f);
                    //Handles.DotCap (0, fp.position, Quaternion.identity, 0.05f);
                    //Handles.DrawLine(fp.position,fp.position + fp.velocity * 0.1f);
                    Handles.Label(fp.position, (int)fp.temperature + "");
                }
            }
        }
示例#11
0
        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;
            }
        }
示例#12
0
        public FluidParticle createParticle(FluidParticleDef def)
        {
            if (count >= fluidSystemDef.maxCount)
            {
                return(null);
            }
            count++;

            FluidParticle fp = new FluidParticle();

            particleBuffer.Add(fp);
            setParticleFlags(fp, def.flags);
            fp.position            = def.position;
            fp.prevPosition        = def.position;
            fp.velocity            = def.velocity;
            fp.weight              = 0;
            fp.force               = Vector2.zero;
            fp.mass                = def.mass;
            fp.staticPressure      = 0;
            fp.depth               = 0;
            fp.color               = def.color;
            fp.foamColor           = def.foamColor;
            fp.foamWeightThreshold = def.foamWeightThreshold;
            fp.temperature         = def.temperature;
            fp.freezingTemperature = def.freezingTemperature;
            fp.boilingTemperature  = def.boilingTemperature;

            FluidProxy proxy = new FluidProxy();

            proxyBuffer.Add(proxy);
            proxy.fp = fp;

//		bool finiteLifetime = def.lifetime > 0;
//		if (m_expirationTimeBuffer.data || finiteLifetime)
//		{
//			SetParticleLifetime(index, finiteLifetime ? def.lifetime :
//			                    ExpirationTimeToLifetime(
//				-GetQuantizedTimeElapsed()));
//			// Add a reference to the newly added particle to the end of the
//			// queue.
//			m_indexByExpirationTimeBuffer.data[index] = index;
//		}

            return(fp);
        }
示例#13
0
        public override void computeDistance(FluidParticle fp, out float distance, out Vector2 normal)
        {
            bool onEdge = computeDistance(vertices, fp.position, out distance, out normal);

            if (onEdge)
            {
                float dot = Vector2.Dot(normals [0], normal);
                if (Mathf.Approximately(dot, -1f))
                {
                    if (distance < scaledWidth)
                    {
                        distance = -distance;
                        normal   = normals [0];
                    }
                    else
                    {
                        distance -= scaledWidth;
                    }
                }
            }
        }
示例#14
0
        public override void computeDistance(FluidParticle fp, out float distance, out Vector2 normal)
        {
            Vector2 p                    = fp.position;
            float   maxDistance          = -float.MaxValue;
            Vector2 normalForMaxDistance = p;

            for (int i = 0; i < vertices.Length; i++)
            {
                float dot = Vector2.Dot(normals [i], p - vertices [i]);
                if (dot > maxDistance)
                {
                    maxDistance          = dot;
                    normalForMaxDistance = normals [i];
                }
            }

            if (maxDistance > 0)
            {
                Vector2 minDistance  = normalForMaxDistance;
                float   minDistance2 = maxDistance * maxDistance;
                for (int i = 0; i < vertices.Length; i++)
                {
                    Vector2 dist  = p - vertices [i];
                    float   dist2 = dist.sqrMagnitude;
                    if (minDistance2 > dist2)
                    {
                        minDistance  = dist;
                        minDistance2 = dist2;
                    }
                }

                distance = Mathf.Sqrt(minDistance2);
                normal   = minDistance.normalized;
            }
            else
            {
                distance = maxDistance;
                normal   = normalForMaxDistance;
            }
        }
示例#15
0
        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;
                    }
                }
            }
        }
示例#16
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;
                }
            }
        }
 public abstract void reportFixtureAndParticle(FluidFixtureShape fixture, FluidParticle fp);
示例#18
0
        void solve(float dt)
        {
            if (count == 0)
            {
                return;
            }
//		if (m_expirationTimeBuffer.data)
//		{
//			SolveLifetimes(step);
//		}
            if ((allParticleFlags & FluidParticleType.ZombieParticle) > 0)
            {
                solveZombie();
            }
            if (needsUpdateAllParticleFlags)
            {
                updateAllParticleFlags();
            }
//		if (m_needsUpdateAllGroupFlags)
//		{
//			UpdateAllGroupFlags();
//		}
            if (paused)
            {
                return;
            }

            float subStep = dt / particleIterations;

            for (iterationIndex = 0; iterationIndex < particleIterations; iterationIndex++)
            {
                ++timestamp;
                updateContacts(false);
                updateBodyContacts();
                computeWeight();
//			if (m_allGroupFlags & b2_particleGroupNeedsUpdateDepth)
//			{
//				ComputeDepth();
//			}
//			if (m_allParticleFlags & b2_reactiveParticle)
//			{
//				UpdatePairsAndTriadsWithReactiveParticles();
//			}
                if (hasForce)
                {
                    solveForce(subStep);
                }
                if ((allParticleFlags & FluidParticleType.ViscousParticle) > 0)
                {
                    solveViscous();
                }
//			if (m_allParticleFlags & b2_repulsiveParticle)
//			{
//				SolveRepulsive(subStep);
//			}
                if ((allParticleFlags & FluidParticleType.PowderParticle) > 0)
                {
                    solvePowder(subStep);
                }
                if ((allParticleFlags & FluidParticleType.TensileParticle) > 0)
                {
                    solveTensile(subStep);
                }
//			if (m_allGroupFlags & b2_solidParticleGroup)
//			{
//				SolveSolid(subStep);
//			}
                if ((allParticleFlags & FluidParticleType.ColorMixingParticle) > 0)
                {
                    solveColorMixing();
                }
                solveGravity(subStep);
                if ((allParticleFlags & FluidParticleType.StaticPressureParticle) > 0)
                {
                    solveStaticPressure(subStep);
                }
                solvePressure(subStep);
                solveDamping(subStep);
//			if (m_allParticleFlags & k_extraDampingFlags)
//			{
//				SolveExtraDamping();
//			}
//			// SolveElastic and SolveSpring refer the current velocities for
//			// numerical stability, they should be called as late as possible.
//			if (m_allParticleFlags & b2_elasticParticle)
//			{
//				SolveElastic(subStep);
//			}
//			if (m_allParticleFlags & b2_springParticle)
//			{
//				SolveSpring(subStep);
//			}
                limitVelocity(subStep);
//			if (m_allGroupFlags & b2_rigidParticleGroup)
//			{
//				SolveRigidDamping();
//			}
//			if (m_allParticleFlags & b2_barrierParticle)
//			{
//				SolveBarrier(subStep);
//			}
//			// SolveCollision, SolveRigid and SolveWall should be called after
//			// other force functions because they may require particles to have
//			// specific velocities.
//			solveCollision(subStep);
//			if (m_allGroupFlags & b2_rigidParticleGroup)
//			{
//				SolveRigid(subStep);
//			}
                if ((allParticleFlags & FluidParticleType.WallParticle) > 0)
                {
                    solveWall();
                }

//			if (iterationIndex == 0) {
//				for (int i=0; i<count; i++) {
//					FluidParticle fp = particleBuffer [i];
//					fp.prevPosition = fp.position;
//				}
//			}

                for (int i = 0; i < count; i++)
                {
                    FluidParticle fp = particleBuffer [i];
                    fp.prevPosition = fp.position;
                    fp.position    += subStep * fp.velocity;
                }
            }
        }
示例#19
0
 public abstract void computeDistance(FluidParticle fp, out float distance, out Vector2 normal);
示例#20
0
 public void particleApplyForce(FluidParticle fp, Vector2 force)
 {
     prepareForceBuffer();
     fp.force += force;
 }