How to link objects and move them relatively?

I created kind of mannequin with three.js.

I want to make it possible to:

  1. link all objects with connection child-parent
  2. move objects relatively (if hand moved, than elbow whould be moved, but if wrist moved, than other parts should not be moved)

I wrote code below and made jsfiddle example. Not sure whether it is correct way.

var scene, camera, renderer, pivot;

//main
init();
animate();

//init
function init() {
  //scene
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xf0f0f0);

  //camera
  camera = new THREE.PerspectiveCamera(140, window.innerWidth / window.innerHeight, 0.1, 10000);

  //neck
  var geometry = new THREE.BoxBufferGeometry(2, 3, 1);
  var material = new THREE.MeshNormalMaterial({
    transparent: true,
    opacity: 0.5
  });
  var figure = new THREE.Mesh(geometry, material);
  figure.position.set(0, 1.5, 0);

  //body
  var geometry2 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
  /* geometry2.rotateZ(THREE.Math.degToRad(90)); // ROTATE GEOMETRY SO IT'S IN THE CORRECT ORIENTATION */
  var figure2 = new THREE.Mesh(geometry2, material);
  figure2.position.set(0, 1.5, 0); // MOVE THE GEOMOETRY UP BY HALF SO PIVOT IS AT THE BOTTOM OF THE GEO
  /* figure2.rotation.set(0, 0, Math.PI / 2); */
  figure.add(figure2);

  //head
  var geometry3 = new THREE.SphereGeometry(0.75, 32, 32);
  var material3 = new THREE.MeshBasicMaterial({
    color: 0xffff00
  });
  var sphere3 = new THREE.Mesh(geometry3, material3);
  sphere3.position.set(0, 2.5, 0);
  figure.add(sphere3)

  //right shoulder 
  var geometry4 = new THREE.SphereGeometry(0.25, 32, 32);
  var material4 = new THREE.MeshBasicMaterial({
    color: 0xffff00
  });
  var sphere4 = new THREE.Mesh(geometry4, material4);
  sphere4.position.set(1.25, 1.25, 0);
  figure.add(sphere4)

  //right hand top
  var geometry5 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
  var figure5 = new THREE.Mesh(geometry5, material);
  figure5.position.set(1.25, 0.25, 0);
  figure.add(figure5);

  //right elbow
  var geometry6 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere6 = new THREE.Mesh(geometry6, material3);
  sphere6.position.set(1.25, -0.75, 0);
  figure.add(sphere6)

  //right hand bottom
  var geometry7 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
  var figure7 = new THREE.Mesh(geometry7, material);
  figure7.position.set(1.25, -1.75, 0);
  figure.add(figure7);
  
  //right hand bottom sphere
  var geometry8 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere8 = new THREE.Mesh(geometry8, material3);
  sphere8.position.set(1.25, -2.75, 0);
  figure.add(sphere8);
  
  //right wrist
  var geometry9 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
  var figure9 = new THREE.Mesh(geometry9, material);
  figure9.position.set(1.25, -3.25, 0);
  figure.add(figure9);
  
  //left shoulder 
  var geometry10 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere10 = new THREE.Mesh(geometry10, material4);
  sphere10.position.set(-1.25, 1.25, 0);
  figure.add(sphere10)

  //left hand top
  var geometry11 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
  var figure11 = new THREE.Mesh(geometry11, material);
  figure11.position.set(-1.25, 0.25, 0);
  figure.add(figure11);

  //left elbow
  var geometry12 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere12 = new THREE.Mesh(geometry12, material3);
  sphere12.position.set(-1.25, -0.75, 0);
  figure.add(sphere12)

  //left hand bottom
  var geometry13 = new THREE.BoxBufferGeometry(0.5, 1.5, 0.5);
  var figure13 = new THREE.Mesh(geometry13, material);
  figure13.position.set(-1.25, -1.75, 0);
  figure.add(figure13);
  
  //left hand bottom sphere
  var geometry14 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere14 = new THREE.Mesh(geometry14, material3);
  sphere14.position.set(-1.25, -2.75, 0);
  figure.add(sphere14);
  
  //left wrist
  var geometry15 = new THREE.BoxBufferGeometry(0.5, 0.5, 0.5);
  var figure15 = new THREE.Mesh(geometry15, material);
  figure15.position.set(-1.25, -3.25, 0);
  figure.add(figure15);
  
  //left hip
  var geometry16 = new THREE.SphereGeometry(0.5, 32, 32);
  var sphere16 = new THREE.Mesh(geometry16, material3);
  sphere16.position.set(-0.5, -2.25, 0);
  figure.add(sphere16);
  
  //left haunch
  var geometry17 = new THREE.BoxBufferGeometry(1, 1.75, 1);
  var figure17 = new THREE.Mesh(geometry17, material);
  figure17.position.set(-0.5, -3.65, 0);
  figure.add(figure17);
  
  //left knee
  var geometry18 = new THREE.SphereGeometry(0.5, 32, 32);
  var sphere18 = new THREE.Mesh(geometry18, material3);
  sphere18.position.set(-0.5, -5, 0);
  figure.add(sphere18);
  
  //left shin
  var geometry19 = new THREE.BoxBufferGeometry(1, 1.75, 1);
  var figure19 = new THREE.Mesh(geometry19, material);
  figure19.position.set(-0.5, -6.35, 0);
  figure.add(figure19);
 
  //left ankle
  var geometry20 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere20 = new THREE.Mesh(geometry20, material3);
  sphere20.position.set(-0.5, -7.5, 0);
  figure.add(sphere20);
  
  //left foot
  var geometry21 = new THREE.BoxBufferGeometry(1, 0.25, 1.5);
  var figure21 = new THREE.Mesh(geometry21, material);
  figure21.position.set(-0.5, -7.85, 0.25);
  figure.add(figure21);
  
  //right hip
  var geometry22 = new THREE.SphereGeometry(0.5, 32, 32);
  var sphere22 = new THREE.Mesh(geometry22, material3);
  sphere22.position.set(0.5, -2.25, 0);
  figure.add(sphere22);
  
  //right haunch
  var geometry23 = new THREE.BoxBufferGeometry(1, 1.75, 1);
  var figure23 = new THREE.Mesh(geometry23, material);
  figure23.position.set(0.5, -3.65, 0);
  figure.add(figure23);

  //right knee
  var geometry24 = new THREE.SphereGeometry(0.5, 32, 32);
  var sphere24 = new THREE.Mesh(geometry24, material3);
  sphere24.position.set(0.5, -5, 0);
  figure.add(sphere24);
  
  //right shin
  var geometry25 = new THREE.BoxBufferGeometry(1, 1.75, 1);
  var figure25 = new THREE.Mesh(geometry25, material);
  figure25.position.set(0.5, -6.35, 0);
  figure.add(figure25);
 
  //right ankle
  var geometry26 = new THREE.SphereGeometry(0.25, 32, 32);
  var sphere26 = new THREE.Mesh(geometry26, material3);
  sphere26.position.set(0.5, -7.5, 0);
  figure.add(sphere26);
  
  //right foot
  var geometry27 = new THREE.BoxBufferGeometry(1, 0.25, 1.5);
  var figure27 = new THREE.Mesh(geometry27, material);
  figure27.position.set(0.5, -7.85, 0.25);
  figure.add(figure27);


  //add figure
  scene.add(figure);

  scene.add(new THREE.AxesHelper());

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

  //add grid
  /* scene.add(new THREE.GridHelper(10, 20)) */

  camera.position.z = 5;

  //top view on object
  /*  camera.position.set(0, 10, 0);
   camera.up.set(0, 0, -1);
   camera.lookAt(0, 0, 0); */

  //controls to rotate camera
  controls2 = new THREE.OrbitControls(camera, renderer.domElement);
  controls2.minPolarAngle = Math.PI/2;
  controls2.maxPolarAngle = Math.PI/2;

  //controls to drag object in 3d
  /*   var cubePoints = [];
    cubePoints.push(figure2);
    var controls = new THREE.DragControls(cubePoints, camera, renderer.domElement); */

}


