How to select a root Object3D using Raycaster - three.js

I have a parent Object3D that has child meshes. How can I use Raycaster to select only the root parent object?
my example

If you have a parent Object3D that has multiple child meshes, and you want to select the parent by raycasting, you can do the following:
Add the parent object to the array of objects:
var objects = [];
...
objects.push( root_parent_object );
Add to each child object a pointer to the root parent object:
child.userData.parent = root_parent_object;
Pass in the recursive flag to intersectObjects().
var intersects = raycaster.intersectObjects( objects, true );
Now when the raycaster intersects a child object, you can obtain the root object.
three.js r.68

I had similar need using collada objects exported from Sketchup. Meshes have a trail of multiple parents ahead of them so all I did was this:
if (intersects.length >0){
par = intersects[ 0 ].object.parent;
while(par.type !== "Group"){
par = par.parent;
}
groupName = par.name;
}

Related

Access A-Frame element from three.js object3D

From A-Frame, you can access an entity's object3D with .object3D or .getObject3D(), is there a way to do the reverse, when you are working with three.js objects, to get the element an object belongs to? Perhaps adding the parent element to userdata?
A-Frame attaches the entity to object3D as .el.
For example with an entity with a mesh:
document.querySelector('a-entity').getObject3D('mesh').el;
It also attaches to the group object3D:
document.querySelector('a-entity').object3D.el;
This is done during setObject3D().
For object3Ds that A-Frame does not directly manage and does not have a direct associated A-Frame entity, then we can walk up the scene graph to find the closest one with object3D.traverseAncestors.
I wrote a small function that traverses upwards using traverseAncenstors and returns an element if there is one.
function getParentEl( o ){
let p;
o.traverseAncestors( function( a ){
if( p === undefined && a.el ){
p = a;
}
});
if( p ){
return p.el
}
return;
}

three js recalculate vector 3 to child object

