Rotating a mesh which is only a part of an object

Hello,

I’d like to add something to this animation. Namely, I’d like to do something like this animation that I did with POV-Ray:

gfycat

That is, I want that each Hopf torus rotates around its cone. This is very easy with POV-Ray (but of course this is not an interactive animation), but I don’t know how to start with three.js. I would appreciate any hint.
I have an idea but I’m not sure it’s a good one: assuming a rotation of 2° at each step, I would do 180 objects, and in the animation I would do 1) scene.add(object[0]), 2) scene.remove(object[0]); scene.add(object[1]), etc… Is it a good idea ? I will try now unless someone here stops me. Not sure I will manage in fact… not even sure this is possible.

That almost works. I’ve done:

var objects = new Array(10);
for(var k=0; k<10; k++){
    objects[k] = new THREE.Object3D();
    for (var i = 0; i < 20; i++) {
        var axis2 = new THREE.Vector3().fromArray(points[i]);
        var mesh = new THREE.Mesh(bufGeom, material);
        var transfoMatrix = reorient(axis1, axis2);
        mesh.matrix = transfoMatrix.multiply(new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1),k*36));
        mesh.matrixAutoUpdate = false;
        objects[k].add(mesh);
        var cone = new THREE.Mesh(coneGeom, coneMaterial);
        var B = getRotation(new THREE.Vector3(0, -h, 0), axis2);
        cone.matrix = B;
        cone.matrixAutoUpdate = false;
        objects[k].add(cone);
        objects[k].name = k.toString();
    }
}

then:

var kk = 0;
function render() {
    var object = scene.getObjectByName(objects[kk].name);
    scene.add(objects[kk]);
    renderer.render(scene, camera);
    //object.rotation.x += dgcontrols.rotationSpeed;
    //object.rotation.y += dgcontrols.rotationSpeed;
    camera.position.z = dgcontrols.cameraz;
    kk += 1;
    if(kk == 10){
        kk = 0;
    }
    scene.remove(object);
    requestAnimFrame(render);
}

But scene.remove(object) has no effect. I’m going to post a fiddle.

EDIT- Here is the result: fiddle.

I’m also wondering how to implement the dragging.

EDIT- Now that is better. Stupid of me, I cannot do scene.getObjectByName before the name is added to the scene! So I do scene.remove(objects[kk]) fiddle

EDIT- Yeah this works: fiddle and I have the dragging. Very nice. But I don’t manage to implement the automatic rotation of the global scene.

