How can i make my particles act more like a fluid

61 views Asked by At

I am trying to create a fluid simulation using sph in javascript i have finally calculated everything so the particles receive a force but the force doesnt seem to work properly and just pushes the particles away from each other randomly because when i add gravity it just goes to to mayhem

My result ideally would be without gravity the particles are evenly distributed without clumps and massive gaps and with gravity it should not explode and flow back and forth

var canvas = document.getElementById("canvas");
var c = canvas.getContext("2d");
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 100;
var simMinWidth = 20.0;
var cScale = Math.min(canvas.width, canvas.height) / simMinWidth;
var simWidth = canvas.width / cScale;
var simHeight = canvas.height / cScale;
var numParticles = 100;
var radius = 0.2;
var pressuremultiplier = 10
var restdensity = 1

function cX(position) {
  return position.x * cScale;
}

function cY(position) {
  return position.y * cScale;
}

class Particle {
  constructor(x, y) {
    this.position = new Vector(x, y)
    this.velocity = new Vector(0, 0);
    this.radius = radius;
    this.smoothinglength = 6 * radius
    this.density = 1
    this.pressure = 1
    this.pressureforce = 1
    this.mass = 1
  }
  updateAcceleration() {
    this.calculatedensity(fluidSimulator.particles)
    this.calculatepressure()
    this.calculatepressureforce(fluidSimulator.particles);
    this.acceleration = (this.pressureforce.divScalar(this.density)).add(fluidSimulator.gravity);

  }
  checkboundarys() {
    if (this.position.x - this.radius < 0.0) {
      this.position.x = 0.0 + this.radius;
      this.velocity.x = -fluidSimulator.collisionDamping * this.velocity.x;
    }

    if (this.position.x + this.radius > simWidth) {
      this.position.x = simWidth - this.radius;
      this.velocity.x = -fluidSimulator.collisionDamping * this.velocity.x;
    }

    if (this.position.y - this.radius < 0.0) {
      this.position.y = 0.0 + this.radius;
      this.velocity.y = -fluidSimulator.collisionDamping * this.velocity.y;
    }

    if (this.position.y + this.radius > simHeight) {
      this.position.y = simHeight - this.radius; // Adjusted this line
      this.velocity.y = -fluidSimulator.collisionDamping * this.velocity.y;
    }
  }
  calculatedensity(nearbyparticles) {
    let density = 0;
    for (let cparticle of nearbyparticles) {
      if (cparticle != self) {
        let distance = this.position.distanceFrom(cparticle.position);
        density += cparticle.mass * fluidSimulator.poly6kernel(distance, this.smoothinglength)
      }
    }
    this.density = density;
  }
  calculatepressure() {
    this.pressure = pressuremultiplier * (this.density - restdensity)
  }
  calculatepressureforce(nearbyparticles) {
    let pressureforce = new Vector(0, 0);
    let pressuremagnitude = 0;
    for (let cparticle of nearbyparticles) {
      let distance = this.position.distanceFrom(cparticle.position);
      if (distance !== 0) {
        let directionvector = new Vector((this.position.x - cparticle.position.x) / distance, (this.position.y - cparticle.position.y) / distance);

        // Check if the denominator (cparticle.density) is not zero
        if (cparticle.density !== 0) {
          pressuremagnitude = cparticle.pressure * cparticle.mass * fluidSimulator.spikykernelderrivative(distance, this.smoothinglength) / cparticle.density;
          pressureforce.x += directionvector.x * (pressuremagnitude);
          pressureforce.y += directionvector.y * (pressuremagnitude)
          if (distance < this.smoothinglength) {
            //console.log(pressureforce)
          }
        }
      }
    }
    this.pressureforce = pressureforce.mulScalar(-1);
  }

  simulateParticle() {
    this.updateAcceleration();
    this.velocity = this.velocity.add(this.acceleration.mulScalar(fluidSimulator.timestep));
    this.position = this.position.add(this.velocity.mulScalar(fluidSimulator.timestep));
    this.checkboundarys()

  }

}

class SPHFluidSimulator {
  constructor() {
    //simulation constants
    this.timestep = 1 / 30;
    this.gravity = new Vector(0, 0);
    this.collisionDamping = 1;
    this.particleSpacing = 0.1;
    this.particles = [];



  }
  poly6kernel(r, h) {
    let influence = 0
    if (r >= 0 & r <= h) {
      influence = (h ** 2 - r ** 2) ** 3

    }
    return (315 / (64 * Math.PI * h ** 9)) * influence

  }
  spikykernelderrivative(r, h) {
    let influence = 0
    if (r >= 0 & r <= h) {
      influence = -3 * (h - r) ** 2
    }
    return (15 / (Math.PI * h ** 6)) * influence


  }
  initialiseParticle(particle) {
    // Add a particle to the simulation and update the grid
    this.particles.push(particle);
  }


}

function generateParticlesRandom() {
  for (let i = 0; i < numParticles; i++) {
    let particleX = Math.random() * simWidth;
    let particleY = Math.random() * simHeight;
    let particle = new Particle(particleX, particleY);
    fluidSimulator.initialiseParticle(particle);
  }
}

function physics() {
  for (const particle of fluidSimulator.particles) {
    particle.simulateParticle();
  }
  //console.log(fluidSimulator.particles[0])

}

function draw() {

  c.clearRect(0, 0, canvas.width, canvas.height);
  c.fillStyle = "#005EB8";
  for (let i = 0; i < numParticles; i++) {
    let particle = fluidSimulator.particles[i];
    c.beginPath();
    c.arc(cX(particle.position), cY(particle.position), cScale * radius, 0.0, 2.0 * Math.PI);
    c.closePath();
    c.fill();
  };
}

function simulate() {
  physics();
  draw();
  requestAnimationFrame(simulate);
}

var fluidSimulator = new SPHFluidSimulator();
generateParticlesRandom();
simulate();
<script src="https://ronenness.github.io/Vector2js/vector2js.js"></script>
<canvas id="canvas"></canvas>

0

There are 0 answers