Three.js - how to create custom shapes - javascript

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;

Related

What are the properties of three.js emissive materials

I'm working on a simple demonstration in three.js and am confused by the behaviour of THREE.MeshPhongMaterial coming from a background in the Unity Game Engine.
create_ring() {
// creates a ring mesh per inputed class data
const material = new THREE.MeshPhongMaterial({
color: this.color,
emissive: this.color,
emissiveIntensity: 1.6
});
const ring_geo = new THREE.TorusGeometry(this.radius, this.thickness, 16, 100);
// Translate in space
ring_geo.translate(5, 5, 0)
// add texture to mesh and output
const ring_mesh = new THREE.Mesh(ring_geo, material);
ring_mesh.receiveShadow = true;
ring_mesh.castShadow = true;
ring_mesh.name = "ring";
return ring_mesh
}
I was under the impression the materials would create a nice gentle pool of light on the floor geometry but now having researched the problem either I need some advice on how to implement this as a shader feature? Or I'm not understanding the limits and behaviour of materials in three.js? Below is an example of what is possible with a material's emissive option in Unity.
There's more than just an emissive material shown in the Unity screenshot above — the objects around the light probably were probably also marked as static, which Unity uses to "bake" the glow effect onto them, while compiling the application. There could also be a "bloom" post-processing effect to create the dynamic glow seen by the camera around the object.
Because three.js runs on the web and does not have an offline compilation step, these additional effects have to be configured manually. You can see the three.js bloom example for some help adding the bloom effect to a scene. Baking the light onto surrounding objects would generally be done in Blender, and then loaded into three.js with the base color texture or a lightmap.

Three.js use multiple materials on one mesh

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!

Calculating light for custom geometry in Three.js

I've created a custom geometry and I've used geometry.computeFaceNormals() to get the lighting right. So far so good.
The problem comes when I animate the geometry. In the animation loop I call again geometry.computeFaceNormals() but the faces' lighting doesn't change.
Here is a fiddle with the example:
You are updating the vertices of your geometry, so typically, your normals must also be updated for the shading to be correct.
However, since you want flat shading, there is another solution.
MeshPhongMaterial generates flat shading using the OES_standard_derivatives extension. This means that geometry normals do not have to be specified or updated when vertices change.
All you have to do is use the following pattern, and flat shading will "just work" -- provided the extension is supported.
var material = new THREE.MeshPhongMaterial( {
color: 0xFFFFFF,
shading: THREE.FlatShading
} );
three.js r.80

Overlaying texture onto STL loaded mesh

I'm looking for an efficient method of overlaying a texture to cover a mesh. I'm not an expert, more a novice, when it comes to 3 dimensional mapping/objects. Below shows how I would like the end product to look.
When attempting to apply texture with the following code, the end result looks similar to below. I have not done any UV mapping, I believe my answer may be lay here. As you can see from the below image it roughly takes the general shade of the picture but I get the impression that the texture is being drawn between each vertice of the model rather than across the entirity.
var textureLoader = new THREE.TextureLoader();
var texture = textureLoader.load('resource/images/materials/Mahogany.jpg');
var STLLoader = new THREE.STLLoader();
STLLoader.load( 'test.stl', function ( geometry1 ) {
var meshMaterial = new THREE.MeshBasicMaterial({map:texture});
var mesh = new THREE.Mesh( geometry1, meshMaterial );
mesh.scale.set(1, 1, 1);
mesh.position.set(5, 20, 80);
scene.add(mesh);
});
The cube has the correct texturing, whereas my STL loaded mesh does not.
Please ignore the rotation of the object in the above picture, I will move to unioning my objects together once I have fixed my texturing issues.
Fairly new at asking questions on here so please do comment to help me expand my question if it's too general or not percise enough. Thank you.
You may use
THREE.MeshPhongMaterial()
instead of
THREE.MeshBasicMaterial()
THREE.MeshPhongMaterial() will wrap the material outside the object and we can get curved material as per the object.

THREEJS Shader Material overwritten

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.

Categories

Resources