Three.js hiding objects of loaded model - javascript

I have model (exported from Blender) which contains two meshes. One mesh is rigged and animated character, second mesh - hair model. I need to select one of the meshes and hide it or change it's texture.
I load model like this:
jsonLoader.load('./models/character.js', function(geometry, materials) {
for(var i = 0; i < geometry.animations.length; i++){
THREE.AnimationHandler.add( geometry.animations[i] );
}
var character = new THREE.SkinnedMesh( geometry );
});
Now both meshes works like one solid mesh.

You can make an object invisible by setting its visible property to false.
character.visible = false;

You need to convert this two meshes in two different objects to make them selectable (see this nice post to learn how to select an object).
Once the object is selected you can change its property to make it visible or hide it.

Related

resizing individual models in a single geometry

I have a 3D model of my home town. I would like to use real time data to change the height of the buildings. In my first try, I loaded the buildings as individual meshes and called scene.add(buildingMesh) during setup.
var threeObjects = []
var buildingMesh = new THREE.Mesh(geometry, material)
threeObjects.push(buildingMesh);
$.each(threeObjects,function(i, buildingMesh)
{
buildingMesh.rotation.x += -3.1415*0.5;
buildingMesh.castShadow = true;
buildingMesh.receiveShadow = true;
scene.add(buildingMesh);
});
Which is too slow as my dataset consists of roughly 10.000 building.
So I took the approach to add all the (geometries of the) meshes to a single geometry and wrap that in a mesh to be added to the scene
singleGeometry.merge(buildingMesh.geometry, buildingMesh.matrix); //in a loop
var faceColorMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, vertexColors: THREE.VertexColors } );
combinedMesh = new THREE.Mesh(singleGeometry, faceColorMaterial);
scene.add(combinedMesh);
Just to make a proof of concept, I'm trying to change the height of a building when I click it. Alas, this is not working.
By adding a new id field, I can get a reference to the faces and vertices and change the color of the building, but I can not for the life of me, get them to to change height.
In my first version, I would just use something like:
buildingMesh.scale.z=2;
But as I have no meshes anymore, I'm kinda lost.
Can anybody help?
disclaimer: I'm new to Three.js, so my question might be stupid...hope it's not :)
If you combine all of your buildings into a single geometry, you're obliterating everything that makes the buildings distinct from each other. Now you can't tell building A from building B because it's all one big geometry, and geometry at its basic level is literally just arrays of points and polygons with no way of telling any of it apart. So I think it's the wrong approach to merge it all together.
Instead, you should take advantage of three.js's efficient scene graph architecture. You had the right idea at first to just add all the buildings to a single root Object3D ("scene"). That way you get all the efficiencies of the scene graph but can still individually address the buildings.
To make it load more efficiently, instead of creating the scene graph in three.js every time you load the app, you should do it ahead of time in a 3D modeling program. Build the parent/child relationships there, and export it as a single model containing all of the buildings as child nodes. When you import it into three.js, it should retain its structure.
JCD: That was not quite the question I asked.
But anyhow, I found a solution to the problem.
What I did was to merge all the geometries, but in stead of using the standard clone function in geometry.merge() I used a shallow reference, which made it possible for me to use the reference in threeObjects to find the correct building and resize the part of the geometry using Mesh.scale, followed by a geometry.verticesNeedUpdate = true;
For further optimization, I split the model into 5 different geometries and only updated the geometry that contained the building

how to use traverse in three.js to modify wireframe

I have several objects, when it was selected the check box would change the wireframe property to true or false ( run time) .
function toggleWireFrame(obj){
var f = function(obj2)
{
if(obj2.hasOwnProperty("material")){
obj2.material.wireframe=!obj2.material.wireframe;
}
}
obj.traverse(f);
}
1) Your code should work, if you call toggleWireFrame on each of the meshes, one by one.
toggleWireFrame(meshA);
toggleWireFrame(meshB);
This would make sense if each of these meshes are made up of several meshes and you need to toggle all the sub-meshes too. You might get mesh hierarchies like that a lot if you import models from an OBJ file, for example.
2) Or did you want to call toggleWireFrame only once and have all your meshes' wireframe toggled?
If that's the case, you will have to call
toggleWireFrame(scene);
or even
toggleWireFrame(myObject3D);
where myObject3D is an Object3D instance which is the parent of all the meshes that you want to toggle wireframe status.
traverse() works by iterating through all children and grandchildren of the starting object. You need to make sure that all the objects that you want to toggle to wireframe is parented under this starting object, as shown in the examples above.
3) Another option is to use an array to store each material as they are created, and then iterate through this array to change the wireframe attribute when the user toggles the check box.
This is what I use on my projects, it just inverses the boolean since it will be true or false.
function wireframeToggle(i) {
bool = i.material.wireframe;
i.material.wireframe = !bool;
}
Working example (x for wireframe)

