How to add lights to a Mesh generated by BufferGeometry and drawed as TriangleStrips? - three.js

I'm trying to add lights to a scene where there is a Mesh created by BufferGeometry. The mesh.drawMode is THREE.TriangleStripDrawMode. I don't know why light is not applying to the mesh.
There is an example bellow:
https://jsbin.com/jofasabeji/edit?js,output
Is there a flag to be activated (like face culling)?
Thanks!

Your geometry is missing vertex normals.
You can specify the normals yourself, or -- if you find the result acceptable -- you can call:
geometry.computeVertexNormals();
Alternatively, you can avoid setting vertex normals if you set the material property to flat-shading (and your material supports it):
material.shading = THREE.FlatShading;
Also, you need to set a reasonable intensity for your light:
var light = new THREE.PointLight( 0xffffff, 1 );
three.js r.85

Related

THREE.js raycaster intersectObject method returns no intersection when checking if point is inside mesh

I want to check whether a point is inside a mesh or not. To do so, I use a raycaster, set it to the point's origin and if the ray intersects the mesh only once, it must be inside. Unfortunately, the intersectObject always returns no intersection, even in cases I know that the point is located inside the mesh.
The point's origin is given in world coordinates and the mesh's matrixWorld is up to date too. Also, I set the mesh.material.side to THREE.DoubleSide, so that the intersection from inside should be detected. I tried setting the recursive attribute to true as well, but as expected, this didn't have any effect (since the mesh is a box geometry). The mesh is coming from the Autodesk Forge viewer interface.
Here is my code:
mesh.material.side = THREE.DoubleSide;
const raycaster = new THREE.Raycaster();
let vertex = new THREE.Vector3();
vertex.fromArray(positions, positionIndex);
vertex.applyMatrix4(matrixWorld);
const rayDirection = new THREE.Vector3(1, 1, 1).normalize();
raycaster.set(vertex, rayDirection);
const intersects = raycaster.intersectObject(mesh);
if (intersects.length % 2 === 1) {
isPointInside = true;
}
The vertex looks like this (and it obviosly lies inside of the bounding box):
The mesh is a box shaped room with the following bounding box:
The mesh looks like this:
The geometry of the mesh holds the vertices in the vb. After applying the world matrix, the mesh vertices are correct in world space. Here is a part of the vb list:
Why does the raycaster not return any intersection? Is the matrixWorld of the mesh taken into account when computing the intersections?
Thanks for any kind of help!
Note that Forge Viewer is based on three.js version R71, and it had to modify/reimplement some parts of the library to handle large and complex models (especially architecture and infrastructure designs), so THREE.Mesh objects might have a slightly different structure. In that case I'd suggest to raycast using Forge Viewer's own mechanisms, e.g., using viewer.impl.rayIntersect(ray, ignoreTransparent, dbIds, modelIds, intersections);.

EdgesHelper as child of a Cube get double rotation speed

When I add an EdgesHelper of a cube to the scene, then rotate the cube, the EdgesHelper follows the rotation.
But if I add EdgesHelper as child of cube, it rotates at double speed.
https://jsfiddle.net/aj3cv4tx/4/ +49
var cube = new THREE.Mesh( geometry, mesh );
var egh = new THREE.EdgesHelper( cube, 0x00ffff );
cube.add(egh); // causes different ratation speed
//scene.add(egh); // this one is ok
How can I fix its rotation speed?
What you are seeing is a consequence of how EdgesHelper (and some of the other helpers) have been implemented.
If you want to use EdgesHelper, you have to adhere to two rules:
EdgesHelper must be added to the scene, directly.
The scene can't have a transform applied (for example, be rotated).
three.js r.74

THREE.BufferGeometry - vertex normals and face normals

In the documentation for THREE.BufferGeometry is written:
normal (itemSize: 3)
Stores the x, y, and z components of the face or vertex normal vector of each vertex in this geometry. Set by .fromGeometry().
When is this variable holding vertex normals and when face normals?
Is it as simple as if a THREE.MeshMaterial is used the normals are interpreted as face normals and when a THREE.LineMaterial is used the normals are used as vertex normals? Or is it more complicated then that.
I also understood that THREE.FlatShading can be used for rendering a mesh with flat shading (face normals point straight outward).
geometry = new THREE.BoxGeometry( 1000, 1000, 1000 );
material = new THREE.MeshPhongMaterial({
color: 0xff0000,
shading: THREE.FlatShading
});
mesh = new THREE.Mesh( geometry, material );
I would say normals are not necessary any more. Why are my buffer geometries made from for example a THREE.BoxGeometry still holding a normal attribute in such case? Is this information still used for rendering or would removing them from the buffer geometry be a possible optimization?
BufferGeometry normals are vector normals and shader interpolates normal value for each fragment from vertices belonging to that face (in most cases triangle)
when you convert THREE.BoxGeometry which has normals computed by default, they stay set up even in the BufferGeometry conversion output, as geometry does not have any way to "know" whether you need normals or any of the attributes (material program decides what attributes are used)
you can remove the normals with geometry.removeAttribute("normal")

Set transparency of face by index in THREE.js

I've managed to set the colour of a mesh face using:
geometry.faces[i].color.setHex('0xff00ff');
Is there a function to set the transparency to true and opacity to say 0.5?
I'm sure there is one, just have no idea of the syntax.
Actually, you cannot achieve that by changing your geometry. Because transparency controlled by materials.
But there's way to do this.
First, each face has materialIndex (Face manual).
Next, Each mesh, drawn within three.js scene has material. And there's special material of type THREE.MeshFaceMaterial (MeshFaceMaterial manual), which takes array of materials as argument.
When faces are drawn, three.js renderer takes face's materialIndex and uses corresponding material from this material array or, if mesh contains single material type.
So you could do something like:
var opacMaterial = new THREE.MeshLambertMaterial({
transparent:true,
opacity:0.7
});
var solidMaterial = new THREE.MeshLambertMaterial({
transparent:false,
color:new THREE.Color(1,0,0)
});
var mesh = new THREE.Mesh(
geometry,
new THREE.MultiMaterial([solidMaterial, opacMaterial])
);
By default, if your geometry have materialIndex == 0 for each faces, you will see solidMaterial drawn.
If you want to make it transparent do something like this;
geometry.faces[i].materialIndex = 1;
Don't forget to update geometry in mesh: (How to update geometry in mesh question.)
Also, aware, if you have materialIndex in your faces greater than length of material array, you will get awkward error inside of deep of THREE.js

Ray intersection and child camera

I've been playing with three.js for few weeks now and got few inconsistencies on ray casting.
Here is a simplified version demonstrating one of the bug I encoutered :
http://jsfiddle.net/eMrhb/12/
The camera is added to the sphere mesh for further use of TrackBallControl for example.
scene.add(mesh);
mesh.add(camera);
Clicking a few times on the sphere and opening the console, show us none of the expected intersections between the ray and the mesh.
Adding the camera to the scene (http://jsfiddle.net/eMrhb/9/), solves the problem:
scene.add(mesh);
scene.add(camera);
But I could use a much more complex hierarchy between my scene objects and the camera to suit my needs.
Is this a limitation? If it is, is there any workarounds I could use?
Yes, this is fixable.
If the camera is a child of another object that is rotated and or translated, then your have to use a different pattern in ray casting.
Instead of this familiar pattern:
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
You have to use this pattern instead:
var position = camera.matrixWorld.getPosition().clone();
var ray = new THREE.Ray( position, vector.subSelf( position ).normalize() );
three.js r.53

Resources