I am trying to understand how to add multiple materials to a mesh. I want to take the existing material and apply another slightly transparent material to my existing mesh. Right now, passing it as an array it just disappears. I know I am missing something, just not sure what that is. The end goal is so I can animate the opacity of the new material in/out over the existing one.
Original Material
const originalMaterial = child.material.clone();
New Material
const newMaterial = new THREE.MeshStandardMaterial({
name: 'New Mat',
map: newTexture,
emissiveMap: newTextureMap,
side: THREE.DoubleSide,
opacity: .5,
transparent: true
});
Combining them
child.material = [originalMaterial, newMaterial]
child.material.needsUpdate = true
WebGL doesn't allow for multiple materials on a single mesh. That's why the THREE.Mesh constructor only allows one geometry, and one material.
To do what you want, you could create two meshes, with one material's transparency set to 0.5. But more frequently you would just use a single mesh, and assign variations in opacity through the .alphaMap texture. This would give you more flexibility because you can have many more transparency values on a single object, without having to create new materials for each:
var textureLoader = new THREE.TextureLoader();
var alphaTexture = textureLoader.load("path/to/alpha.png");
mesh.material.alphaMap = alphaTexture;
mesh.material.transparent = true; // <- don't forget this!
Related
I am working with THREE.js and BufferGeometry to create a view of a set of points based on an image. Currently, I have the following:
As can be seen, the "object" that I have constructed has faces that can only be viewed from the opposite side as intended.
I have constructed my BufferGeometry with the a set of points with a corresponding array of normals, implemented like so (assuming that verts and norms are valid):
vertices = Float32Array.from(verts)
normals = Float32Array.from(norms)
// Make new geometry
geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3))
material = new THREE.MeshPhongMaterial({color: 0xffffff})
mesh = new THREE.Mesh(geometry, material)
geometry.computeVertexNormals()
scene.add(mesh)
As you can see from trying to add the array of normals, I have tried adding normals in which all are (0,1,0). Without geometry.computeVertexNormals(), this still results in none of the faces being solid/behaving correctly. With such, the result in the image is generated.
What could be causing the solid to behave as such?
I´m using Three.js and trying to create some custom shapes, similar to one that appears in a project from one of agencies using threejs:
three.js featured project esample
How did they generated these boxes with holes inside? (on that examples
boxes basically have only borders around and are empty inside).
As I saw in the code (I was trying to figure out myself) they use BoxGeometry but I have no idea how to accomplish that. Does anyone know or can give me any directions? It would be really helpfull as i´m stuck with this and have no idea on how to create them.
So in THREE.js Meshes represent any kind of 3D object. They combine Geometries and Shaders. Generally to create a mesh you call
var mesh = new THREE.Mesh( geometry, shader );
If you use any of the builtin shaders (also known as Materials [ MeshBasicMaterial, MeshLambertMaterial, etc]) they have a wireFrame boolean attribute that allows this functionality.
var geometry = new THREE.BoxGeometry( x, y, z ),
material = new THREE.MeshBasicMaterial( {
wireFrame: true, // This makes the object appear wireframe
color: 0xffffff // You can alter other properties
});
var box = new THREE.Mesh( geometry, material );
// You can also change it later
box.material.wireFrame = false;
I have a shader material that works as expected.
This shader has a texture attached.
I want to create 2 meshes using this shader material, with a different texture for each mesh.
Problem is that if I try to render my 2 meshes in the scene, the first object's material got overwritten somehow and uses the same material as the second object.
var dataShader = VJS.shaders.data;
var uniforms = dataShader.parameters.uniforms;
// texture size (2048 for now)
uniforms.uTextureSize.value = stack._textureSize;
// array of 16 textures
uniforms.uTextureContainer.value = textures;
// texture dimensions
uniforms.uDataDimensions.value = new THREE.Vector3(stack._columns, stack._rows, stack._nbFrames);
// world to model
uniforms.uWorldToData.value = stack._lps2IJK; //new THREE.Matrix4();
var sliceMaterial = new THREE.ShaderMaterial({
// 'wireframe': true,
'side': THREE.DoubleSide,
'transparency': true,
'uniforms': uniforms,
'vertexShader': dataShader.parameters.vertexShader,
'fragmentShader': dataShader.parameters.fragmentShader,
});
var slice = new THREE.Mesh(sliceGeometry, sliceMaterial);
// this is an Object3D that is added to the scene
this.add(slice);
Does it make sense? Is it the expected behavior? If so, is there a good way to bypass this issue?
Thanks
You need to create two instances of the material, using the same shader, and assign the appropriate texture/uniforms for each.
edit
Copying uniforms is a bit tricky. You lose the reference i think when you clone the material, so you might want to be careful how you manage them.
I'm new to three.js. I need to handle multiple objects as a single one. In simple terms I need to render a kind of bas-relief:
a box geometry (the base)
an extruded image on top of it
and some text.
Each object has to have a different material but they has to act as a single one: location and rotation the same etc.
I'm still new to three.js so I don't know how to make a kind of composite pattern: with group? Joining geometry? Join mesh? What is the best way?
Right now I'm using everything in a group but.. it seems a bit slow.
You could nest your objects in an Object3D instance.
group = new THREE.Object3D(); //create a container
group.add( mesh1 ); //add a mesh with geometry to it
group.add( mesh2 );
scene.add( group ); //add the group to the scene
EDIT:
Release 69 added THREE.Group class and the release note say to use this instead of Object3D where possible, but I can not find any other documentation.
https://github.com/mrdoob/three.js/releases
group = new THREE.Group(); //create a container
group.add( mesh1 ); //add a mesh with geometry to it
group.add( mesh2 );
scene.add( group ); //add the group to the scene
How can I create a material that reflects other shapes from the scene? I have tried the reflectivity property but it didn't reflect anything.
There is an example that seems to have this effect
It doesn't look like standard materials were used to create this.
To go into a bit of the theory: a reflection is basically an image of the scene taken from a certain position. So if you want a planar mesh to serve as a mirror, you'll have to add a camera at that position, have it render the scene to a texture in the animation loop, and then use that texture in the material for the planar mesh. I would also recommend looking at http://stemkoski.github.io/Three.js/Reflection.html in addition to the examples WestLangley mentioned.
Also, play around with settings; for a less reflective effect, for example, try:
var mirrorMaterial = new THREE.MeshBasicMaterial( { color: 0x111111, envMap: mirrorCamera.renderTarget } );
or
var mirrorMaterial = new THREE.MeshPhongMaterial( { emissive: 0x111111, envMap: mirrorCamera.renderTarget } );
https://threejs.org/examples/#webgl_materials_cubemap
I did it with the above example:
new THREE.MeshLambertMaterial ({
map: texture,
envMap: scene.background,
combine: THREE.MixOperation,
reflectivity: .5
})
The key variable, as i understand, is THREE.MixOperation