three.js change mesh from scene - javascript

I want to change a mesh from a group, trriged by a button.
I'm loading an external .obj file:
loader.load( obj, function ( object ) {
createScene( object, mod.tipo, pid, cor.replace("#","0x") );
});
and add on a group
function createScene( geometry, name, id, cor ) {
geometry.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
var material = new THREE.MeshPhongMaterial( {
specular: 0xffffff,
shininess: 10,
side: THREE.DoubleSide,
map: THREE.ImageUtils.loadTexture('/3d/js/texturas/white.jpg'),
shading: THREE.SmoothShading
} );
material.color.setHex(cor);
child.material = material;
group.add( child );
}
and add this group in a scene: scene.add( group )
to change i set de visible of my mesh to false. But a want to remove it from scene and group.
I already try scene.remove('name') and scene.remove(mesh) but didnt work.
Someone know how to do this?

You probably want:
var toRemove = scene.getNodeByName ( 'name', true );
if (toRemove !== undefined)
scene.remove ( toRemove );
which searches in your scene for a node named name and then removes the resulting node from the scene.

I get a solution:
In my case i was using a group to join the meshes and rotate all of them to start position.
First i have to add the mashes directly in the scene. I could'n make it work on a group
Second i have a global variable that contain an array of all meshes. And as was tring to remove use this reference. I have to change this logic.
So i create this function:
var clearScene = function(name) {
var objsToRemove = scene.children;
for (var t = 0; t<objsToRemove.length; t++){
if (objsToRemove[t] instanceof THREE.Mesh) {
if (objsToRemove[t].name = name) {
scene.remove(objsToRemove[t]);
break;
}
}
}
}
it goes on each meshe looking for the mashe i want to delete. and simply call the remove frome the scene.
this works for me.
I have to change my group logic and mabe rotate mesh by mashe to default position, i think that i will have a better performance

Related

ThreeJS: Add Two Materials on an Mesh Object

