Using three.js, and adapting instructions from West Langley's post provided here: Three.js: Adding and Removing Children of Rotated Objects, I set up a WebGL scene to which five cube meshes are added. Initially, all objects are children of the scene, then, I attach them to the fifth "parentCube" cube and translate it 100 units along the Y-Axis thereby translating the other four cubes and subsequently detach them.
After that, I want to independently translate the "parentCube" cube (previously the parent of the four cubes) back to the origin, however, when I perform that translation, the other four cube meshes also translate with the former parent cube mesh, even when I detached them.
This may be a very basic question, but how can I independently translate "parentCube" without affecting the position of the other cubes considering all of the above details? Where am I going wrong with the detachment? Any help would be appreciated. Thank you :)
Here's the code sample which I use to perform all of the above:
//Create parentCube mesh
var parentCube = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 10, 10, 10), new THREE.MeshBasicMaterial({ color: 0xa1ff11, wireframe: true }));
scene.add(parentCube);
//...create materials for the child cubes....
//create child cube mesh
for(var i = 0; i < 4; i++)
cubeMesh[i] = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 30, 30, 30), materials[i]);
//--> Set child cube world positions before the attachment to parentCube mesh
cubeMesh[0].position.set((100 / 2),(100 / 2),(100 / 2));
cubeMesh[1].position.set(-(100 / 2),(100 / 2),(100 / 2));
cubeMesh[2].position.set(-(100 / 2),-(100 / 2),(100 / 2));
cubeMesh[3].position.set((100 / 2),-(100 / 2),(100 / 2));
//Add child cubes to the scene
for(var i = 0; i < cubeMesh.length; i++)
scene.add(cubeMesh[i]);
//attach child cubeMesh[i] to parentCube mesh
for(var i = 0; i < 4; i++)
THREE.SceneUtils.attach(cubeMesh[i], scene, parentCube);
//--> Set positions of child elements after attachment to parentCube
cubeMesh[0].position.set((100 / 2),(100 / 2),(100 / 2));
cubeMesh[1].position.set(-(100 / 2),(100 / 2),(100 / 2));
cubeMesh[2].position.set(-(100 / 2),(100 / 2),-(100 / 2));
cubeMesh[3].position.set((100 / 2),(100 / 2),-(100 / 2));
//translate parentCube
parentCube.position.set(0,150,0);
parentCube.updateMatrixWorld();
//Attempt to detach child objects from parentCube
//And make them children of the scene
for(var i = 0; i < 4; i++)
{
cubeMesh[i].updateMatrixWorld();
THREE.SceneUtils.detach(cubeMesh[i], parentCube, scene);
}
//Attempt to translate parentCube back to origin
parentCube.position.set(0,0,0);
}
your line of code
THREE.SceneUtils.detach(cubeMesh[i], scene, parentCube);
should be
THREE.SceneUtils.detach(cubeMesh[i], parentCube, scene);
I have done a demo with your example, and what I believe should be te correct approach.
HTML
<body>
<button onclick="attachChild();">attach</button>
<button onclick="detachChild();">dettach</button>
</body>
JavaScript
var camera, scene, renderer;
var geometry, material1, material2;
var parentCube;
var cubeMesh = [];
var cameraControls;
var attached = true;
window.onload = function() {
init();
animate();
}
function init() {
camera = new THREE.PerspectiveCamera(75, 2, 1, 10000);
camera.position.z = 400;
camera.position.y = 100;
scene = new THREE.Scene();
geometry = new THREE.BoxGeometry(200, 200, 200);
material1 = new THREE.MeshBasicMaterial({ color: 0xff0000, wireframe: true });
//Create parentCube mesh
parentCube = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 1, 1, 1), material1);
scene.add(parentCube);
//...create materials for the child cubes....
material2 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
//create child cube mesh
cubeMesh[0] = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 1, 1, 1), material2);
cubeMesh[1] = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 1, 1, 1), material2);
cubeMesh[2] = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 1, 1, 1), material2);
cubeMesh[3] = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100, 1, 1, 1), material2);
//--> Set child cube world positions before the attachment to parentCube mesh
cubeMesh[0].position.set(100,100,0);
cubeMesh[1].position.set(-100,100,0);
cubeMesh[2].position.set(-100,-100,0);
cubeMesh[3].position.set(100,-100,0);
//Add child cubes to the scene
for (var i = 0; i < 4; i++)
parentCube.add(cubeMesh[i]);
//translate parentCube
parentCube.position.set(0,50,0);
renderer = new THREE.CanvasRenderer();
renderer.setSize(600, 300);
document.body.appendChild(renderer.domElement);
// CONTROLS
cameraControls = new THREE.OrbitControls(camera);
cameraControls.addEventListener( 'change', render );
}
function animate() {
cameraControls.update();
requestAnimationFrame(animate);
parentCube.rotation.z += 0.01;
render ();
}
function render () {
renderer.render(scene, camera);
}
function attachChild () {
if (attached) {
alert ("already attached");
} else {
for (var i = 0; i < 4; i++)
THREE.SceneUtils.attach(cubeMesh[i], scene, parentCube);
attached = true;
}
}
function detachChild () {
if ( ! attached) {
alert ("not attached");
} else {
for (var i = 0; i < 4; i++)
THREE.SceneUtils.detach(cubeMesh[i], parentCube, scene);
attached = false;
}
}
Notice specially that I add the children directly to the parent (not the scene), and that I consider them attached from the beginning. After that, detaching and reattaching them works as expected
How could this be used for a Rubik's cube simulation ?
I would just create all the cubes added to the scene.
Then, to perform a move, you have to
That worked well. Additionally, as I'm quite new to WebGL development, I wanted to know: Is it always necessary to reposition child elements in world space after parenting them to an object (cubeMesh[i] attached to parentCube, in this case), as I've done above? Or is there some easier way of working around that? Whenever I parent objects, the children occupy the position of the parent object even though I assign world space positions to the children prior to the attachment. Thanks in advance.
When you do the attach, the mesh shouldn't change the world coordinates. So, if it has been positioned before, it should keep the global position, and you shouldn't need to do anything else. If this is not the case, please post more of your code, and I'll take a look
I updated the main questions' code to reflect my queries posed in the comments. After creating the cubeMesh[i] child cubes (prior to the attachment to the parentCube), I set their global positions. Post the attachment of cubeMesh[i] to parentCube, I have to again reset their positions in world space (Kindly refer to the arrow-headed commented portions of the code). If I don't do that after the attachment, all the cubeMesh[i] meshes get repositioned at parentCubes' position, thereby losing their original world space positions. Thanks.
I believe that the problem is that you haven't gone thru any render between setting the objects position and attaching them to the parent. Is this a real approach (are you really in need of attach them to the parent just after creation?) if so, why don't add them to the parent instead of to the scene ?
Thanks for the example. Understood a lot from it. I'm actually working on modelling and animating a Rubik's Cube and as such cubeMesh[i] (the child cubes) will be attached and detached on the fly to the parentCube cube/object3D() (Whichever is used).