EDIT- Yeah I have the automatic rotation. I can’t post more than three links. I’ve done:

    function render() {
      for(var k=0; k<180; k++){
        objects[k].rotation.x += dgcontrols.rotationSpeed;
        objects[k].rotation.y += dgcontrols.rotationSpeed;
      }
      scene.add(objects[kk]);
      ......

Question closed! Unless you have some improvements to suggest.

Just some feedback to your fiddle:

The following code snippet in your render() function is no good approach:

scene.add(objects[kk]);
renderer.render(scene, camera);
scene.remove(objects[kk]);

You should create your objects once and then animate them by changing their transformation. It’s very inefficient to create an object for each keyframe. Besides, instead of developing your own controls, it’s way more reliable to use something like THREE.OrbitControls. In this way, you get an automatic rotation of your camera around your object/scene for free (by setting controls.autoRotate to true).

Thank you. But we apply a transformation to a mesh, not to an object. Maybe this is possible to apply a transformation to an object, I don’t know, but in this case this is not what we want: each object is composed of 20 meshes, and each mesh has its own transformation. So you mean I should store the meshes in a two-dimensional array? I’m not sure to understand.

I’ve never tried OrbitControls, I will give it a look.

Hmm I’m realizing that I need 20 transformation matrices but I create them 180 times, not good…
So I’ve tried to improve that and I don’t understand something. This is a general Javascript question.
When I do:

for (var i = 0; i < 20; i++) {
  var axis2 = new THREE.Vector3().fromArray(points[i]);
  var mesh = new THREE.Mesh(bufGeom, material);
  var transfoMatrix = reorient(axis1,axis2).multiply(new THREE.Matrix4()
    .makeRotationAxis(new THREE.Vector3(0, 0, 1), k * 2 * pi / 180));
  mesh.matrix = transfoMatrix;
  ......

then that works, but when I do:

var transfoMatrices = new Array(20);
for (var i = 0; i < 20; i++) {
    var axis2 = new THREE.Vector3().fromArray(points[i]);
    transfoMatrices[i] = reorient(axis1, axis2);
}
for (var k = 0; k < 180; k++) {
  objects[k] = new THREE.Object3D();
  for (var i = 0; i < 20; i++) {
      var mesh = new THREE.Mesh(bufGeom, material);
      var transfoMatrix = transfoMatrices[i].multiply(new THREE.Matrix4()
          .makeRotationAxis(new THREE.Vector3(0, 0, 1), k * 2 * pi / 180));
      mesh.matrix = transfoMatrix;
      ......

that does not work. The multiplication by the makeRotationAxis is not performed! What is this joke please? (I’m not fluent in Javascript).

But this works:

var transfoMatrix = new THREE.Matrix4()
  .makeRotationAxis(new THREE.Vector3(0, 0, 1), k * 2 * pi / 180)
  .premultiply(transfoMatrices[i]);

As if Javascript ignored everything after transfoMatrices[i].

1 Like

Have a look at this simple example: https://jsfiddle.net/f2Lommf5/

An instance of THREE.Mesh is always a THREE.Object3D. So you can transform it e.g. by changing .position, .rotation and .scale. In the example, the box rotates without creating it multiple times.

I have understood! So I’ve done:

var transfoMatrices = new Array(20);
var rotationMatrices = new Array(20);
for (var i = 0; i < 20; i++) {
  var axis2 = new THREE.Vector3().fromArray(points[i]);
  transfoMatrices[i] = reorient(axis1, axis2);
  rotationMatrices[i] = getRotation(new THREE.Vector3(0, -h, 0), axis2);
}
var tori = new Array(20);
var cones = new Array(20);
for (var i = 0; i < 20; i++) {
  tori[i] = new THREE.Mesh(bufGeom, material);
  object.add(tori[i]);
  var cone = new THREE.Mesh(coneGeom, coneMaterial);
  cone.matrix = rotationMatrices[i];
  cone.matrixAutoUpdate = false;
  object.add(cone);
}
scene.add(object);

// rendering function ------------------------------------------------------
var kk = 0;
function render() {
  object.rotation.x += dgcontrols.rotationSpeed;
  object.rotation.y += dgcontrols.rotationSpeed;
  for (var i = 0; i < 20; i++) {
    var transfoMatrix = new THREE.Matrix4()
      .makeRotationAxis(new THREE.Vector3(0, 0, 1), kk * 2 * pi / 180)
      .premultiply(transfoMatrices[i]);
    tori[i].matrix = transfoMatrix;
    tori[i].matrixAutoUpdate = false;
  }
  renderer.render(scene, camera);
  camera.position.z = dgcontrols.cameraz;
  kk += 1;
  if (kk == 180) {
    kk = 0;
  }
  requestAnimFrame(render);
}

So no need of 180 objects. Could even be improved by storing the makeRotationAxis(new THREE.Vector3(0, 0, 1), kk * 2 * pi / 180) once for all, instead of calculating this matrix in the animation, each time.

This is magic to me and this looks obvious to you. That should be because I’ve never followed a course in Javascript, and frankly I don’t understand how this language works (but that does not prevent me to develop some apps for my job). The point I don’t understand is that tori[i] is linked to the scene: after the scene.add, any future modification to tori[i] is propagated to the scene. I’m fluent in R and there’s no such thing in R, that’s why this point looks magic to me.

Thank you!