Three.js - Replace skinnedMesh child of object - three.js

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)
});

Related

Three.js FBXLoader2, change color of single Mesh (in Group or detached)

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 );

How to find sub-parts of a .OBJ 3D model using three.js?

I need to implement a functionality where user can upload a OBJ 3D model and then I will show different sub-parts of that model in browser. (Same as https://www.sculpteo.com is doing.).
But I am unable to find sub-parts of OBJ model. I am using three.js to show OBJ model in browser.
Is there any way to find sub-parts to OBJ model using three.js?
I am sharing code to load OBJ model =>
var mtlLoader = new THREE.MTLLoader();
mtlLoader.setPath( 'path' );
mtlLoader.load( 'model.mtl', function( materials ) {
materials.preload();
var objLoader = new THREE.OBJLoader();
objLoader.setMaterials( materials );
objLoader.setPath( 'path' );
objLoader.load( 'model.obj', function ( object ) {
scene.add( object);
});
});
Now I don't know how to find sub-parts of this "model.obj". Kindly help. Thanks in advance.
OJBLoader returns (THREE.Object3D() (it was in r71)) THREE.Group() (r81) with children of THREE.Mesh.
You'll get sub-parts as child meshes of the object only if your .obj file has groups of objects. Without it, you'll get just a sinlge child mesh.
Read about Wavefront .obj file format.
So, if your data of sub-parts grouped under
o [object name]
tag, then you'll have as many child meshes as you have "o" groups in your .obj file and then you can traverse.
upd#1: It also works with "g" tags.
g [group name]
The example based on "webgl_interactive_cubes" from Threejs.org, the data of sub-parts grouped with "g" tags (skull, uteeth, jaw, lteeth) in the .obj file
When you load the objects you can do this inside your callback function :
objLoader.load('yourUrl.obj', function (object) {
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
console.log(child);
// here you can make what you want with the children of object
}
});
});

Change Object parent in Three.js?

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 );

How to select a group (object3d) with domevent.js?

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

Computing Bounding Sphere after static .OBJ loading with Three.js

I got the following code for loading a simple, non-animated .OBJ with a .MTL into Three.js. It's very simple indeed and works well, but when I add the line with computeBoundingSphere(), it fails with a "TypeError: object.computeBoundingSphere is not a function" :
var callbackIrali1 = function ( event ) {
var object = event.content;
object.computeBoundingSphere();
scene.add( object );
};
var loaderIrali1 = new THREE.OBJMTLLoader();
loaderIrali1.addEventListener( 'load', callbackIrali1);
loaderIrali1.load( 'models/obj/irali/irali.obj', 'models/obj/irali/irali.mtl' );
The issue is, I can't find what type of object might be this event.content returned by the callback, and so I can't find how to apply the computeBoundingSphere() function to it.
Finally found it out by myself :
- The object returned by the Loader is an Object3D,
- Thus, it has 2 children : mesh and materials,
- So you have to find the first child, then extract its geometry, and then compute the bounding sphere.
Which gives the following line :
object.children[0].geometry.computeBoundingSphere();

Resources