private void UpdateParticles(ref List <mParticle> particles, float dTime) { float r = Domain.xMax; float l = Domain.xMin; // Rectangle contains coordinates inverse on y float t = Domain.yMax; float b = Domain.yMin; for (int i = 0; i < particles.Count; i++) { mParticle particle = particles[i]; // Update velocity + position using forces particle.Update(dTime); // Clip positions to domain space if (particle.Position.x < l) { particle.Position.x = l + Constants.SmallEpsilon; } else if (particle.Position.x > r) { particle.Position.x = r - Constants.SmallEpsilon; } if (particle.Position.y < b) { particle.Position.y = b + Constants.SmallEpsilon; } else if (particle.Position.y > t) { particle.Position.y = t - Constants.SmallEpsilon; } // Reset force particle.Force = Vector2.zero; } }
public void Emit(ref List <mParticle> particles, double dTime) { if (this.Enabled) { // Calc particle count based on frequency time += dTime; int nParts = (int)(this.Frequency * time); if (nParts > 0) { // Create Particles for (int i = 0; i < nParts; i++) { // Calc velocity based on the distribution along the normalized direction float dist = UnityEngine.Random.value * Distribution - Distribution * 0.5f; Vector2 normal = new Vector2(Direction.y, -Direction.x); normal = normal * dist; Vector2 vel = Direction + normal; vel.Normalize(); float velLen = UnityEngine.Random.value * (this.VelocityMax - this.VelocityMin) + this.VelocityMin; vel = vel * velLen; // Calc Oldpos (for right velocity) using simple euler // oldPos = this.Position - vel * m_time; Vector2 oldPos = this.Position - vel * (float)time; mParticle p = new mParticle(); p.Position = Position; p.PositionOld = oldPos; p.Velocity = vel; p.Mass = ParticleMass; particles.Add(p); } // Reset time time = 0.0; } } }
public void GetNeighbourIndex(ref mParticle particle, out List <int> neighbours) { neighbours = null; int x_ori = GetGridIndexX(ref particle); int y_ori = GetGridIndexY(ref particle); for (int xOff = -1; xOff < 2; xOff++) { for (int yOff = -1; yOff < 2; yOff++) { // Own index // Neighbour index int x = x_ori + xOff; int y = y_ori + yOff; // Clamp if (x > -1 && x < this.Width && y > -1 && y < this.Height) { if (m_grid[x] != null) { List <int> idxList = m_grid[x][y]; if (idxList != null) { // Return neighbours index neighbours.AddRange(idxList); return; } } } } } }
public void Refresh(ref List <mParticle> particles) { m_p = particles; m_grid = null; m_grid = new List <int> [Width][]; for (int i = 0; i < neightbors.Length; i++) { neightbors[i].Clear(); } if (particles != null) { for (int i = 0; i < particles.Count; i++) { mParticle p = particles[i]; int gridIndexX = GetGridIndexX(ref p); int gridIndexY = GetGridIndexY(ref p); p.grid_index = new Vector2(gridIndexX, gridIndexY); // Add particle to list if (m_grid[gridIndexX] == null) { m_grid[gridIndexX] = new List <int> [Height]; } if (m_grid[gridIndexX][gridIndexY] == null) { m_grid[gridIndexX][gridIndexY] = new List <int>(); } m_grid[gridIndexX][gridIndexY].Add(i); } } for (int i = 0; i < particles.Count; i++) { for (int xOff = -1; xOff < 2; xOff++) { for (int yOff = -1; yOff < 2; yOff++) { int x = (int)particles[i].grid_index.x + xOff; int y = (int)particles[i].grid_index.y + yOff; // Clamp if (x > -1 && x < this.Width && y > -1 && y < this.Height) { if (m_grid[x] != null) { List <int> idxList = m_grid[x][y]; if (idxList != null) { // Return neighbours index neightbors[i].AddRange(idxList); } } } } } } }
private int GetGridIndexY(ref mParticle particle) { int gridIndexY = (int)((particle.Position.y - Constants.SimulationDomain.yMin) / CellSpace); // Clamp Y if (gridIndexY < 0) { gridIndexY = 0; } if (gridIndexY >= Height) { gridIndexY = Height - 1; } return(gridIndexY); }
private int GetGridIndexX(ref mParticle particle) { int gridIndexX = (int)((particle.Position.x - Constants.SimulationDomain.xMin) / CellSpace); // Clamp X if (gridIndexX < 0) { gridIndexX = 0; } if (gridIndexX >= Width) { gridIndexX = Width - 1; } return(gridIndexX); }
private void NoOverlapParticles(ref List <mParticle> particles, ref Grid grid) { float minDist = .5f * CellSpace; float minDistSq = minDist * minDist; Vector2 dist; List <int> list; int nIdx; for (int i = 0; i < particles.Count; i++) { mParticle p = particles[i]; list = grid.GetNeighbourIndex(p, i); for (int j = 0; j < list.Count; j++) { nIdx = list[j]; mParticle pn = particles[nIdx]; if (p != pn) { dist = pn.Position - p.Position; float distLenSq = dist.sqrMagnitude; if (distLenSq < minDistSq) { if (distLenSq > Constants.SmallEpsilon) { 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.PositionOld.y -= diff; p.Position.x += diff; p.PositionOld.y += diff; } } } } } }
public static List <mParticle> Create(int nParticles, float cellSpace, Rect domain, float particleMass) { List <mParticle> particles = new List <mParticle>(nParticles); // Init. Particle positions float x0 = domain.x + cellSpace; float x = x0; float y = domain.y; for (int i = 0; i < nParticles; i++) { if (x == x0) { y += cellSpace; } Vector2 pos = new Vector2(x, y); mParticle p = new mParticle(); p.Position = pos; p.PositionOld = pos; p.Mass = particleMass; particles.Add(p); x = x + cellSpace < domain.width ? x + cellSpace : x0; } return(particles); }
private void Forces(ref List <mParticle> particles, ref Grid grid, Vector2 globalForce) { Vector2 f, dist; float scalar; List <int> list; int nIdx; for (int i = 0; i < particles.Count; i++) { mParticle p = particles[i]; // Add global force to every particle p.Force += globalForce; list = grid.GetNeighbourIndex(p, i); for (int j = 0; j < list.Count; j++) { nIdx = list[j]; if (nIdx < i) { mParticle pn = particles[nIdx]; if (pn.Density > Constants.SmallEpsilon && p != pn) { dist = p.Position - pn.Position; // pressure 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; // viscosity // f = particles[nIdx].Mass * ((particles[nIdx].Velocity - particles[i].Velocity) / particles[nIdx].Density) * WViscosityLap(ref dist) * Constants.VISC0SITY; /* * scalar = pn.Mass * this.SKViscosity.CalculateLaplacian(ref dist) * Viscosity * 1 / pn.Density; +f = pn.Velocity - p.Velocity; +f = f * scalar; +p.Force += f; +pn.Force -= f;*/ Vector2 velA = p.Velocity; float dist2 = dist.sqrMagnitude; if (dist2 < CellSpace2) { // Particles are near enough to exchange velocity. float length = Mathf.Sqrt(dist2); Vector2 sepDir = dist / length; Vector2 velB = pn.Velocity; Vector2 velDiff = velA - velB; float velSep = Vector2.Dot(velDiff, sepDir); if (velSep < 0.0f) { // Particles are approaching. float infl = 1.0f - length / CellSpace; float velSepA = Vector2.Dot(velA, sepDir); // vel of pcl A along sep dir. float velSepB = Vector2.Dot(velB, sepDir); // vel of pcl B along sep dir. float velSepTarget = (velSepA + velSepB) * 0.5f; // target vel along sep dir. float diffSepA = velSepTarget - velSepA; // Diff btw A's vel and target. float changeSepA = Viscosity * diffSepA * infl; // Amount of vel change to appl Vector2 changeA = changeSepA * sepDir; // Velocity change to apply. p.Force += (changeA - Constants.Friction * p.Velocity) * p.Mass; // Apply velocity change to A. pn.Force -= (changeA - Constants.Friction * p.Velocity) * p.Mass; // Apply commensurate change to B. } } } } } } }
public List <int> GetNeighbourIndex(mParticle particle, int index) { return(neightbors[index]); }