首页 > 解决方案 > calling object3D children for unique styles / animations

问题描述

I'm wondering how I would go about calling the individual children of cube (mesh0, mesh1) so I'm able to set different styles / animations to them both.

AFRAME.registerComponent('multi_box', {
  schema: {},
  update: function() {
  for (var i = 0; i < 2; i++) {
    var material = new THREE.MeshBasicMaterial({color: "blue"});
    var geometry = new THREE.BoxGeometry(1, 1, 1);
    var cube = new THREE.Mesh(geometry, material);
    cube.position.x = i == 0 ? -1 : 1;
    cube.position.y = 0.5;
    cube.position.z = -5;

    this.el.setObject3D("mesh"+i, cube); //unique name for each object
}
    console.log(this.el.object3DMap)  
}
});

Codepen link: https://codepen.io/ubermario/pen/wrwjVG

I can console.log them both and see that they are unique objects to each other but I'm having trouble calling them:

var meshtest = this.el.getObject3D('mesh0')
console.log(meshtest.position)

I'v tried this method but with no luck: aframe get object3d children

Any help is appreciated :)

标签: three.jsaframe

解决方案


Instancing

In your for cycle, you create

  1. a new geometry instance
  2. a new material instance
  3. a new mesh that connect the previous two

Each new keyword creates a unique instance that is independent of the others. In your case mesh0 and mesh1 are fully independent of each other. If you change any property of an instance, like for example material color or position, the other(s) will not be affected by that. In fact you do that by assigning a different x position to each cube.

Storage

Your component holds a map of 3D objects. Each is identified by a unique name. You generate this name by concatenating the prefix mesh with the iteration number (value of i).

You can later access the cubes just the same way you created them. Either by name

this.el.getObject3D('mesh0')
this.el.getObject3D('mesh1')
//etc.

or by index

this.el.object3D.children[0]
this.el.object3D.children[1]

and you can manipulate them further. For example you can put his on Ln19 in your Codepen:

this.el.getObject3D('mesh0').position.y = 2;
this.el.object3D.children[1].position.z = -3;

Just for completeness: If you would omit the +i at the end, you would overwrite the same key again and again, so mesh would reference just the last cube and others would get lost.

Changing properties

Three.js has a nice API, but in javascript you always need to think what happens behind the scenes. You will see that while learning new stuff. For example:

this.el.object3D.children[1].position.z = -3;
this.el.object3D.children[1].material.color.set('#ffff00');
this.el.object3D.children[1].material.color = [1, 1, 0];

As you can see the position can be changed directly, but color needs a setter sometimes. Things get more complicated with vectors where you need to watch which methods change the current instance and which produce a new one. You could easily forget to clone it. Say you had:

var pos = new THREE.Vector3(-1, 0.5, -5)
for (var i = 0; i < 2; i++) {
    var material = new THREE.MeshBasicMaterial({color: "blue"});
    var geometry = new THREE.BoxGeometry(1, 1, 1);
    var cube = new THREE.Mesh(geometry, material);

    //wrong, since it will assign the object reference,
    //i.e. always the same object.
    //Thus, the cubes will be at one position in the end
    cube.position = pos;

    //right
    cube.pos = pos.clone();

    pos.x += 1;
    this.el.setObject3D("mesh"+i, cube); //unique name for each object
}

The difference is a bit more moderate topic on reference and value types. You will find many tutorials for that, for example this small gist I just found.

I hope this was helpful and wish you good progress in learning!


推荐阅读