ThreeJS new mesh vs clone - javascript

I'm wondering which style is more effective creating a new mesh or cloning one.
For example I have a loop that creates multiple times the "same mesh".
But I also noticed that if I have an opacity of the mesh set as 0 and I want to change it later to be visible, this would effect all the meshes that have the same material. Could it be because they have the same uuid.
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
transparent: true, // Make the material transparent
opacity: 0 // Set material opacity to 0
});
var geometry = new THREE.PlaneGeometry(width, height);
$.each(things, function(i, something) {
var mesh = new THREE.Mesh(geometry, material);
// Mesh positioning
scene.add(mesh);
});
So if I use the same material and geometry multiple times and use the raycaster to change the mesh opacity it would change the opacity of all the meshes.
Should I use the clone inside the each loop or create the material and the geometry of the mesh again and again?
$.each(things, function(i, something) {
var mesh = new THREE.Mesh(geometry.clone(), material.clone());
// Mesh positioning
scene.add(mesh);
});
or
$.each(things, function(i, something) {
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
transparent: true, // Make the material transparent
opacity: 0 // Set material opacity to 0
});
var geometry = new THREE.PlaneGeometry(width, height);
var mesh = new THREE.Mesh(geometry, material);
// Mesh postioning here
scene.add(mesh);
});

In your first method all the meshes are built up on the SAME GEOMETRY and MATERIAL(As you said they also have the same uuid).
So when you change the properties of the material it will affect all the meshes which are using the same material. But when you clone the material, it will create a NEW MATERIAL WITH THE SAME PROPERTIES, and also changes on the original material will not affect the cloned material. So most probably this method will work for you,
$.each(things, function(i, something) {
var mesh = new THREE.Mesh(geometry, material.clone());
// rest of your code...
});
I tried the following and it worked for me,
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
transparent: true,
opacity: 0.5
});
var geometry = new THREE.PlaneGeometry(100, 100, 1, 1);
for( var i = 0; i < 5; i++ ){
scene.add( new THREE.Mesh( geometry, material.clone() ) );
}

Related

How to set a texture to one side of a plane and have a color on the other side?

I'm trying to make a plane in three.js that one side is a texture and the other side is a color. I tried:
var material = new THREE.MeshBasicMaterial({color: 0xff0000, side: THREE.FrontSide, map: texture});
var geometry = new THREE.PlaneGeometry(width, height);
plane = new THREE.Mesh(geometry, material);
However this makes a plane that only one side has the texture and the other side is completely transparent. If I go:
var material = new THREE.MeshBasicMaterial({color: 0xff0000});
Then both sides have the color. Is there a way to make it so one side has a texture and the other side has the color?
Here is one patten you can follow if you want a different material on the front and back of a mesh:
var group = new THREE.Group();
scene.add( group );
group.add( new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { map: texture } ) ) );
group.add( new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.BackSide } ) ) );
Another approach is to write your own custom ShaderMaterial, but the above is the easiest if you are just getting started with three.js
three.js r.104

Different customDepthMaterial for every material

I have a tree model, that consists from only one mesh and has two materials: bark and branch. I export this mesh from Blender to .json and than add it on the scene:
var texture2 = new THREE.TextureLoader().load('models/branch1.png');
var loader = new THREE.JSONLoader();
loader.load("models/treeTest.json", function (geometry, materials) {
materials.forEach(function (material) {
material.alphaTest = 0.5;
});
mesh = new THREE.Mesh( geometry, materials );
mesh.customDepthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
map: texture2,
alphaTest: 0.5
} );
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
});
Result:
As you can see branches and bark use the same customDepthMaterial and because of that they have same shadows. I need to give customDepthMaterial only to branches, trunk must stay not transparent. I have tried to add customDepthMaterial on material with this:
materials.forEach(function (material) {
material.customDepthMaterial = new THREE.MeshDepthMaterial( {
depthPacking: THREE.RGBADepthPacking,
map: texture2,
alphaTest: 0.5
} );
});
but this code doesnt work (no errors in console, shadows just doesnt have transparency).
I know, that I can split my mesh into two parts (branches and trunk) and than use ObjectLoader, but I need the better solution.

Merging geometries in three.js

