1

I'm trying to rotate multiple objects around the same Vector3 point but in different directions - so they effectively 'swarm' around the point.

I'm using the trig approach rather simply wrapping each object in a Container and applying some random rotations as I'm projecting their 3D vector to 2D positions to attach label DIVs above the canvas, and the container approach messes with with project class.

Here's my current code which makes all objects rotate around the point along the same orbit path:

for(var i = 0; i<objectsArr.length; i++){
    var obj = objectsArr[i];
    var radius = obj.angle * (Math.PI / 180);
    obj.position.x = obj.radius * Math.cos(radius); 
    obj.position.y = obj.radius * Math.sin(radius);
    obj.angle += obj.orbitSpeed;
}

Does anyone know how I can make them orbit in random directions along X, Y, Z axis?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
DTids
  • 110
  • 3
  • 11

1 Answers1

3

First, see this answer about rotating objects about a point.

From your code, it looks like you're storing each object's orbit speed, and their current angle of rotation (which represents the vector to the position). Rather than storing a 2D angle, store it as a Vector3 which represents the normal of (perpendicular to) the object's orbital plane. (This will let you really get a "swarm" going later, when you can define different orbital planes.) I also recommend storing the orbit speed in radians per step, so you don't have to perform the conversion every pass.

The rest of problem actually becomes very simple with the Vector3.applyAxisAngle method.

Some pseudo-code:

  1. Subtract the rotation point position from the object's position.
  2. Use the object's orbit speed, and angle to update the temp position.
  3. Add the rotation point position back to the object's position.

To see it in your code:

var obj;
for(var i = 0; i< objectsArr.length; i++){
    obj = objectsArr[i];
    obj.position.sub(rotationPoint); // rotationPoint is a Vector3
    obj.position.applyAxisAngle(obj.angle, obj.orbitSpeed);
    obj.add(rotationPoint);
}

And here's a live demo of a few objects orbiting randomly about a "nucleus" at (10, 10, 10).

var renderer, scene, camera, controls, stats, nucleus;

var WIDTH = window.innerWidth,
  HEIGHT = window.innerHeight,
  FOV = 60,
  NEAR = 1,
  FAR = 1000;

var electrons = [],
    numElectrons = 100; // more electrons = slower updating
function populateScene() {
  var geo = new THREE.SphereBufferGeometry(10, 16, 16);
  var mat = new THREE.MeshPhongMaterial({color:"blue"});
  nucleus = new THREE.Mesh(geo, mat);
  nucleus.position.set(10, 10, 10); // you can change these values
  scene.add(nucleus);
  
  var electron = null,
    plane = new THREE.Plane(),
    point = new THREE.Vector3();
  geo = new THREE.SphereBufferGeometry(1, 16, 16);
  mat = new THREE.MeshPhongMaterial({color:"red"});
  for(var i = 0; i < numElectrons; ++i){
    electron = new THREE.Mesh(geo, mat);
    electrons.push(electron);
    electron.angle = new THREE.Vector3(
      Math.random(),
      Math.random(),
      Math.random()
    ).normalize();
    electron.orbitSpeed = (Math.random() * 0.05) + 0.05;
    if(Math.random() > 0.5) electron.orbitSpeed *= -1;
    plane.normal.copy(electron.angle);
    point.set(Math.random(), Math.random(), Math.random());
    plane.projectPoint(point, electron.position);
    electron.position.setLength(Math.floor(Math.random() * 20) + 15);
    electron.position.applyAxisAngle(electron.angle, Math.random() / 10);
    electron.position.add(nucleus.position);
    scene.add(electron);
  }  
}

function updateElectrons(){
  var obj = null;
  for(var i = 0; i < numElectrons; ++i){
      obj = electrons[i]
      obj.position.sub(nucleus.position);
      obj.position.applyAxisAngle(obj.angle, obj.orbitSpeed);
      obj.position.add(nucleus.position);
  }
}

function init() {
  document.body.style.backgroundColor = "slateGray";

  renderer = new THREE.WebGLRenderer({
    antialias: true,
    alpha: true
  });
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap;

  document.body.appendChild(renderer.domElement);
  document.body.style.overflow = "hidden";
  document.body.style.margin = "0";
  document.body.style.padding = "0";

  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
  camera.position.z = 100;
  scene.add(camera);

  controls = new THREE.TrackballControls(camera, renderer.domElement);
  controls.dynamicDampingFactor = 0.5;
  controls.rotateSpeed = 3;

  var light = new THREE.PointLight(0xffffff, 1, Infinity);
  camera.add(light);

  stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0';
  document.body.appendChild(stats.domElement);

  resize();
  window.onresize = resize;

  populateScene();

  animate();
}

function resize() {
  WIDTH = window.innerWidth;
  HEIGHT = window.innerHeight;
  if (renderer && camera && controls) {
    renderer.setSize(WIDTH, HEIGHT);
    camera.aspect = WIDTH / HEIGHT;
    camera.updateProjectionMatrix();
    controls.handleResize();
  }
}

function render() {
  renderer.render(scene, camera);
}

function animate() {
  requestAnimationFrame(animate);
  updateElectrons();
  render();
  controls.update();
  stats.update();
}

function threeReady() {
  init();
}

(function() {
  function addScript(url, callback) {
    callback = callback || function() {};
    var script = document.createElement("script");
    script.addEventListener("load", callback);
    script.setAttribute("src", url);
    document.head.appendChild(script);
  }

  addScript("https://threejs.org/build/three.js", function() {
    addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function() {
      addScript("https://threejs.org/examples/js/libs/stats.min.js", function() {
        threeReady();
      })
    })
  })
})();

three.js r86

TheJim01
  • 8,411
  • 1
  • 30
  • 54