Web Analytics
Sistem Sunce–Zemlja–Mesec

Sun–Earth–Moon System

This 3D animation models the Sun, Earth, and Moon as a simple hierarchical system: the Earth revolves around the Sun, and the Moon revolves around the Earth. Each celestial body rotates around its "parent" with its own angular velocity. The visualization is created using p5.js in WEBGL mode, with realistic planet textures and orbit visualization.

The physics behind it is kinematic: in each frame, we update the angle using the expression Δθ = ω·Δt, then draw each sphere in polar coordinates (r·cos θ, r·sin θ) relative to the body it orbits. Lighting and orbit trails help convey the motion in 3D space.

For more details on the mathematics and programming of this simulation using Processing and the Java programming language, check out our guide: SvetProgramiranja: Movement of 3D Objects in Processing .

Key Concepts

Below is an interactive 3D visualization. Drag with the mouse to rotate the camera and use the scroll wheel to zoom. Displayed orbits help you understand the movement of each celestial body.

3D Animation: Earth's Rotation Around the Sun

Animation not working? Reload the page (refresh)

← horizontal scroll →

Code Explanation: Sun–Earth–Moon Animation

In this 3D simulation, we use p5.js in WEBGL mode. The model is hierarchical: the Earth orbits the Sun, and the Moon orbits the Earth. Each body has its own angular and orbital velocity, with textures and lighting enhancing realism.

Global variables:

  • sunIm, earthIm, moonIm, spaceIm — textures for the planets and background.
  • sun, earth, moon — instances of the Planet class with parameters: radius, distance, parent, speedRotation, speedOwnRotation, and emission.
  • glContext — the WebGL context used to clear the Z-buffer after drawing the background.

preload():

  • Images are loaded using loadImage(prefix + "Textures/…").

setup():

  • Canvas dimensions are determined using determineSize(), then created with createCanvas(widthS, heightS, WEBGL).
  • Planet objects for the Sun, Earth, and Moon are initialized.
  • The saved WebGL context (canvasDrawing.GL) is used to clear the depth buffer before drawing the 2D background.

draw():

  • The 2D background is set using image(spaceIm,…), and then the Z-buffer is cleared.
  • Basic lighting is set with ambientLight(255), and orbitControl is enabled to allow camera rotation with the mouse.
  • The hierarchical call sun.orbit() and sun.show() recursively animates and draws all planets.

The Planet class:

  • orbit() — increments the angle and angleOwn values, and recursively calls orbit for its children.
  • show() — draws the orbit as a circle, applies rotation based on the angle, and renders the textured or emissive sphere.
