Vardan Betikyan
Vardan Betikyan

Reputation: 394

Three.js - How to set position relative to an object's position and direction?

I'm trying to get my 2nd object to be directly behind (-distance) my 1st object that has been rotated.

Let's say I have 2 objects:

var object1 = new THREE.Object3D();
object1.position.set(5, 10, 53);
object1.rotateX(1);
object1.rotateY(1.5);


var distance = 20; //place object2 20 units behind object1
var object2 = new THREE.Object3D();
object2.position.set( /*position object2 right behind object1 -distance */);
object2.lookAt(object1);

In this instance, how do I place object2 directly behind object1 which has been rotated?

Visual 2D example. Not to scale

enter image description here

Upvotes: 7

Views: 6068

Answers (2)

TheJim01
TheJim01

Reputation: 8866

In this specific use-case, you can add object2 to object1, and simply set object2's position to a single-axis value of the distance you want, in whatever axis serves as "behind" object1.

// given: object1, object2
// assuming: the meshes' "forward" direction is locally +Z, both "up" are +Y

scene.add( object1 )

object1.add( object2 )

object2.position.z = -distance

A few clarifications:

the meshes' "forward" direction is locally +Z

This is important for determining what "behind" means. For example, a car would have the headlights pointing in the +Z direction.

both "up" are +Y

This is another aspect of the model orientation. If the "up" direction of both models is +Y, then both are "upright" relative to each other. This is like saying that for two cars, both of their roofs are oriented in the +Y direction.

How this works:

Given that both meshes are--in their base orientation--oriented the same, then what you can do is manipulate object2 relative to object1. You can do this by making object2 a child of object1, which means object2 will now perform its transformations within object1's local space, rather than world space. This is possible because Mesh is a derivative of Object3D, which is a generic 3D container in three.js. As a child, object2 automatically inherits object1's transformations, so as you move/rotate object1, object2 will follow.

How this won't work

You can continue chaining children to your heart's content, but at some point you might want to make one of the objects in your chain do something relative to an external or global object. Unwinding the transformations will take a few extra steps before you can perform your desired actions.

Upvotes: 2

Mugen87
Mugen87

Reputation: 31026

Do it like so:

let camera, scene, renderer;

init();
animate();

function init() {

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 100);
  camera.position.set(5, 10, 55);

  scene = new THREE.Scene();

  const geometry = new THREE.PlaneGeometry();
  const material = new THREE.MeshNormalMaterial();

  const mesh1 = new THREE.Mesh(geometry, material);
  mesh1.position.set(5, 10, 53);
  mesh1.rotateX(1);
  mesh1.rotateY(1.5);
  scene.add(mesh1);

  const mesh2 = new THREE.Mesh(geometry, material);
  scene.add(mesh2);

  const v1 = new THREE.Vector3(0, 0, 1).applyQuaternion(mesh1.quaternion);
  mesh2.quaternion.copy(mesh1.quaternion);
  mesh2.position.copy(mesh1.position).add(v1.multiplyScalar(-2));

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.target.copy(mesh1.position);
  controls.update();

}

function animate() {

  requestAnimationFrame(animate);
  renderer.render(scene, camera);

}
body {
      margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>

The idea is to apply the rotation of object1 to object2 and also use it to compute the position behind object1. This is done by applying the rotation to a vector which is then scaled by a distance value (in the above case -2) and then added to object1's position value.

Upvotes: 4

Related Questions