Smooth shading in THREE.js with varying triangle orientation - three.js

In a THREE.js scene with a Geometry object containing a triangle mesh, I want to achieve smooth phong shading. This seems to require making sure the triangles are added with the correct orientation.
Here's a Code Pen showing the issue. The same surface is rendered twice, on the left with varying triangle orientations, and on the right with consistent triangle orientations:
In my real code, because of how I am generating the triangle geometry, it is hard to know what the correct orientation should be. How can I achieve smooth shading independent of the triangle orientation?
I am just using a simple phong material:
let material = new THREE.MeshPhongMaterial({
color: new THREE.Color('#FFAA44'),
side: THREE.DoubleSide,
flatShading: false
});

You're running into issues with the winding order of vertices.
Counter-clockwise:
1
/ \
2———3
Clockwise:
1
/ \
3———2
When you use counter-clockwise winding order, the geometry.computeVertexNormals() makes all normals point away in the direction the triangle is facing, let's call it "forward". However, when you use clockwise winding order, it makes the normals point away in the opposite direction, so they're pointing "backward".
The phong material you're using relies on these normals to give you smooth shading. When you flip-flop between forward- and backward-facing normals, the possibility for smooth shading goes out the window, and you get the checkered look you see in your example. Actually all meshes, by convention, have all triangles follow a uniform winding order. You could solve your unique problem by looking at your vertex positions, and swapping two if you find they're winding in a clockwise manner:
Since you're using something similar to a plane grid, you could use a simple if statement. Based on my diagram above, you could do:
if (v2.x > v3.x) {
// Clockwise winding order! Must flip verts 2 & 3
}
It might vary which vertices you're comparing, based on how you're building them, but once all triangles are uniform, you can call computeVertexNormals();

Related

Three.js vertex shader to render all geometry triangles so they face camera

I would like to create a vertex shader in Three.js to render the faces of a textured geometry so that all the triangles are face-on to the camera.
This is to emulate the functionality and performance of Three.js Points, but without the size limitation of gl_PointSize.
I'm not really sure what calculation to perform in the vertex shader. Any help appreciated.
you will have to add custom attribute to your geometry, easiest one to use would be a vector to the center of the triangle
in vertex shader you will have to calculate how to move each vertex, you now have
vertex position
vector to center
vertex normal == face normal
camera orientation (from matrices)
from that you can calculate the triangle center, which be static and calculate the rotation vertex has to make around the triangle center around axis perpendicular to the vector to center so that normal will come out as inverse of the camera orientation
the math is not very complicated, but writing shader code is tedious because of the non-existent debug - i advise you to first write a code that rotates the positions of geometry(using only the same parametres) and port it to shader

Intersection arbitrary mesh with plane (in THREEJS)

Is it currently possible to display the intersection of a mesh and a plane as below in THREEJS:
Display in red, green, yellow the intersection of meshes with a back plane with a texture on it.
If not, which would the best approach be:
compute a "line geometry" at the intersection of the mesh and the plane in JavaScript, then renderer it
apply a custom shader material to the mesh (with the plane parameters as a uniform) that only colors a pixel if the current triangle intersects the plane
For option #2 are there some demos online already of such shaders?
Thanks,
Nicolas
=== UPDATE 2022 ===
THREE-Mesh-BVH provides new efficient ways to create contours. That is how I currently do it:
Adjust you geomeotry to a BVH tree
Compute each triangle to pllane intersection as it is super fast thanks to the BVH tree.
Live example: https://gkjohnson.github.io/three-mesh-bvh/example/bundle/clippedEdges.html
====
AMI now supports it (https://fnndsc.github.io/ami/#viewers_quadview)
The steps are:
Display intersection between a mesh and a plane
Post process the intersection to display the contours.
There are different techniques to display mesh/plane intersection:
With a stencil buffer (https://github.com/daign/clipping-with-caps)
Playing the the mesh opacity (https://github.com/FNNDSC/ami/tree/dev/examples/viewers_quadview)
All those techniques are computationally expensive at it requires 3 renders pass to display contours of 1 mesh and there may be a better approach but not sure what would be the best alternative.
HTH

Tiled Terrain Normals

I am trying to create a terrain solution in ThreeJS and I'm running into some trouble with the generation of the normals. I am approaching the problem by creating a number of mesh objects using the THREE.PlaneGeometry class. Once all of the tiles have been created I go through each and set the UV's so that each tile represents a part of the whole. I also generate a height value of the vertex Y positions to create some hills. I then call the geometry functions
geometry.computeFaceNormals();
geometry.computeVertexNormals();
This is just so that I have some default face and vertex normals for each tile.
I then go through each tile and try to average out the normals on each corner.
The problem is (I think) with the normals, but I don't really know what to call this problem. Each of the normals on the plane's corners point in the same direction as the face when created. This makes the terrain look like a flat shaded object. To prevent this I thought perhaps what I needed to do was make sure each vertext normal (each corner) had the same averaged normal as its immediate neighbours normals. I.E each corner of each tile has the same normal as all the immediate normals around it from the adjacent planes.
figure A
Here I am visualising each of the 4 normals on the mesh. You can see that at each corner the normals are the same (On top of eachother)
figure B
EDIT
figure C
EDIT
Figure D
Except even when the verts all share the same normals it still comes up all blocky <:/
I don't know how to do this... I think my understanding of what needs to be done is incorrect...?
Any help would be greatly appreciated.
You're basically right about what should happen. The shading you're getting is not consistent with continuous normals. If each all the vertex-faces at a given location have the same normal you should not see the clear shading discontinuities in your second image. However the image doesn't look like simple face normals either, at least not to my eye.
A couple of things to look at:
1) I note that your quads themselves are not planar. Is it possible your algorithm is assuming that they are? the non-planar quad meshes don't have real 'face normal' to use as a base.
2) Are your normalized normalized after you average them? That is, do they have a vector length of 1?
3) Are you confident that the normal averaging code is actually using the correct normals to average? The shading in this does not look like completely flat shaded image where each vertex-face normal in a quad is the same - if that were the case you'd get consistent shading across each quad although the quads would not be continuous. This it possible your original vertex-face normals are not in fact lined up with the face normals?
4) Try turning off the bump maps to debug. Depending on how the bump is being done in your shader you may have incorrect binormals/bitangents rather than bad vert normals.
Instead of averaging at each vertex / corner the neighborhood normals you should average the four normals that each vertex has (4 tiles meet at each vertex).

