javascriptthree.jshierarchy3d-model

I'm trying to rotate a (THREE.mesh) 3d object around another that is already rotating on an axis. Any pointers?


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...


Solution

  • 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. :)