Any suggestions for rotating a (THREE.mesh) 3D object around another object that is already rotating on an axis?

I am trying to create a simulation where a moon orbits around a planet that is itself orbiting around a sun.

Using three.js, I have successfully set up the Earth rotating around the Sun. However, I am facing challenges in making the Moon 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;

Desired Outcome: The Earth should rotate around the Sun (stationary), with the Moon revolving around the Earth as it revolves around the Sun.

Current Status: The Earth rotates around the Sun but unsure how to proceed with the Moon's rotation...

Answer №1

Creating a hierarchy of objects will simplify the rotation process as they rotate around their parent objects.

It's important to note that your groups are not functioning as intended: when you add an object to a group and then to the scene, it is removed from the group and added directly to the scene. For this example, we will avoid using groups altogether.

For instance:

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 becomes child of scene
sunContainer.add(earthContainer); // earthContainer becomes child of sunContainer
earthContainer.add(moonContainer); // moonContainer becomes child of earthContainer

var earthOrbitRadius = 3;
var moonOrbitRadius = 0.2;

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

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

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

Reintegrate these changes into your code and adjust values accordingly for desired results.

There are alternative methods to achieve similar effects such as adjusting planet rotation in relation to orbit rotation or using a physics engine like Bullet Physics within Three.js. You can also explore pivot points for more flexibility.

Providing working code would greatly aid in troubleshooting. :)

Answer №2

I have created a straightforward example to demonstrate the hierarchy of THREE.Object3D and how children are related to their "parents" in terms of 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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating TypeScript modules for npm

I have been working on creating my first npm module. In the past, when I used TypeScript, I encountered a challenge where many modules lacked definition files. This led me to the decision of developing my module in TypeScript. However, I am struggling to ...

What is the reason behind the ability to omit the arrow function and method argument in RxJS subscribe?

Recently, I found myself in a situation where I had to work with RxJS. While trying to set up an error handling flow, I came across some unusual syntax for passing method arguments: .subscribe( x => { }, console.warn // <- I was puzzled b ...

The number of files being uploaded by my code keeps increasing when it should only be uploading a single file

My jquery dialog form contains a button that triggers the following function: <button type="button" class="btn btn-primary" onclick="gpa_pl_upd_photo_upload()" value="">Upload Photo</button> The issue I& ...

Adjust the position of an image to move it closer to the top using CSS

I have a fiddle where I am trying to adjust the position of an image (keyboard) to match a specific design. https://i.sstatic.net/flqCH.png In my fiddle, the keyboard image is slightly lower than the desired position shown in the design. I am looking for ...

Is it possible that react-gtm-module is generating a faulty source path?

It seems that the react-gtm-module is generating an incorrect src path, substituting a "/" with a ".". This is the original src path provided by Google: . However, the generated src path by react-gtm-module is: gtag: . Google Tag Manager detects this i ...

What could be the reason for Safari generating larger videos than Chrome when utilizing the MediaDevices.getUserMedia() API?

Embarking on a small experiment to gauge the size of captured videos using the MediaDevices.getUserMedia() API. My Safari implementation yielded videos 5-10 times larger than those in Chrome. Here's the code snippet: index.html: <html lang=" ...

No visuals render with Three.js

I am experimenting with three.js for the first time and I am having trouble understanding why I can't see the color on my torus. I've tried setting alpha to true in my render. I attempted to change the camera position in the z-axis. I also tri ...

ASP.net bundling causing issues with script rendering and display

I recently encountered an issue with external scripts on one of my views. To resolve it, I copied and pasted each function from the URL into a new local js script, bundled them together, and everything was displaying correctly. However, when I tried to use ...

Transferring Shadertoy creations into Three.js

Embarking on my coding journey, I have completed some online courses and dabbled in three.js experiments. Now, I am eager to dive into the world of Shaders. Discovering Shadertoy.com has been eye-opening with its plethora of mesmerizing experiments and ef ...

Refresh the table following the removal of an item

I am currently working on displaying server data in a table. The delete function is functioning properly, but the deleted item only disappears from the table after refreshing the page. Is there a way to trigger a re-render of the component after deleting a ...

Unlimited height dialog overlay exclusive to Facebook

It seems like a crucial matter that needs attention. My dialog has an overlay with specific width settings as shown below: .ui-widget-overlay { width: 518px !important; } The height of the overlay will vary based on the page size controlled by JavaS ...

Refreshing JWT Authentication in Angular

I am currently following a tutorial on Egghead.io, which can be found here. However, I am adding a MongoDB to fetch my users which is causing me some issues. I have managed to get everything working except for the part where it mentions that the /me route ...

Passing data from a card component to a tab component in ReactJS

Just starting out with react and facing an issue. I want to transfer props from the child component to the parent component tabs that include favorite tabs. My plan was to pass the values through the handleClickOpen method where I click the favorites icon. ...

Tips for avoiding the Basic Authentication popup

I am working on a Java application using JSF that requires JavaScript to connect to a website with Basic authentication. My goal is to replicate the experience of manually entering a username and password in the popup form. Despite trying various methods ...

Is there a way to effortlessly zoom in on a Google map with just one mouse click?

Can the Google Maps be zoomed to a specific level with just one click of the mouse? ...

Organize the words within HTML elements without considering the tags

My webpage contains buttons that appear as follows: <button>Apple</button> <button>Dog</button> <button>Text</button> <button>Boy</button> <button class='whatNot'>Text</button> <butt ...

Encountered an error: Unable to access property 'tween' of an undefined variable in the Masterslider.js script

My webpage features three sliders using Master Slider alongside Fullpage.js. var slider = new MasterSlider(); slider.setup('masterslider', { width: 300, height: 300, });   slider.control('lightbox'); slider.control('slidei ...

Navigate directly to a designated element in a React component without the need to scroll when clicking a link

When viewing a user's profile in React, clicking on an image currently scrolls to that specific image within the entire images page. However, I am looking to modify this behavior so that it navigates directly to the image element without any scrolling ...

Querying MongoDB with a JavaScript file for formatting datetime values

I am utilizing mongodb3.0.5 and my database collection appears as follows: { "_id" : "xxxxxxxxxxxxxxx", "SchoolId" : 1, "ActivationTimestamp" : ISODate("2015-09-22T13:01:58.000Z"), "PersonDetails" : [ { "Name" : "John" ...

Can the parcel bundler dist folder be customized for decoration?

After compiling code with parcel using the command parcel src/index.html, all files are generated inside the dist folder. However, I am looking for a more organized way to manage these files once my website is complete. Ideally, I want separate folders suc ...