Getting initial conditions for the rings of Saturn


#1

Hey people!

I’m trying to figure out how to model the rings of Saturn using a particle system for a gravity simulator that I’m making. Using the code below, I’ve managed to create a, if not perfect, the gaps aren’t there for example, decent ring that rotates around Saturn under the force of the gravity of Saturn and its moons. However, my ring has an axial tilt of 0 whereas in reality the axial tilt of Saturn’s rings is 27 degrees. The problem is that I can’t get the z position and velocity vectors right for the particles that make up the particle system. Would anybody be able to help me figure out how to accomplish this?

Prisoner was kind enough to give me a better grasp of how to achieve this over at Stackoverflow (https://stackoverflow.com/questions/50705595/rings-of-saturn-initial-conditions/50708794?noredirect=1#comment88563339_50708794), but I need to have the initial conditions in vector form because of how I do my gravity calculations (see the code below).

For the full source code and project, you can check out the git repository (please note I haven’t committed the code pasted below as it doesn’t yet do what I want it to do) https://github.com/TheHappyKoala/Gravity-Playground

If more information is needed, please let me know!


export default class {
  constructor(params) {
    this.numberOfParticles = params.numberOfParticles;

    this.g = params.g;

    this.law = params.law;

    this.dt = params.dt;

    this.particles = [];

    this.init();
  }

  init() {
    for (let i = 0; i < this.numberOfParticles; i++) {
      const rad = Math.PI * 2 * Math.random();
      const dist = (25 + 20 * Math.random()) / 32000;

      this.particles.push({
        x: Math.cos(rad) * dist,
        y: Math.sin(rad) * dist,
        z: 0,
        vx:
          Math.cos(
            rad + Math.PI / 2 + (Math.PI / 180 * 6 - Math.PI / 180 * 12) * 0
          ) *
          Math.sqrt(500 / dist) /
          120,
        vy:
          Math.sin(
            rad + Math.PI / 2 + (Math.PI / 180 * 6 - Math.PI / 180 * 12) * 0
          ) *
          Math.sqrt(500 / dist) /
          120,
        vz: 0
      });
    }
  }

  iterate(masses) {
    for (let i = 0; i < this.particles.length; i++) {
      let massI = this.particles[i];

      console.log(massI);

      let ax = 0;
      let ay = 0;
      let az = 0;

      for (let j = 0; j < masses.length; j++) {
        let massJ = masses[j];

        let dx = massJ.x - massI.x;
        let dy = massJ.y - massI.y;
        let dz = massJ.z - massI.z;

        let distsq = dx * dx + dy * dy + dz * dz;

        let fact = this.g * massJ.m / Math.pow(distsq, this.law);

        ax += dx * fact;
        ay += dy * fact;
        az += dz * fact;
      }

      massI.vx += ax * this.dt;
      massI.vy += ay * this.dt;
      massI.vz += az * this.dt;

      massI.x += massI.vx * this.dt;
      massI.y += massI.vy * this.dt;
      massI.z += massI.vz * this.dt;
    }
  }
}```

```import * as THREE from 'three';

export default class extends THREE.Object3D {
  constructor(ringParticles, scenarioScale) {
    super();

    this.ringParticles = ringParticles;

    this.scenarioScale = scenarioScale;

    this.setRing();
  }

  setRing() {
    const ringGeometry = new THREE.Geometry();

    for (let i = 0; i < this.ringParticles.length; i++) {
      let particle = this.ringParticles[i];

      particle.x = particle.x * this.scenarioScale;
      particle.y = particle.y * this.scenarioScale;
      particle.z = particle.z * this.scenarioScale;

      ringGeometry.vertices.push(particle);
    }

    const particleMaterial = new THREE.PointsMaterial({
      size: 1,
      color: 'red',
      transparent: true,
      opacity: 0.45
    });

    const ring = new THREE.Points(ringGeometry, particleMaterial);

    ring.name = 'ring';

    this.add(ring);
  }

  draw(ringParticles) {
    const ring = this.getObjectByName('ring');

    for (let i = 0; i < ring.geometry.vertices.length; i++) {
      ring.geometry.vertices[i].x = ringParticles[i].x * this.scenarioScale;
      ring.geometry.vertices[i].y = ringParticles[i].y * this.scenarioScale;
      ring.geometry.vertices[i].z = ringParticles[i].z * this.scenarioScale;
    }

    ring.geometry.verticesNeedUpdate = true;
  }
}```

#2

Any chances to provide a live demo? Maybe via github pages since you have already have a repo. This makes your project more accessible and interested community members can easier debug your code.


#3

Hi Mugen87,

Here’s a live demo: https://protected-beyond-45467.herokuapp.com/

I only have the free tier of Heroku so it takes a couple of seconds before it loads, but hopefully it, alongside the code provided above, should give people more of an idea as to what I’m trying to achieve.

Feedback is always welcome!