How can I access multiple meshes with the same name?
var mesh1 = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xffffff }));
mesh1.name = "meshes";
scene.add( mesh1);
var mesh2 = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xffffff }));
mesh2.name = "meshes";
scene.add( mesh2);
Something like:
meshes.position.z = 2;
You could store the meshes in a two dimensional array indexed by their name. Then you could do:
arr["meshes"].forEach(function(obj, idx){
obj.position.z = 2;
});
Related
When I create multiple mesh's with the same name I can't select them all when I want to remove them from a scene.
I've tried traversing the function to no avail.
event.preventDefault();
scene.traverse(function(child) {
if (child.name === "blueTiles") {
var remove_object = scene.getObjectByName( "blueTiles", true );
scene.remove(remove_object);
}
});
var surroundMaterial = new THREE.MeshBasicMaterial({ color: 0x154995, side: THREE.DoubleSide, transparent: true, opacity: 0.8 });
surroundingCubes = new THREE.Mesh( geometry, surroundMaterial );
scene.add( surroundingCubes );
surroundingCubes.name = "blueTiles";
surroundingCubes.position.set(selectedObject.position.x - 1, 0.11, selectedObject.position.z);
var surroundMaterial = new THREE.MeshBasicMaterial({ color: 0x154995, side: THREE.DoubleSide, transparent: true, opacity: 0.8 });
surroundingCubes = new THREE.Mesh( geometry, surroundMaterial );
scene.add( surroundingCubes );
surroundingCubes.name = "blueTiles";
surroundingCubes.position.set(selectedObject.position.x + 1, 0.11, selectedObject.position.z);
surroundingCubes.rotation.x = Math.PI / 2;
I should be able to only delete all the objects with the name blueTiles
EDIT I switched from names to Groups, and that worked wonders
SOLUTION BELOW
function onDocumentMouseDown(event) {
for (var i = group.children.length - 1; i >= 0; i--) {
group.remove(group.children[i]);
}
var surroundingMaterial = new THREE.MeshBasicMaterial({ color: 0x154995, side: THREE.DoubleSide, transparent: true, opacity: 0.8 });
var geometry = new THREE.PlaneGeometry(1, 1, 1, 1);
if ( selectedObject.position.x - 1 >= 0) {
surroundingCube = new THREE.Mesh( geometry, surroundingMaterial );
surroundingCube.position.set(selectedObject.position.x - 1, 0.11, selectedObject.position.z);
surroundingCube.rotation.x = Math.PI / 2;
group.add(surroundingCube);
}
if ( selectedObject.position.x + 1 <= 9) {
surroundingCube = new THREE.Mesh( geometry, surroundingMaterial );
surroundingCube.position.set(selectedObject.position.x + 1, 0.11, selectedObject.position.z);
surroundingCube.rotation.x = Math.PI / 2;
group.add(surroundingCube);
}
scene.add( group );
}
You can try grouping the meshes using the THREE.group class.
A very basic usage would be something like:
var meshes = new THREE.Group();
var mesh1 = new THREE.Mesh( geometry, material );
var mesh2 = new THREE.Mesh( geometry, material );
var mesh3 = new THREE.Mesh( geometry, material );
meshes.add( mesh1 );
meshes.add( mesh2 );
meshes.add( mesh3 );
scene.add( meshes );
getObjectByName just calls getObjectByProperty (using the name property) which only returns the first object it finds.
You really just need to loop over children of the scene / object3d, check their name, and remove.
If you know all the ones you want to remove will be at the top level it is simple.
Something like....(untested)
for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
if (scene.children[i].name === 'blueTiles') {
scene.remove(scene.children[i]);
}
}
If you also want to check at lower levels, you probably want some sort of recursion.
EDIT...
After having another look at your question..and remembering that there is a traverse function
You seem to already be traversing the scene and have access to the child.
I think you just need to change your function (and not call getObjectByName at all).
scene.traverse(function(child) {
if (child.name === "blueTiles") {
scene.remove(child);
}
});
How can a clipping plane be setup so that all child objects on baseObject are clipped when outside the baseObject?
In this example the childObject should only show the region inside the parent and not show anything outside the parent's bounds.
Here is a jsfiddle
var geometry = new THREE.PlaneGeometry( 100, 100 );
var material = new THREE.MeshBasicMaterial( {color: 0xffff00, side: THREE.DoubleSide} );
var baseObject = new THREE.Mesh( geometry, material );
var geometry = new THREE.PlaneGeometry( 20, 20 );
var material = new THREE.MeshBasicMaterial( {color: 0x00ff00, side: THREE.DoubleSide} );
var childObject = new THREE.Mesh( geometry, material );
// Set the child object to straddle the baseObject's border.
childObject.position.set(50, 0, 0)
baseObject.add(childObject)
I'm working off an example from the site and would like to add a textured cube to the scene and ideally have it in a specific position. This is what I've tried so far but it's not appearing:
var frametexture = new THREE.ImageUtils.loadTexture( 'https://threejs.org/examples/textures/crate.gif' );
var artwork = new THREE.BoxBufferGeometry( 200, 200, 20 );
var material = new THREE.MeshBasicMaterial( { map: frametexture } );
artframe = new THREE.Mesh( artwork, frametexture );
scene.add( artframe );
artwork.scale( - 1, 1, 1 );
Here's my JSFIDDLE
var frametexture = new THREE.ImageUtils.loadTexture( 'https://threejs.org/examples/textures/crate.gif' );
Should instead be
var frametexture = THREE.ImageUtils.loadTexture( 'https://threejs.org/examples/textures/crate.gif' );
and
artframe = new THREE.Mesh( artwork, frametexture );
needs to be
artframe = new THREE.Mesh( artwork, material);
I have some generated geometries, where I want to see the faces from 2 sides.
So when looking from the front of one of the face's in the geometry, it is using material1 but viewed from the back you see material2.
I have experimentet with THREE.FrontSide, THREE.BackSide & THREE.DoubleSide, but none of them seem to give the wanted result. DoubleSide will just mirror the material on front and back.
Should I clone my geometry and create to meshes with two different materials ( mat1 = front & mat2 = back ) or what would you guys do?
Yes, two meshes with different materials should do the trick:.....
var material1 = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
var material2 = new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.BackSide } );
var object1 = new THREE.Mesh( geometry, material1 );
var object2 = new THREE.Mesh( geometry, material2 );
I have a loop where I create a multiple Mesh with different geometry, because each mesh has one texture:
var geoCube = new THREE.CubeGeometry(voxelSize, voxelSize, voxelSize);
var geometry = new THREE.Geometry();
for( var i = 0; i < voxels.length; i++ ){
var voxel = voxels[i];
var object;
color = voxel.color;
texture = almacen.textPlaneTexture(voxel.texto,color,voxelSize);
//Return the texture with a color and a text for each face of the geometry
material = new THREE.MeshBasicMaterial({ map: texture });
object = new THREE.Mesh(geoCube, material);
THREE.GeometryUtils.merge( geometry, object );
}
//Add geometry merged at scene
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
mesh.geometry.computeFaceNormals();
mesh.geometry.computeVertexNormals();
mesh.geometry.computeTangents();
scene.add( mesh );
But now I have this error in the javascript code Three.js
Uncaught TypeError: Cannot read property 'map' of undefined
In the function:
function bufferGuessUVType ( material ) {
}
Update:
Finally I have removed the merged solution and I can use an unique geometry for the all voxels. Altough I think that If I use merge meshes the app would have a better performance.
For r53+ the code should be something like this:
var geoCube = new THREE.CubeGeometry(voxelSize, voxelSize, voxelSize);
var geometry = new THREE.Geometry();
var materials = [];
for( var i = 0; i < voxels.length; i++ ){
for ( var j = 0; j < geoCube.faces.length; j ++ ) {
geoCube.faces[ j ].materialIndex = i;
}
var object = new THREE.Mesh( geoCube );
// here I assume you'll me positioning the object.
THREE.GeometryUtils.merge( geometry, object );
var voxel = voxels[i];
var texture = almacen.textPlaneTexture(voxel.texto,voxel.color,voxelSize);
materials.push( new THREE.MeshBasicMaterial( { map: texture } ) );
}
// Add geometry to scene
var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( materials ) );
mesh.geometry.computeFaceNormals();
mesh.geometry.computeVertexNormals();
scene.add( mesh );
Some methods are expecting the materials array to be in the mesh face material. For example:
function getBufferMaterial( object, geometryGroup ) {
return object.material instanceof THREE.MeshFaceMaterial
? object.material.materials[ geometryGroup.materialIndex ]
: object.material;
};
Its possible to handle this by referencing the materials array both in the geometry and in the mesh face material. So the line where the mesh is created would look something like:
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(geometry.materials) );
and in the loop processing the voxels:
geometry.materials.push( new THREE.MeshBasicMaterial({ map: texture }));
Each face in the geometry also needs to have a materialIndex assigned or there will be an error. Looping through geometry.faces[] and assigning a materialIndex might be a good way if you know how many faces each of the voxels has.