31

I think this picture best explains my issue:

hooray for optical illusions

First I translate the box along the red line. Next, I want the effect of rotation to be the blue line in a, but what's actually happening is more like the blue line in b. It feels like changing the rotation is always relative to the original object space, but the translation (despite happening first) is always relative to the parent, and doesn't really affect the geometry points in relation to the object space. I apologize if that's confusing; clearly I'm new at this.

The important part of the code which produces this effect is below. Please keep in mind that the orientation of the image is different than this code produces; the image is merely an example to show the effect clearly.

var objectContainer = new THREE.Object3D();

var tubeRadius = 100;
var tubeGeometry = new THREE.CylinderGeometry(tubeRadius, tubeRadius, tubeRadius * 3, 36, 1, false);
var tube = new THREE.Mesh(tubeGeomtry, material);
scene.add( tube );

var boxes = new THREE.Object3D();
var boxEdge = 50;
var boxGeometry = new THREE.CubeGeometry(boxEdge, boxEdge, boxEdge);
var box1 = new THREE.Mesh( boxGeometry, material );
box1.translateX(tubeRadius + boxEdge / 2 + 5);
box1.translateY(boxEdge / 2);
box1.rotation = new THREE.Vector3(0, 2*Math.PI/3*0, 0);
boxes.add(box1);
var box2 = box1.clone();
box2.rotation = new THREE.Vector3(0, 2*Math.PI/3*1, 0);
boxes.add(box2);
var box3 = box1.clone();
box3.rotation = new THREE.Vector3(0, 2*Math.PI/3*2, 0);
boxes.add(box3);
scene.add( boxes );

The only solution I can think of is to wrap each box in another object space and rotate about that, but it seems like excessive work. What is the preferred method to achieve the result I'm looking for?

Share a link to this question
CC BY-SA 3.0
2
  • I don’t know Three.js, but how about just translating it by Math.cos(rotation) * boxEdge / 2, Math.sin(rotation) * boxEdge / 2 as well as the local rotation? – Ry- Mar 5 '13 at 2:13
  • That feels like double work, rotate and translate each box. Really what I want to do is rotate each clone about the same point, which is origin before the translation. – Nick Larsen Mar 5 '13 at 2:16
34

There are several ways of doing what you want, but I think the easiest is like so:

// parent
parent = new THREE.Object3D();
scene.add( parent );

// pivots
var pivot1 = new THREE.Object3D();
var pivot2 = new THREE.Object3D();
var pivot3 = new THREE.Object3D();

pivot1.rotation.z = 0;
pivot2.rotation.z = 2 * Math.PI / 3;
pivot3.rotation.z = 4 * Math.PI / 3;

parent.add( pivot1 );
parent.add( pivot2 );
parent.add( pivot3 );

// mesh
var mesh1 = new THREE.Mesh( geometry, material );
var mesh2 = new THREE.Mesh( geometry, material );
var mesh3 = new THREE.Mesh( geometry, material );

mesh1.position.y = 5;
mesh2.position.y = 5;
mesh3.position.y = 5;

pivot1.add( mesh1 );
pivot2.add( mesh2 );
pivot3.add( mesh3 );

Then in your render loop:

parent.rotation.z += 0.01;

EDIT: updated fiddle: https://jsfiddle.net/edqf7ugc/

three.js r.116

Share a link to this answer
CC BY-SA 4.0
2
  • Thanks for the example. As I mentioned in the question, this is what I was thinking. Is this a typical solution to the problem? I intend to develop this for a while and I just want to make sure I'm not shooting myself in the foot. – Nick Larsen Mar 5 '13 at 10:26
  • Yes. It is typical. The other solution is to have each box be a child of the scene, and compute the new position and rotation vector every frame using math. – WestLangley Mar 5 '13 at 14:39
6

Creating a compound object whose centre will be the point about which the inner objects rotate is one obvious answer, and would be very quick to write. Just create an Object3D and add your box to it.

A similar approach is covered by this question. It shifts the point of the vertices for an object, so it effectively has a new centre.

Alternatively, you can mess around with the matrices by hand. Try this:

var boxGeometry = new THREE.CubeGeometry(boxEdge, boxEdge, boxEdge);
var mr = new THREE.Matrix4();
var mt = new THREE.Matrix4();
mt.setPosition(new THREE.Vector3(0,tubeRadius,0));
var box1 = new THREE.Mesh( boxGeometry, material );
box1.applyMatrix(mt);
var box2 = box1.clone();
mr.makeRotationZ(2 * Math.PI /3);
box2.applyMatrix(mr);
boxes.add(box2);
var box3 = box1.clone();
mr.makeRotationZ(4 * Math.PI /3);
box3.applyMatrix(mr);
boxes.add(box3);
boxes.add(box1);
scene.add( boxes );
Share a link to this answer
CC BY-SA 3.0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.