//animate
function animate() {
  requestAnimationFrame(animate);

  render();
};

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

Instead of adding all objects to the same root object, you can compose objects to represent the intended hierarchy. Meaning you do stuff like:

leftArm.add( leftForArm );
leftForArm.add( leftHand );
leftHand.add( leftThumb );

By doing this, the transformation of all ancestors will be honored (which allows you to move objects relative to its parent).

1 Like

Hi! Thank you! But how can I move them?

Have you tried changing the position property of your objects?

1 Like

Thanks! You helped a lot.

I thought there is some solution from the box in three.js. At the end I solved this with such function:

function onDocumentMouseMove( event ) {
	event.preventDefault();
	mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    raycaster.setFromCamera( mouse, camera );   

    if (clicked) { 
      if (typeof(lastMPos.x) != 'undefined') {
        //calculate how far the mouse has moved
        var deltaX = lastMPos.x - event.clientX,
            deltaY = lastMPos.y - event.clientY;

        //rotate your object accordingly
        pivot.rotation.z -= deltaX  * 0.03;
      }

      lastMPos = {
        x : event.clientX,
        y : event.clientY
    }
  }
}

Current problem is that when I go up from current position ob object it goes back. I think it is because rotation.z is connected with delta.x, but I can’t figure out how to take it consideration.

Another issue is that currently rotating object can go on another object. How can I limit it?