In ThreeJS, it is possible to add more than one material to an Object3D/Mesh according to its documentation. We can use a single Material or use an array of Material:
Mesh typescript file class declaration and contructor (from ThreeJS src code):
export class Mesh<
TGeometry extends BufferGeometry = BufferGeometry,
TMaterial extends Material | Material[] = Material | Material[] // ### Here: Material[] ###
> extends Object3D {
constructor(geometry?: TGeometry, material?: TMaterial);
Here is my problem which I can't seem to be able to solve...
When I use a single Material, my Mesh is displayed. However, when I use two materials as an array, my Mesh won't display. I also don't have any error print out in the console when rendering the scene.
My ultimate goal here is to be able to have to separate materials for the inner and the outer part of my object.
Here is my code:
export function init(radius: number = 18.0, innerColor: number = 0xFFFFFF, outerColor: number = 0x444444) {
var obj = new Object3D();
loader.load(
objPath,
function(object){
obj = object;
const mesh = obj.children[0] as Mesh;
// WORKING:
mesh.material = new MeshPhongMaterial({color: outerColor});
// NOT WORKING: Using two materials
// mesh.material = new Array<Material>(new MeshPhongMaterial({color: outerColor}), new MeshPhongMaterial({color:innerColor}));
mesh.scale.setLength(radius)
scene.add(mesh);
},
function (error){
console.log(error)
}
);
}
Why can't I manage to see my object when using two materials ?
I known there was the MeshFaceMaterial in previous version and the material array acceptance of the contructor is supposed to be a replacement for that in some sens.
ThreeJS version: r128
Any help would be appreciated !
The easiest way is to clone your mesh and assign two separate materials, one for the inside, another for the outside:
const meshOuter = obj.children[0] as THREE.Mesh;
const meshInner = meshOuter.clone();
// Outer mesh shows front side
meshOuter.material = new THREE.MeshPhongMaterial({
color: outerColor,
side: THREE.FrontSide
});
// Inner mesh shows back side
meshInner.material = new THREE.MeshPhongMaterial({
color: innerColor,
side: THREE.BackSide
});
// Scale inner mesh down just a bit to avoid z-fighting
meshInner.scale.multiplyScalar(0.99);

Alternating materials on one object

I'm a beginner using three.js and I am trying to have two materials defined on one single object, and alternate between the two using a visibilty flag, but with no success.
Is there another way, or can this be done?
var materials = [
new THREE.MeshPhongMaterial( { color: 0x00ff00,visible:true, shininess: 1 } ),
new THREE.MeshPhongMaterial( { color: 0xff0000,visible:false, shininess: 1 } )
];
obj= THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
scene.add( obj);
scene.traverse(function (node){
if(node instanceof THREE.Mesh) {
node.visible =!node.visible;
}
});
I will entually aplly this to all objects in the scene that's why I'm using the scene.traverse
It looks like you're trying to apply visibility to the materials, yet you're checking the meshes during your traverse. Remove the visibility: true/false from your material definitions, and add the following line:
obj= THREE.SceneUtils.createMultiMaterialObject( geometry, materials );
obj.children[1].visible = false; // add this line
scene.add( obj);
This will apply visibility = false to the second mesh created by createMultiMaterialObject. Your traverse will then correctly flip the visibility of the meshes.
As you get to know THREE.js better, you'll want to look into THREE.MultiMaterial and geometry groups for applying multiple materials to a single mesh.

THREE.js - add a THREE.SkinnedMesh to a custom skeleton structure

I'm trying to define a model of the human body in THREE.js using the classes THREE.Bone, THREE.Skeleton and THREE.SkinnedMesh.
I defined a custom skeleton structure made of 12 body parts, each of which is a THREE.Bone instance, and used the .add() method to define parent / child relationships among them. Finally, I created a standard THREE.Object3D as the body root that is parent of the full skeleton.
Posting only part of the structure for conciseness:
// create person object
var body_root = new THREE.Object3D()
// create torso
var torso = new THREE.Bone();
torso.id = 1;
torso.name = "torso";
x_t = 0;
y_t = 0;
z_t = 0;
torso.position.set(x_t,y_t,z_t);
x_alpha = 0 * Math.PI;
y_alpha = 0 * Math.PI;
z_alpha = 0 * Math.PI;
torso.rotation.set(x_alpha,y_alpha,z_alpha);
// create right arm
var right_arm = new THREE.Bone();
right_arm.id = 2;
right_arm.name = "right_arm";
x_t = -TORSO_WIDTH / 2;
y_t = TORSO_HEIGHT;
z_t = 0;
right_arm.position.set(x_t,y_t,z_t);
x_alpha = 0 * Math.PI;
y_alpha = 0 * Math.PI;
z_alpha = 0 * Math.PI;
right_arm.rotation.set(x_alpha,y_alpha,z_alpha);
// add right_arm as child of torso
torso.add( right_arm );
This works just fine, and after loading the page I can access the model and traverse it correctly through the console.
However, when I try to render the skeleton in the scene things get tricky.
1. How can I add a THREE.SkinnedMesh for a custom skeleton structure?
In the documentation (check source code) a CylinderGeometry and a SkinnedMesh are created for all the bones jointly
var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 );
var mesh = THREE.SkinnedMesh( geometry, material );
and then the bone structure is binded:
// See example from THREE.Skeleton for the armSkeleton
var rootBone = armSkeleton.bones[ 0 ];
mesh.add( rootBone );
// Bind the skeleton to the mesh
mesh.bind( armSkeleton );
This works perfectly for the simple example in the documentation (5 bones each one parent of the next one), but how can I adapt this example to a more complex structure in which some bones have multiple children? And how can I implement bones with different geometry? For instance I would like to implement joints like shoulder and elbow with a sphere for which I can only change rotation and body parts like arm and forearm with cylinders having different base radius.
Is it possible to define a SkinnedMesh for each joint independently and for a more complex structure than the one in the example? If so how do you link them all together?
2. Can I add a THREE.SkeletonHelper to the scene without defining a skinned mesh but using only the bones?
Since I don't know the answer to question 1 I decided to simply try to render the skeleton structure. This is done in other examples (such as this one) by creating a THREE.SkeletonHelper instance and adding that to the scene.
I tried passing the body_root variable (instead of the SkinnedMesh) to the constructor and the helper is created, but not rendered.
helper = new THREE.SkeletonHelper( body_root );
helper.material.linewidth = 3;
scene.add( helper );
In order to visualize the helper it needs to be binded to a mesh, even if the mesh is not added directly to the scene, i.e. adding the line mesh.bind(armSkeleton) visualizes the skeleton helper.
Is this possible at all to visualize the skeleton helper without defining a mesh? If so how?
NOTE on question 2:
I believe this should be possible, since the THREE.SkeletonHelper class defines internally its own geometry and material, so it should be possible to render it without needing the mesh of the skeleton:
THREE.SkeletonHelper = function ( object ) {
this.bones = this.getBoneList( object );
var geometry = new THREE.Geometry();
for ( var i = 0; i < this.bones.length; i ++ ) {
var bone = this.bones[ i ];
if ( bone.parent instanceof THREE.Bone ) {
geometry.vertices.push( new THREE.Vector3() );
geometry.vertices.push( new THREE.Vector3() );
geometry.colors.push( new THREE.Color( 0, 0, 1 ) );
geometry.colors.push( new THREE.Color( 0, 1, 0 ) );
}
}
geometry.dynamic = true;
var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors, depthTest: false, depthWrite: false, transparent: true } );
THREE.LineSegments.call( this, geometry, material );
this.root = object;
this.matrix = object.matrixWorld;
this.matrixAutoUpdate = false;
this.update();
};