ray intersect planes with dynamic geometry returns empty array

* SOLVED *
It was not about 0,0,0 or distortion. It´s super weird but I found out that compute geometry as a Sphere worked! (even at the tiles corners, where you should think a sphere wouldnt cover it does)
http://threejs.org/docs/#Reference/Core/Geometry
computeBoundingSphere();
Problem desc. follows below.
Hey I'm building a webgl wall for my portfolio site, I need ray intersection to know both when user hovers over the wall and when they click what plane they're clicking on so I can redirect them to correct project.
http://www.martinlindelof.com
What i do is adding all planes on xyz(0,0,0) then I'm using dynamic geometry to place out their vertices on a point grid that's affected by a repelling particle (using traer)
now when I'm doing ray intersect (using examples from threejs r49) I get an empty array back, nothing hit.
could this be because all planes origins are in 0,0,0. should I maybe on each frame not only moving vertices but the entire plane?
or is something else.
(face normals seems to be pointing in the right direction, I see the texture on the plane and it's not inverted as it should be if it was the face backside with double sided planes. guess it's not by default in three.js when creating plane)
Ray got problems with object position 0,0,0 (because somewhere will be divided by position and will result in not dividable). Try another position.

OBJ format and Flat vs Smooth Shading

I'm using OpenGL ES 1.1 and working on converting an OBJ export from Blender into some binary files containing vertex data. I actually already have a working tool, but I'm working on changing some things and came across a question.
Even with Smooth shading, it seems that with correct normals (perpendicular to the face plane) it achieves a flat appearance for faces. With Smooth shading enabled and the proper normals (simply via edges marked as sharp in Blender and an edge-split modifier applied), I can get the affect of smooth parts and sharp edges.
Where I'm going with this brings 2 questions.
Are the "s 1" or "s off" lines where smooth or flat shading is denoted in the OBJ file completely unnecessary from a smooth shading and use of normals standpoint?
When actually set to Flat shading in OpenGL, are normals completely ignored (or just assumed to all be perpendicular to the faces)?
For a vertex to look smooth, its normal has to be the average of the adjacent face normals (or something the like), but not perpendicular to the face plane (except if you meaned the average plane of all its adjacent faces).
GL_FLAT means, the color of a face is not interpolated over the triangle, but taken from a single triangle corner (don't know which, first or last). This color comes either from vertex colors or vertex lighting, so in fact you get per-face normals, but this is not neccessarily the faces direction, but the normal of a corner vertex.
If you got per vertex normals in the OBJ file you do not need the s parts. But you can use these to compute vertex normals. The s parts are the smoothing groups and are to be interpreted as 32bit bitfields. So there are actually 32 different smoothing groups and every face can be part of more than one. So all faces after an "s 5" line are part of smoothing groups 1 and 3 (first and third bits set). When two neighbouring faces are part of the same smoothing group, the edge between them is smooth (vertices share normals). This way you can reconstruct the neccessary per-vertex normals.
Changing the mode between gl_flat and gl_smooth doesn't seem to affect my rendering when I'm using per vertex normals. Your problem from what I can tell is that each face only has one normal. For smooth shading, each face should have three normals, one for each vertex, and they should all be different. For example, the normals of a cylinder, if projected inside of the cylinder, should all intersect at the axis of the cylinder. If your model has smooth normals, then an OBJ export should export per vertex normals. It sounds like you are probably assigning per face normals. As far as rendering in OpenGL-ES, the smoothing groups aren't used, only normals.

Resources