2

I am looking for a way to orbit a moon around my planet that is orbiting my sun.

(All of these are 3d objects in three.js)

I have defined all my objects and currently have the earth rotating around my sun, but I am having difficulties getting the moon to rotate around the already rotating Earth.

sun = models['sun'];
earth = models['earth'];
moon = models['moon'];

let suns = new THREE.Group();
suns.add(sun);

let planets = new THREE.Group();
planets.add(earth);

let moons = new THREE.Group();
moons.add(moon);

scene.add(sun);
scene.add(earth);
scene.add(moon);

var orbit = 3;
var date = Date.now() * 0.0005;

earth.position.set(Math.cos(date) * orbit, 0, Math.sin(date) * orbit);

earth.rotation.y += 0.01*animation_speed;
moon.rotation.y += 0.01*animation_speed;

Expected: Earth rotates around Sun (static), while Moon rotates around Earth as it rotates around Sun.

Current: Earth rotates around Sun. Not sure what to do with moon...

2 Answers2

2

it would be easy if you make a hierarchy of your objects, that way they rotate around their parents.

First note that your groups do not do anything at all: If you call suns.add(sun) and then you call scene.add(sun), the second call removes the sun from suns and adds it to scene, therefore your groups are empty. So in the following example, we will not use the groups.

F.e.

const sun = models['sun'];
const earth = models['earth'];
const moon = models['moon'];

const sunContainer = new THREE.Object3D
sunContainer.add(sun)
const earthContainer = new THREE.Object3D
earthContainer.add(earth)
const moonContainer = new THREE.Object3D
moonContainer.add(moon)

scene.add(sunContainer); // sunContainer is child of scene
sunContainer.add(earthContainer); // earthContainer is child of sunContainer
earthContainer.add(moonContainer); // moonContainer is child of earthContainer

var earthOrbitRadius = 3;
var moonOrbitRadius = 0.2;

// position them at their orbit radius (relative to their parents)
earthContainer.position.set(earthOrbitRadius, 0, 0);
moonContainer.position.set(moonOrbitRadius, 0, 0);

// each planet rotates around its poles
sun.rotation.y += 1*animation_speed;
earth.rotation.y += 1*animation_speed;
moon.rotation.y += 1*animation_speed;

// and each planet orbits around its parent
sunContainer.rotation.y += 0.1*animation_speed;
earthContainer.rotation.y += 0.1*animation_speed;

Now restore those bits back into your code, adjust the numbers as needed, and it should work similar to what want.

There's other ways to do it, that's just one way. To make planet rotation independent of orbit rotation, you could adjust the planet rotation with negative orbit rotation. Or, you could make the container orbit, then add sun, earth, and moon directly to scene instead of the containers, then copy the container positions to them, while they rotate independently. Or you could use a physics engine (Bullet Physics is built into Three.js). Or you can use pivot points.

By the way, it would help if you post working code. :)

trusktr
  • 44,284
  • 53
  • 191
  • 263
  • 1
    Thank you so much, this really helped me get moving in the right direction to finally establish my code. Sorry if my first questions wasn't super detailed, this is my first post on stack overflow :P – Amine Kebichi Apr 08 '19 at 20:12
  • 1
    I've been looking for this solution for days. I love you. – Joe Moore Aug 24 '22 at 12:57
0

I've developed simple example to illustrate hierachy of THREE.Object3D and how children related to its "parents" and its positions and rotations.

var scene = new THREE.Scene();
var aspect = window.innerWidth / window.innerHeight;
var camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000);
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
solarsystem.forEach(d => create(d, scene))
scene.add(sphere({radius:5, orbit:0}))

function create(d, target) {
   var o = new THREE.Object3D(d.name);
   o.add(orbit(d));
   let p = sphere(d)
   o.add(p);
   d.satellites && d.satellites.forEach(d1 => create(d1, p))
   target.add(o);
   d.o=o; 
}

function orbit(d) {
    var o = new THREE.Object3D('orbit '+d.name);
    o.rotateX(Math.PI/2);
    o.add( new THREE.Line( 
        new THREE.CircleGeometry( d.orbit, 64 ), 
        new THREE.LineBasicMaterial( { color: 0xffffff } ) ));
    return o;
}

function sphere(d){
    var o = new THREE.Object3D('sphere '+d.name);
    o.add(new THREE.Mesh( 
        new THREE.SphereGeometry(d.radius, 16, 16), 
        new THREE.MeshBasicMaterial({ 
            color: 0x2980b9, wireframe: true 
        })));
    o.translateX(d.orbit)
    return o;
}

var grid = new THREE.GridHelper(500, 100, 0x666666, 0x444444)
grid.rotateY(Math.PI/2);
scene.add(grid);
camera.position.set(5,5,0);

new THREE.OrbitControls( camera, renderer.domElement );

let t = 0;

function render(dt) {
    let t2= dt-t;
    requestAnimationFrame( render );
    renderer.render( scene, camera );
    solarsystem.forEach(upd)
    t = dt;
    
    function upd(d) {
        d.o.rotateY(t2/10000*d.speed);
        d.satellites && d.satellites.forEach(upd)
    }
}

requestAnimationFrame( render );
body, canvas { 
  margin: 0;  
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/103/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script>
    let solarsystem = [{
        name: 'earth', radius: 2, orbit: 30, speed: 2,
        satellites: [{
            name: 'moon', radius: 1, orbit: 6, speed: 1,
        }]
    }, {
        name: 'mars', radius: 2, orbit: 50, speed: 1,
        satellites: [{
            name: 'phobos', radius: 0.5, orbit: 3, speed: 1,
        }, {
            name: 'deimos', radius: 0.5, orbit: 4, speed: 3,
        }]
    }];
</script>
Stranger in the Q
  • 3,668
  • 2
  • 21
  • 26