How to use the Raycaster with a CombinedCamera?

I try to use a Raycaster (for selection) that works fine with a PerspectiveCamera but doesn't work with a CombinedCamera.
First it seems that CombinedCamera is not supported by the Raycaster, so among those line of three.js I add this :
if ( camera instanceof THREE.CombinedCamera ) {
if( camera.inPerspectiveMode ) {
camera = camera.cameraP;
} else if ( camera.inOrthographicMode ) {
camera = camera.cameraO;
}
}
if ( camera instanceof THREE.PerspectiveCamera ) {
...
So as it refers to the nested camera, however that doesn't do the trick because, I believe, the nested cameras position-quaternion-rotation are not updated ??
How can I achieve this and make Raycaster work with both Ortho and Perspective modes of a CombinedCamera ?
The renderer needs world matrix data for the raycasting to work. Make the following modification to the CombinedCamera code:
// Add to the .toPerspective() method:
this.matrixWorldInverse = this.cameraP.matrixWorldInverse; //
this.matrixWorld = this.cameraP.matrixWorld; //
// and to the .toOrthographic() method add:
this.matrixWorldInverse = this.cameraO.matrixWorldInverse; //
this.matrixWorld = this.cameraO.matrixWorld; //
r73.

Applying texture to threejs object

I'm having trouble applying a texture to an object I exported. My code looks like this:
var loader = new THREE.ObjectLoader();
var texture = THREE.ImageUtils.loadTexture('models/mountain/mountain.png');
loader.load("models/mountain/mountain.json", function (obj) {
var material = new THREE.MeshPhongMaterial({
map: texture
});
mesh = new THREE.Mesh( obj, material );
scene.add( mesh );
});
Just adding the obj to the scene works fine, but when I have to set a mesh and texture I get an error. What should the correct syntax be?
your problem may be that the "obj" returned by the ObjectLoader is actually just a Object3D. The objects containing the actual geometry and materials are children of this "obj".
So to change material you need to:
for(var i = 0; i < obj.children.length; i++)
{
obj.children[i].material = new THREE.PhongMaterial...
}
Also, please look into the MTL loader. OBJ/MTL loader is the usual way to use textured OBJs, as seen in the example: http://threejs.org/examples/#webgl_loader_obj_mtl

Categories