I have a scene which contains multiple meshes, each of varying shapes and sizes.
I have looped through each Mesh and using geometry.merge() I have been able to create a new mesh from the geometries in the scene.
I want to mask the entire mesh with an alphaMask, however, each geometry has the material applied to it separately.
An example of this can be seen here - https://codepen.io/danlong/pen/KXOObr
function addObjects(scene) {
// merged geomoetry & material
var mergedGeometry = new THREE.Geometry();
var mergedMaterial = new THREE.MeshStandardMaterial({ color: "#444", transparent: true, side: THREE.DoubleSide, alphaTest: 0.5, opacity: 1, roughness: 1 });
// multiple meshes
var geometry = new THREE.IcosahedronGeometry(30, 5);
var material = new THREE.MeshStandardMaterial({ color: "#444" });
var geo1 = new THREE.IcosahedronGeometry(30, 5);
var mesh1 = new THREE.Mesh( geo1, material );
mesh1.position.x = 10;
mesh1.position.y = 10;
mesh1.position.z = 0;
var geo2 = new THREE.IcosahedronGeometry(30, 5);
var mesh2 = new THREE.Mesh( geo2, material );
mesh2.position.x = 20;
mesh2.position.y = 20;
mesh2.position.z = 0;
var geo3 = new THREE.IcosahedronGeometry(30, 5);
var mesh3 = new THREE.Mesh( geo3, material );
mesh3.position.x = 30;
mesh3.position.y = 30;
mesh3.position.z = 0;
// scene.add(mesh1, mesh2, mesh3);
mesh1.updateMatrix();
mergedGeometry.merge(mesh1.geometry, mesh1.matrix);
mesh2.updateMatrix();
mergedGeometry.merge(mesh2.geometry, mesh2.matrix);
mesh3.updateMatrix();
mergedGeometry.merge(mesh3.geometry, mesh3.matrix);
// alpha texture
var image = document.createElement('img');
var alphaMap = new THREE.Texture(image);
image.onload = function() {
alphaMap.needsUpdate = true;
};
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGUlEQVQoU2NkYGD4z4AHMP7//x+/gmFhAgCXphP14bko/wAAAABJRU5ErkJggg==';
mergedMaterial.alphaMap = alphaMap;
mergedMaterial.alphaMap.magFilter = THREE.NearestFilter;
mergedMaterial.alphaMap.wrapT = THREE.RepeatWrapping;
mergedMaterial.alphaMap.repeat.y = 1;
// merged geometry with alpha mask
merge1 = new THREE.Mesh(mergedGeometry, mergedMaterial);
merge1.rotation.z = -Math.PI/4;
// merge geometry without alpha mask
var merge2 = new THREE.Mesh(mergedGeometry, material);
merge2.position.x = -100;
merge2.rotation.z = -Math.PI/4;
scene.add(merge1, merge2);
return mesh;
}
The mesh on the left is the merged geometries which I want to apply the alphaMask to. The mesh on the right is the outcome of this and instead of the map being applied to the mesh as a whole, each of the geometries has the map applied.
Is there a way to mask the entire mesh and not each geometry?
--
three.js r86
EDIT:
I've tried to apply a clipping plane to my mesh but it's not the effect I'm looking for. I want to be able to apply an alphaMask across the whole mesh and reveal it however I make my mask image. Something like this effect - https://codepen.io/supah/pen/zwJxdb
Is it something to do with the UV's being preserved from the original geometries? Do I need to change these in some way?
I think what you really want is an overlaid mask. This can be accomplished by rendering a single plane that has the alpha map applied, on top of the scene rendering. Using an orthographic camera, and controlling certain renderer settings, such as disabling automatic clearing of color.

using a texture mesh and wireframe mesh in threejs

I'm trying to draw a wireframe mesh and a textured mesh in threeJS but when I have both added to my scene the textured mesh doesn't display. Code below:
I'm having trouble creating two meshes that share the same geometry where one of the materials is wireframe and the other is a texture. If one of the materials is wireframe and the other is just a color fill it works fine- but as soon as I make the second material a texture it stops working.
If I comment out scene.add( wireMesh ); then the textured mesh shows up.
var wireMat = new THREE.MeshBasicMaterial( { color:0x00FFFF, wireframe: true, transparent: true, overdraw:true } );
var wireMesh = new THREE.Mesh(geometry, wireMat);
scene.add( wireMesh );
var texture = texture = THREE.ImageUtils.loadTexture( 'textures/world.jpg' );
var imageMat = new THREE.MeshBasicMaterial( {color:0xffffff, map: texture } );
var fillMesh = new THREE.Mesh(geometry, imageMat);
scene.add( fillMesh );
Under SceneUtils there is a createMultiMaterialObject(geometry, materials). It essentially creates multiple meshes that all share the same geometry all in a group.
Example:
var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
new THREE.MeshLambertMaterial( { color: 0xffffff} ),
new THREE.MeshBasicMaterial( { color: 0x222222, wireframe: true} )
]);
THREE.SceneUtils source code
Unfortunately it is not possible to share geometry between an object using wireframe and another one not using it. You'd need to clone that geometry. Which reminds me that we haven't done .clone() for Geometry yet.

Can I hide faces of a mesh in three.js?

I want to make parts of a mesh invisible at runtime. Can I set these parts invisible/transparent, e.g. by changing attributes of single faces? The mesh itself uses only one material.
Exemplary illustration as the editor understands this question: Imagine a mesh (here with a geometry of 20 vertices) where each quad of four vertices builds up a Face4. Now, some parts of the mesh should be made invisible (here two faces are invisible).
Note: This answer applies to legacy versions of three.js
You can assign a different material to each face. Here is an example where the faces share a material, but some faces are transparent:
// geometry
var geometry = new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 );
// materials
materials = [
new THREE.MeshLambertMaterial( { color: 0xffff00, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { transparent: true, opacity: 0 } )
];
// assign material to each face
for( var i = 0; i < geometry.faces.length; i++ ) {
geometry.faces[ i ].materialIndex = THREE.Math.randInt( 0, 1 );
}
geometry.sortFacesByMaterialIndex(); // optional, to reduce draw calls
// mesh
mesh = new THREE.Mesh( geometry, materials );
scene.add( mesh );
three.js r.87

Categories

Resources