Three.js load multiple separated objects / JSONLoader

is it possible to load a scene (e.g. two different cubes) exported from blender to json and identify them?
I need to distinguish between them e.g. to make one rotating and the other moving.
Thank you in advance!
Denv
edit+++
Thank you for your answer!
So if I load two cubes in one JSON file:
loader.load("untitled1.js", function(geometry, materials) {
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(materials));
mesh.scale.set( 10, 10, 10 );
mesh.position.y = 0;
mesh.position.x = 0;
scene.add( mesh );
});
How can I move first cube?
mesh.getObjectById(0).position.x = 15;
Doesn't seems to work.
Thank you!
Yes, it is possible to load an entire scene from a json file exported from Blender!
I achieved that with the following process: (Using three.js r80)
First you have to name your different objects in Blender like in the following image Outliner.
Then you can export the file using Three.js json exporter add-on for Blender, but taking care of marking the Scene checkbox like in the following:
Using this option your json file now contains all the meshes on the Blender's Outliner, as you can verify using any text editor. It doesn't matter if the meshes were selected or not.
It is important to know that the root (or parent) object isn't a Geometry anymore. It is labeled with the Object type by now. To access the children objects (of Mesh type) you can use the getObjectByName method on the root object like in the following code:
jsonloader.load( "obj/Books.json", function ( loadedObj ) {
var surface = loadedObj.getObjectByName("Surface");
var outline = loadedObj.getObjectByName("Outline");
var mask = loadedObj.getObjectByName("Mask");
// Watch the objects properties on console:
console.log(loadedObj);
console.log(surface);
console.log(outline);
console.log(mask);
} );
If we check the browser's console, we can see the proper objects assigned. And from now, you can manipulate the children objects independently (move, rotate, change materials, etc.)
Each object loaded has an associated .id. So you can use the Object3D.getObjectById() to find it and apply transforms on it.

Three.js loading exported blender model

I did a simple 3d model in blender and exported it to .obj file. Now I am loading it using three.js and I want objects that have string 'clickable' in its name to move on Y axis on click.
You can look at it here: http://three.parkz.cz/shop.html
The problem is that the informations parsed from names of objects (which I set in blender) are not corresponding to the right objects.
Loading and parsing:
var loader = new THREE.OBJMTLLoader();
loader.addEventListener('load', function(event) {
object = event.content;
object.name = 'CustomObjects';
for(var i = 0; i < object.children.length; i++) {
//console.log(object.children[i]);
var properties = object.children[i].name.split('_');
if(properties[1] == 'clickable') {
object.children[i].clickable = true;
} else object.children[i].clickable = false;
}
object.rotation.x = 0.5;
object.rotation.y = 0.5;
scene.add(object);
});
loader.load('shop.obj', 'shop.mtl');
For example that two cubes in the center (called '005_kiosek' and '010_kiosek2') are not supposed to be clickable but they are! You can open console and after click on it you can see that they are named wrongly '004_clickable' and '009_clickable'!
Here is my blender file: http://three.parkz.cz/shop.blend
Is it problem on javascript side or blender exports it wrong?
Thank you in advance!
Martin
P.S: Does anybody know why aren't that simple meshes (green and blue) rendered well?
The green and blue mesh are not rendered correctly because, under the current implementation, the obj loader only accepts triangles as faces. As those meshes use polygons, they are not rendered correctly.
As for the names I would try to verify that what I put in the blender file, comes out correct. So when you load the model, just print the name and its clickable attribute, to see if all is correct instead for taking it for granted.

Multiple .obj Models in THREE.js and detecting clicked objects

I have been following along this example to load .obj Model using three.js. Since I needed more than one model to load so I tried this
loader.addEventListener( 'load', function ( event ) {
var object = event.content;
object.position.y = - 80;
scene.add( object );
});
loader.load( 'obj/model1.obj' );
loader.load( 'obj/model2.obj' );
First: I don't know whether this is the right approach or not since I searched but didn't find any tutorial loading more than one .obj models.
Second: I want to be able to click different models on the screen. I tried this which doest not seem to work for me. Any suggestions on this?
This example shows you a pattern for loading multiple models:
http://mrdoob.github.com/three.js/examples/webgl_loader_json_objconverter.html
Regarding detecting clicked objects, depending on your model, you may need to set the recursive flag to true:
ray.intersectObjects( objects, true );
Well, since you haven't provide enough code to fully explain you question I will guess that for the second part you have to make sure you put the objects in an array of objects such as:
var objects = [];
after initializing the objects you do:
objects.push( object );
now you have an array where you can check for objects intersected after implementing the THREE.Ray.

Categories

Resources