I have Vector3 in position.
I have scene childs:
planet = new THREE.Object3D();
city= new THREE.Object3D();
street= new THREE.Object3D();
scene.add(planet);
planet.add(city);
city.add(street);
how can i get correct world position of vector in each object(planet,city and street individually), with respect to position,scale and rotation of each object..
i try planet.worldToLocal(new THREE.Vector3( vector.x,vector.y,vector.z ) but it seem to work only from global to child object, not for recalculating from planet to city.
example:
planet.position.set(10,0,0);
city.position.set(10,0,0);
street.position.set(10,0,0);
if myVector is new THREE.Vector3(0,10,0), i need to get the same position in street object, that should be (30,10,0) how to get it by THREE functions??
You can get the world position of an object like so:
var position = object.getWorldPosition(); // creates a new THREE.Vector3()
or
var position = new THREE.Vector3();
object.getWorldPosition( position ); // reuses your existing THREE.Vector3()
Note: If you have modified the position/rotation/scale of any of the objects in the hierarchy since the last call to render(), then you will have to force an update to the world matrices by calling scene.updateMatrixWorld(). The renderer calls this for you, otherwise.
three.js r.71
I guess you want to use Vector3.add in combination with getWorldPosition():
planet.position.set(10,0,0);
city.position.set(10,0,0);
street.position.set(10,0,0);
myVector = new THREE.Vector3( 0, 10, 0 );
myVector.add( street.getWorldPosition() );
console.log( myVector ); // 30, 10, 0

Clone rotation from child and assign it to another child of a different parent in THREE.JS

I have a parent Object containing a child Object
var parent1 = new THREE.Object3D();
parent1.rotation.set(1,2,3);
scene.add(parent1);
var child1= new THREE.Object3D();
child1.rotation.set(0.5,0.1,0.3);
parent.add(child1);
and another parent containing another child.
var parent2= new THREE.Object3D();
scene.add(parent2);
var child2= new THREE.Object3D();
childC2.rotation.set(3,1.15,2);
parent.add(child2);
Now I want to give child2 the same rotation as child1 by rotating it's parent2.
As mentioned here, I can get the world-rotation from my original child1 like this:
var quaternion = new THREE.Quaternion();
child1.matrixWorld.decompose( new THREE.Vector3(), quaternion, new THREE.Vector3() );
and apply it to my parent2 like this:
parent2.quaternion.copy( quaternion );
Now parent2 has the same rotation like the original child1, but I want it's child child2 to have have the same rotation like child1 (only by modifing parent2)
I think this can be done by getting the difference of the world-rotation from parent2 and child2 and substracting this from the world-rotation of child1, to correct the offset generated by the rotation of child2.
But my knlowledge of quaternions and matrices is to bad to get it working.
Check out this fiddle, to understand my problem.
Thanks a lot.
UPDATE
I tried the approach of WestLangley. If my Objects are only rotated around x-axis it works like this (see fiddle)
//calculate the relative rotation of child2
THREE.SceneUtils.detach( child2, parent2, scene );
var rotX=parent2.rotation.x-child2.rotation.x;
var rotY=parent2.rotation.y-child2.rotation.y;
var rotZ=parent2.rotation.z-child2.rotation.z;
THREE.SceneUtils.attach( child2, scene, parent2 );
//combine the relative rotation of child2 and the 'world' rotation of child1
THREE.SceneUtils.detach( child1, parent1, scene );
rotX+=child1.rotation.x;
rotY+=child1.rotation.y;
rotZ+=child1.rotation.z;
THREE.SceneUtils.attach( child1, scene, parent1 );
parent2.rotation.set(rotX,rotY,rotZ);//assign it to parent2
If my Objects are rotated around x,y,z this is NOT working anymore (fiddle). Is this a problem with gimbal lock? Do I need to do the calculation with quaternions instead of Euler Objects?
So you want to rotate a parent object so that the parent's child has a particular orientation, and you want that particular orientation to match the orientation of a child object of a different parent. Whew!
Here is one way to do that:
// detach the children from their parents and add them to the scene
THREE.SceneUtils.detach( child2, parent2, scene );
THREE.SceneUtils.detach( child1, parent1, scene );
// here is the tricky part: add the second parent as a child of its former child
THREE.SceneUtils.attach( parent2, scene, child2 );
// copy the first child's rotation, and make sure the matrix is updated
child2.rotation.copy( child1.rotation );
child2.updateMatrixWorld( true );
// detach the parent from the child and add it to the scene
THREE.SceneUtils.detach( parent2, child2, scene );
// put the children back where the were before
THREE.SceneUtils.attach( child2, scene, parent2 );
THREE.SceneUtils.attach( child1, scene, parent1 );
Here is a fiddle: http://jsfiddle.net/715v2hr1/
three.js r.68

How to find the scene position of an object, within a rotating parent object

Within my THREE scene i have an Object that rotates. The child object is positioned at (92,92,92) within the rotating Object, so it orbits the centre position (0,0,0) is a spherical path with my mouse movement. How can i find the global position of the child object in respect to the scene as it rotates. I'm fairly new to THREE.js and thankful for any support in advance.
My code:
ObjectParent = new THREE.Object3D();
scene.add( ObjectParent );
ObjectChild = new THREE.Object3D();
ObjectParent.add( ObjectChild );
ObjectChild.position.set(92,92,92);
Render:
ObjectParent.rotation.y -= (target.y + ObjectParent.rotation.y) * 0.08;
ObjectParent.rotation.x += (target.x - ObjectParent.rotation.x) * 0.07;
ObjectParent.updateMatrixWorld();
scene.updateMatrixWorld();
First of all, you usually do not need to call
ObjectParent.updateMatrixWorld();
scene.updateMatrixWorld();
inside your render loop. The renderer will do that for you.
To find the world position of a child object, you can use this pattern:
var vector = new THREE.Vector3();
...
vector.setFromMatrixPosition( child.matrixWorld );
The renderer should have previously updated the scene matrices for you. If you have changed a parent's position since the last rendering, you will have to first call
parent.updateMatrixWorld();
to update the relevant matrices.
It is a good idea to look at the three.js source code so you understand what these functions do.
three.js r.67

Three.js - move custom geometry to origin

I have some custom geometries obtained from a STEP file conversion and I use the mouse to rotate them. They rotate around the origin of the scene, but since they are far from it, they seem rotating on a virtual sphere. How can I move them to the origin so that they don't seem "floating" around (I mean that I'd like to reduce to zero the radius of the virtual sphere). This is the example I'd like to move. I've tried setting their position to (0, 0, 0) doing:
object.position.x = 0;
object.position.y = 0;
object.position.z = 0;
but it didin't work.
The typical solution to this problem is to translate the geometry right after it is created. You do that by applying a translation matrix to the geometry like so:
geometry.applyMatrix( new THREE.Matrix4().makeTranslation( distX, distY, distZ ) );
EDIT: You can simply do this, instead:
geometry.translate( distX, distY, distZ ); // three.js r.72
The function geometry.computeBoundingBox() may be of help to you in determining an amount to translate.
However, I see in your case, you have multiple geometries, so it it a bit more complicated, but doable. You will need to translate each geometry by the same amount.
EDIT
Tip: Instead of adding each object to the scene, create a parent object, add it to the scene, and then add the objects to the parent.
var parent;
parent = new THREE.Object3D();
scene.add( parent );
parent.add( object1 );
parent.add( object2 );
// and so on...
Then in your render function, just rotate the parent, not the individual objects.

Resources