Solar System
Planets in turning groups, a moon, a light at the sun and 2,000 stars. Drag to look around.
# A solar system in 3D.
# Shows: groups (a planet in a turning group goes round the sun), a moon,
# a point light at the sun, and 2,000 stars in one Points object.
# Drag to look around, scroll to zoom. Click, then press the up and down
# arrows to speed time up or slow it down.
#
# Run it: pyctures run solar_system.py
# Share it: pyctures build solar_system.py -o site/
import math, random
renderer = THREE.WebGLRenderer(canvas=canvas, antialias=True)
renderer.setPixelRatio(pixel_ratio)
renderer.setSize(width, height, False)
scene = THREE.Scene()
scene.background = THREE.Color("black")
camera = THREE.PerspectiveCamera(55, width / height, 0.1, 500)
camera.position.set(0, 14, 24)
controls = addons.OrbitControls(camera, canvas)
controls.enableDamping = True
# --- the sun: glows by itself, and lights everything ---------------------
sun = THREE.Mesh(THREE.SphereGeometry(1.5, 48, 24), THREE.MeshBasicMaterial(color="gold"))
scene.add(sun)
scene.add(THREE.PointLight("white", 400, 0)) # a bulb at the sun's centre
scene.add(THREE.AmbientLight("white", 0.08)) # so night sides are not pure black
# --- planets ---------------------------------------------------------------
# name colour size distance speed (turns a second)
planets_data = [
("Mercury", "darkgray", 0.25, 3.0, 0.40),
("Venus", "navajowhite", 0.45, 4.5, 0.25),
("Earth", "royalblue", 0.5, 6.5, 0.16),
("Mars", "orangered", 0.35, 8.5, 0.11),
("Jupiter", "sandybrown", 1.1, 12.0, 0.05),
]
orbits = [] # (group, speed) pairs to turn each frame
earth = None
for name, colour, size, distance, speed in planets_data:
orbit = THREE.Group()
orbit.rotation.y = random.uniform(0, math.tau) # start somewhere along the orbit
scene.add(orbit)
planet = THREE.Mesh(THREE.SphereGeometry(size, 32, 16), THREE.MeshStandardMaterial(color=colour, roughness=0.8))
planet.position.x = distance
orbit.add(planet)
orbits.append((orbit, speed))
# a faint ring to show the path
path = THREE.Mesh(
THREE.RingGeometry(distance - 0.02, distance + 0.02, 128),
THREE.MeshBasicMaterial(color="#333", side=THREE.DoubleSide),
)
path.rotation.x = -math.pi / 2
scene.add(path)
if name == "Earth":
earth = planet
# --- a moon going round the Earth ---------------------------------------
moon_orbit = THREE.Group()
earth.add(moon_orbit) # the moon's group rides along with the Earth
moon = THREE.Mesh(THREE.SphereGeometry(0.14, 16, 8), THREE.MeshStandardMaterial(color="lightgray"))
moon.position.x = 0.9
moon_orbit.add(moon)
# --- stars: a few thousand points far away ---------------------------------
positions = []
for _ in range(2000):
# a random direction, 80 to 150 units away
theta = random.uniform(0, math.tau)
phi = math.acos(random.uniform(-1, 1))
r = random.uniform(80, 150)
positions += [r * math.sin(phi) * math.cos(theta), r * math.cos(phi), r * math.sin(phi) * math.sin(theta)]
stars_geometry = THREE.BufferGeometry()
stars_geometry.setAttribute("position", THREE.Float32BufferAttribute(positions, 3))
scene.add(THREE.Points(stars_geometry, THREE.PointsMaterial(color="white", size=0.4)))
# --- every frame ---------------------------------------------------------
speed_up = 1.0
def on_key_down(key):
global speed_up
if key == "ArrowUp":
speed_up *= 2
elif key == "ArrowDown":
speed_up /= 2
def update(dt):
for orbit, speed in orbits:
orbit.rotation.y += speed * math.tau * dt * speed_up / 4
moon_orbit.rotation.y += 2 * dt * speed_up
earth.rotation.y += 3 * dt * speed_up # the Earth spins on its own axis too
sun.rotation.y += 0.1 * dt
def draw():
controls.update()
renderer.render(scene, camera)
Run it yourself
pip install pyctures pyctures run solar_system.py
Put it on your website
pyctures build solar_system.py -o site/
Python runs in the visitor's browser, so any static host works. How · This file on GitHub