DEBUG key: /en/sun_earth_moon_animation
DEBUG locale: sr
DEBUG target: /en/en/sun_earth_moon_animation
🇬🇧 English
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 .
ω
on every update.(x, y, z)
.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.
Animation not working? Reload the page (refresh)
← horizontal scroll →
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():
loadImage(prefix + "Textures/…")
.setup():
determineSize()
, then created with createCanvas(widthS, heightS, WEBGL)
.canvasDrawing.GL
) is used to clear the depth buffer before drawing the 2D background.draw():
image(spaceIm,…)
, and then the Z-buffer is cleared.ambientLight(255)
, and orbitControl
is enabled to allow camera rotation with the mouse.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.
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();
}
}
<!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>