```html

earth_sun_moon_animation.js


var canvasDrawing; // GL canvas for rendering the 3D scene
let container, containerMain; // HTML elements to hold the canvas
var isMobile; // whether the device is mobile (orientation available)
var widthS;
var heightS;
let sun; // main object – the Sun
let prevMouse; // previous mouse position (on press)
let zoom = 1; // zoom factor for the scene
let drag; // vector for moving the light source
let sunIm, earthIm, moonIm, spaceIm; // textures for planets and background
let wEarth = 0.005, wEarth1 = 0.08, wMoon = -0.2; // rotation speeds (orbit and own axis)
let z = 0; // light source height
let dLight = 200; // distance of light source from center
var rSun, rEarth, rMoon; // radii of the bodies
let prefix = "/js/p5js/SunceOrbita/"; // path to the textures folder
let glContext; // WebGL context for managing the depth buffer

function setup() {
  isMobile = window.orientation > -1; // check for mobile device
  determineSize(); // calculate canvas dimensions
  drag = createVector(0, 0); // initialize light-drag vector
  canvasDrawing = createCanvas(widthS, heightS, WEBGL); // create WebGL canvas
  container = document.getElementById('canvasForHTML');
  canvasDrawing.parent(container); // insert canvas into container
  glContext = canvasDrawing.GL; // obtain WebGL context

  // compute body radii based on screen width
  rSun = widthS / 20;
  rEarth = rSun / 4;
  rMoon = rEarth / 3;

  // create planet instances and set up hierarchy
  sun = new Planeta(rSun, 0, null, sunIm, 0, 0, color(255));
  earth = new Planeta(rEarth, widthS / 3, sun, earthIm, wEarth, wEarth1);
  moon = new Planeta(rMoon, rEarth + rMoon + 25, earth, moonIm, wMoon, 0);

  smooth(16); // anti-aliasing for smooth edges
}

function preload() {
  // load all textures before the scene starts
  sunIm = loadImage(prefix + "Textures/sun1.jpg");
  earthIm = loadImage(prefix + "Textures/earth1.jpg");
  moonIm = loadImage(prefix + "Textures/moon.jpg");
  spaceIm = loadImage(prefix + "Textures/space.jpg");
}

function determineSize() {
  // adjust canvas dimensions based on resolution and orientation
  if (isMobile) {
    if (displayWidth > 1200) {
      heightS = 2 * displayHeight / 3;
      widthS = 2 * displayWidth * 3;
    } else if (displayWidth < displayHeight) {
      widthS = displayWidth;
      heightS = 2 * widthS / 3;
    } else {
      widthS = 2 * displayWidth / 3;
      heightS = 2 * widthS / 3;
    }
  } else {
    // for desktop use full width
    widthS = displayWidth;
    heightS = 2 * widthS / 3;
  }
  // cap max width to preserve aspect ratio
  if (widthS > 940) {
    widthS = 940;
    heightS = 627;
  }
}

function windowResized() {
  determineSize(); // recalculate dimensions
  resizeCanvas(widthS, heightS, false);
}

function draw() {
  // set space background and clear depth buffer before 3D drawing
  spaceIm.resize(widthS, heightS);
  imageMode(CENTER);
  background(0,0,0,0);
  push();
    camera(0,0,-300,0,0,0,0,-1,0);
    image(spaceIm,0,0,1.5*widthS,1.5*heightS);
    glContext.clear(glContext.DEPTH_BUFFER_BIT);
  pop();

  noStroke();
  ambientLight(255); // global ambient light component
  orbitControl(); // mouse/touch interactive camera control
  rotateX(10*PI/24);
  rotateY(PI/64);

  // update all bodies’ positions before drawing
  sun.orbit();
  sun.show();
}

function mousePressed() {
  // store mouse position on click for later light adjustments
  prevMouse = createVector(mouseX, mouseY);
  // move light along z-axis with arrow keys
  if (key == "ArrowRight") { z += 1; }
  else if (key == "ArrowLeft") { z -= 1; }
}

function mouseWheel(event) {
  // zoom scene with mouse wheel
  zoom += event.delta * 0.0005;
}

class Planeta {
  constructor(radius, distance, parent, texture, speedRotation, speedOwnRotation, emission) {
    // set up basic body parameters
    this.radius = radius;
    this.distance = distance;
    this.parent = parent;
    this.texture = texture;
    this.emission = emission;
    // random initial rotations for a dynamic effect
    this.angle = random(2*PI);
    this.angleOwn = random(2*PI);
    this.speedRotation = speedRotation;
    this.speedOwnRotation = speedOwnRotation;
    this.children = [];
    // add to parent’s children list (scene hierarchy)
    if (parent) { parent.children.push(this); }
  }

  orbit() {
    // advance orbit and self-rotation angles
    this.angle += this.speedRotation;
    this.angleOwn += this.speedOwnRotation;
    // recursively update children
    for (let planet of this.children) {
      planet.orbit();
    }
  }

  show() {
    // save current transform matrix
    push();

    // 1) draw orbit as a circle in the XY plane
    push();
      strokeWeight(0.5);
      stroke(color(200,200,100));
      noFill();
      ellipse(0,0,this.distance*2);
    pop();

    // 2) if the body emits light (Sun), set up pointLight sources
    if (this.emission) {
      fill(this.emission);
      scale(100);
      // six pointLight sources around center for a more realistic effect
      pointLight(this.emission, drag.x+dLight, drag.y, z);
      pointLight(this.emission, drag.x-dLight, drag.y, z);
      pointLight(this.emission, drag.x, drag.y+dLight, z);
      pointLight(this.emission, drag.x, drag.y-dLight, z);
      pointLight(this.emission, drag.x, drag.y, z+dLight);
      pointLight(this.emission, drag.x, drag.y, z-dLight);
      scale(0.01);
    }

    // 3) rotate and position the body relative to its parent
    rotate(-this.angle);
    translate(this.distance, 0);
    rotate(-this.angleOwn);

    // 4) apply texture or color and draw the sphere
    if (this.emission) {
      texture(this.texture);
      sphere(this.radius);
      ambientLight(this.emission);
    } else {
      if (this.texture != null) {
        texture(this.texture);
      } else {
        ambientMaterial(255);
      }
      sphere(this.radius);
    }

    // 5) recursively draw all satellites (children) of this body
    for (let planet of this.children) {
      planet.show();
    }

    // restore previous transform matrix
    pop();
  }
}
```

index.html


<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <script src="libraries/p5.min.js"></script>
    <script src="earth_sun_moon_animation.js"></script>
  </head>

  <body>
    <div id="canvasForHTML" class="canvasForHTML"></div>
    <p>Animation not working? Please refresh the page. </p>
  </body>
</html>