简体   繁体   中英

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

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

First note that your groups are pointless. 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, I will not use the groups.

Fe

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 use pivot points .

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

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); do=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) { dorotateY(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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM