Is it possible to change the parent of any object?
For example:
scene.add(Object);
Object.Add(OtherObject);
OtherObject.parent = scene; // <-- Something like this
I just know that I can remove the Object and create it again in the new parent, but I'll hope there's another way. I got some Object that are on a plane, if I click them I want fix them to the camera so I can see all the time in front of the camera. And If I click them Again I wanna set the parent again to the plane.
Why did this dont work?
var obj = clicked.clone();
camera.add(obj);
obj.position.set(0,0,-20);
Easiest way is to use the detach and attach functions of the THREE.SceneUtils object:
THREE.SceneUtils.detach( child, parent, scene );
THREE.SceneUtils.attach( child, scene, parent );
Related
I have a camera drone animation model that I attach two objects to. The camera drone is just a black sphere with a texture. I attach a red sphere to the camera drone where the lens appears on its textureis, to make it look like a security camera lens. Works great. When I move the model, the red sphere moves with the camera drone perfectly as it moves and rotates.
However, I also attach a spotlight at the exact same place on the camera drone object. My desire is to have the spotlight beam come out of the camera drone lens so that it appears to emanate from the lens. However, when the camera drone moves, the spotlight stays in place and gets left behind, despite the fact I attach the spotlight the exact same way and in the exact same place as I attach the red sphere. In other words, when the camera drone moves away, I see the spotlight hanging in space where it was first created instead of it traveling in lock step with the camera drone.
Below is the code I use to create and attach the red sphere and spotlight. The code executes when the GLB loader callback executes.
Note: self.CAC.modelInstance is where the ThreeJS object for the camera drone animation model is stored. Also, AnimatedLight is the object I created to build a spotlight and animate it. Finally, initModelArgs is an object that contains some size, position, and other settings that are loaded from a file earlier.
Can someone tell me what I am doing wrong and how to fix this problem? Also, can you tell me what it is about the way that I think how the spotlight should work that is also wrong?
// PARAMETERS: url, onLoad, onProgress, onError
self.CAC.modelLoader.load(
// url
urlToModel,
// onLoad
(glb) => {
// Size.
glb.scene.scale.x = initModelArgs.theScale;
glb.scene.scale.y = initModelArgs.theScale;
glb.scene.scale.z = initModelArgs.theScale;
self.CAC.setModelInstance(glb.scene);
// Set the initial position.
self.CAC.modelInstance.position.x = initModelArgs.initialPos_X;
self.CAC.modelInstance.position.y = initModelArgs.initialPos_Y;
self.CAC.modelInstance.position.z = initModelArgs.initialPos_Z;
// Create an animation mixer for this model.
self.CAC.modelAnimationMixer = new THREE.AnimationMixer(self.CAC.modelInstance);
// Speed
self.CAC.modelAnimationMixer.timeScale = initModelArgs.theTimeScale;
// Add the model to the scene.
g_ThreeJsScene.add(self.CAC.modelInstance);
// Initialize the model completely. The camera drone has no
// animations because we animate it manually, so we pass
// NULL to let the initializeModelCompletely() function
// know that.
self.CAC.initializeModelCompletely(null);
// NOTE: Camera drone has no animations/actions. We animate it
// manually.
// -------------------- BEGIN: SUB-OBJECTS ------------
// Call updateCenterOfModel so our bounding box and center properties
// are correct.
self.CAC.updateCenterOfModel();
// Create the sub-objects necessary for emulating a light
// projector on the camera drone.
// .................... BEGIN: SUB-OBJECT - Camera Lens ............
const radius = 3;
const cameraLensObj =
new THREE.Mesh(
new THREE.SphereBufferGeometry( radius, 20, 20 ),
new THREE.MeshPhongMaterial( { color: 0xFF0000 } ));
cameraLensObj.position.set(0, 0, 15);
// Add it to the top level animation model.
self.CAC.modelInstance.add(cameraLensObj);
// .................... END : SUB-OBJECT - Camera Lens ............
// .................... BEGIN: SUB-OBJECT - Light Beam ............
const spotLightAsLightBeam_anim_obj =
new AnimatedLight(
`${self.CAC.modelName}-lens-light-beam`,
modelDeclJsonObj,
'SpotLight',
// Tell the animated light to augment our mini-menu
// instead of creating its own.
self);
// Call initialize model on the spotlight or we will not have
// the model instance filled in.
spotLightAsLightBeam_anim_obj.initializeModel(self.CAC.parentAnimManagerObj, initModelArgs);
const spotLightModelInstanceObj = spotLightAsLightBeam_anim_obj.CAC.modelInstance;
// Position the spotlight that acts as the camera drone's light
// beam right on top of the small sphere we use to emulate
// a projector's lens.
spotLightModelInstanceObj.position.set(0, 0, 15);
// Add it to the top level animation model.
self.CAC.modelInstance.add(spotLightAsLightBeam_anim_obj.CAC.modelInstance);
// .................... END : SUB-OBJECT - Light Beam ............
I try something like this to replace a skinnedMesh child of object. It is possible?
object.traverse(function(child){
child = [];
child = child1.clone(); // other object child with same skeleton and same child order but with different geometry and material (shoes)
});
I have a .fbx model which load via FBXLoader2.
When I add the model (which include 3 meshes) to the scene, it is added as a Group. Now I try to change the color of a single Mesh in the Group, but all 3 meshes are getting the color. Then i thought they might be "linked" because of the Group. So i detached them (SceneUtils.detach).
Now I have all the meshes in the scene. Still, when I change the color of a single mesh, all three of them get the color. When I console.log the mesh (in the group or detached) it shows me the correct mesh.
var loader = new THREE.FBXLoader( manager );
loader.load( 'somemodel.fbx', function( object ) {
model = object;
var modelLength = model.children.length;
for (i=0;i<modelLength;i++) {
THREE.SceneUtils.detach(model.children[0], model, scene);
}
scene.children[0].material.emissive.setHex( 0xff0000 );
}
When i try to change position or scale the mesh, it works fine.
Anybody had the problem before?
Just clone the material and replace it with original once.
scene.children[0].material = scene.children[0].material.clone();
scene.children[0].material.emissive.setHex( 0xff0000 );
I am using the latest version of Three.js(82) and importing my spot light from blender exporter(json). I have the following code when looping over all the scene objects after loading:
// loop
if(object instanceof THREE.SpotLight){
lightHelper = new THREE.SpotLightHelper(object);
scene.add(lightHelper);
}
// after loop
spot = scene.getObjectByName("Spot",true);
spot.target = scene.getObjectByName("Cube",true);
// in render() funcition
lightHelper.update();
The spotlight helper shows up but it never points to the target. If I try to add a spotlight to the scene manually, it works fine. I think it has to do something with the spotlight being in the child scene. Can anyone suggest a fix for this?
I've a problem with object3d selection on my scene.
I use the three.js r61 and the domevent.js libraries.
I have added the THREE.Object3D Patch, but doesn't seems to works.
I have a list of objects that are mesh or object3d.
When i try to capture an object click, all works fine if object is a mesh but not if it is a group.
Each object is added with objects.push(object); // mesh or object3d
Here is the code :
// Objects selection
THREE.Object3D._threexDomEvent.camera(camera);
THREE.Object3D._threexDomEvent.domElement(renderer.domElement);
for ( object in objects )
{
// Bind depends on object type
var bindControl = objects[object];
console.log('bind ' + bindControl.name);
bindControl.on('click', function(object3d) {
console.log('ok');
seletedObject = object3d.target;
console.log('selected : ' + object3d.target.name);
});
...
}
So the domevent works fine for a mesh that is directly in the scene, but if i click on a mesh that is in a group, as the group only is in the objects list, the click event is not fired.
I don't know how to make my object3d to be clickable.
If someone has an idea, it will be greatly appreciated.
Thanks
The code of domevents.js doesn't works with groups because of two reasons:
To detect intersection with or without the descendants you need to pass the second parameter as true on the intersectObjects function:
var intersects = this._raycaster.intersectObjects( boundObjs, true);
The event is attached to the parent element (the object3d or THREE.Group object) and when intersection is detected it returns the descendant object with the nearest intersection. So the _bound function will ty to get context of child element instead of parent. You have to change the behaviour of _objectCtxGet function:
THREEx.DomEvents.prototype._objectCtxGet = function(object3d){
if(typeof object3d._3xDomEvent == 'undefined' && typeof object3d.parent != 'undefined')
{
return object3d.parent._3xDomEvent;
}
return object3d._3xDomEvent;
}
So i found a solution don't know if it is the better one but it works at least with a group of 2 mesh.
Here is the code i modified in the ThreeX.domevent.js (in THREEx.DomEvent.prototype._onEvent)
var objectCtx = this._objectCtxGet(object3d);
var objectParent = object3d.parent;
while ( typeof(objectCtx) == 'undefined' && objectParent )
{
objectCtx = this._objectCtxGet(objectParent);
objectParent = objectParent.parent;
}
This is beacause the object clicked is not the one that is in the objects list, so we must found the parent that is in the list, and it work with this code.
Be aware that i've only tested it for my case and tested it in only some case, so take it carrefully.
Bye