Face normals on dynamic geometry - javascript

I'm trying to create a vertex animation for a mesh.
Just imagine a vertex shader, but in software instead of hardware.
Basically what I do is to apply a transformation matrix to each vertex. The mesh it's ok but the normals doesn't look good at all.
I've try to use both computeVertexNormals() and computeFaceNormals() but it just doesn't work.
The following code is the one I used for the animation (initialVertices are the initial vertices generated by the CubeGeometry):
for (var i=0;i<mesh1.geometry.vertices.length; i++)
{
var vtx=initialVertices[i].clone();
var dist = vtx.y;
var rot=clock.getElapsedTime() - dist*0.02;
matrix.makeRotationY(rot);
vtx.applyMatrix4(matrix);
mesh1.geometry.vertices[i]=vtx;
}
mesh1.geometry.verticesNeedUpdate = true;
Here there're two examples, one working correctly with CanvasRenderer:
http://kile.stravaganza.org/lab/js/dynamic/canvas.html
and the one that doesn't works in WebGL:
http://kile.stravaganza.org/lab/js/dynamic/webgl.html
Any idea what I'm missing?

You are missing several things.
(1) You need to set the ambient reflectance of the material. It is reasonable to set it equal to the diffuse reflectance, or color.
var material = new THREE.MeshLambertMaterial( {
color:0xff0000,
ambient:0xff0000
} );
(2) If you are moving vertices, you need to update centroids, face normals, and vertex normals -- in the proper order. See the source code.
mesh1.geometry.computeCentroids();
mesh1.geometry.computeFaceNormals();
mesh1.geometry.computeVertexNormals();
(3) When you are using WebGLRenderer, you need to set the required update flags:
mesh1.geometry.verticesNeedUpdate = true;
mesh1.geometry.normalsNeedUpdate = true;
Tip: is it a good idea to avoid new and clone in tight loops.
three.js r.63

Related

How do I change the basic parameters of a Geometry in Three.js (for example, radius, number of vertices, etc.)

I create a tetrahedron of radius 3
// create a tetrahedron
var tetGeometry = new THREE.TetrahedronGeometry(3);
var tetMaterial = new THREE.MeshLambertMaterial(
{color: 0x20f020, transparent:true, opacity:0.6});
tet = new THREE.Mesh(tetGeometry, tetMaterial);
tet.name='tet';
tet.castShadow = true;
Later, I want the tetrahedron to grow:
// change hedron
scene.getObjectByName('tet').radius = control.hedronRadius;
That doesn't work.
// change vertices
scene.getObjectByName('tet').detail = control.hedronVertices;
That doesn't work either.
scene.getObjectByName('tet').verticesNeedUpdate;
And this doesn't help.
So how do I change the radius of a tetrahedron (or any Geometry) and how do I change the vertices.
In the documentation I see references to:
Geometry
.dynamic
.morph
.verticesNeedUpdate
.scale
And also references to bones and skeletons and skinned meshes used to animate geometries.
How do I change these aspects of Geometries in general?
What's the most reasonable, suggested way then to grow the radius of a Tetrahedron, or change the number of vertices show it becomes a different number polyhedron?
To change geometry you need to use:
morphTargets: true
I've prepared an example using a tetrahedron as you mention in jsfiddle.
Use sliders to change geometry.
To make some custom vertices and "fill" them by faces, you need to understand a lot of things from math, like; point, vector, etc.
I've done 2 simple flat objects, triangle and square in jsfiddle.
I hope that you'll easy understand how it works in general.

Create texture from Array THREE.js

I'm working on a terrain generator, but I can't seen to figure out how to do the colors. I want to be able to generate an image that will take up my whole PlaneGeometry. My question is how can I create a single image that will cover the entire PlaneGeometry (with no wrapping) based off my height map? I can think of one way, but I'm not sure it would fully cover the PlaneGeometry and it would be very inefficient. I'd draw it in a two-dimensional view with colors on a canvas. I'd then convert the canvas to the texture Is that the best/only way?
UPDATE: Using DataTexture, I got some errors. I have absolutely no idea where I went wrong. Here's the error I got:
WebGL: drawElements: texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'. Or the texture is Float or Half Float type with linear filtering while OES_float_linear or OES_half_float_linear extension is not enabled.
Both the DataTexture and the PlaneGeometry have a size of 512^2. What can I do to fix this?
Here's some of the code I use:
EDIT: I fixed it. Here's the working code I used.
function genDataTexture(){
//Set the size.
var dataMap = new Uint8Array(1 << (Math.floor(Math.log(map.length * map[0].length * 4) / Math.log(2))));
/* ... */
//Set the r,g,b for each pixel, color determined above
dataMap[count++] = color.r;
dataMap[count++] = color.g;
dataMap[count++] = color.b;
dataMap[count++] = 255;
}
var texture = new THREE.DataTexture(dataMap, map.length, map[0].length, THREE.RGBAFormat);
texture.needsUpdate = true;
return texture;
}
/* ... */
//Create the material
var material = new THREE.MeshBasicMaterial({map: genDataTexture()});
//Here, I mesh it and add it to scene. I don't change anything after this.
The optimal way, if the data is already in your Javascript code, is to use a DataTexture -- see https://threejs.org/docs/#api/textures/DataTexture for the general docs, or look at THREE.ImageUtils.generateDataTexture() for a fairly-handy way to make them. http://threejs.org/docs/#Reference/Extras/ImageUtils

Three.js: Updating Geometries vs Replacing

I have a scene with lots of objects using ExtrudeGeometry. Each of these need to update each frame, where the shape that is being extruded is changing, along with the amount of extrusion. The shapes are being generated using d3's voronoi algorithm.
See example.
Right now I am achieving this by removing every object from the scene and redrawing them each frame. This is very costly and causing performance issues. Is there a way to edit each mesh/geometry instead of removing from the scene? Would this help with performance? Or is there a more efficient way of redrawing the scene?
I'd need to edit both the shape of the extrusion and the amount of extrusion.
Thanks for taking a look!
If you're not changing the number of faces, you can use morph targets http://threejs.org/examples/webgl_morphtargets.html
You should
Create your geometry
Clone the geometry and make your modifications to it, such as the maximum length of your geometry pillar
Set both geometries as morph targets to your base geometry, for example
baseGeo.morphTargets.push(
{ name: "targetName", vertices: [ modifiedVertexArray ] }
);
After that, you can animate the mesh this using mesh.updateMorphTargets()
See http://threejs.org/examples/webgl_morphtargets.html
So I managed to come up with a way of not having to redraw the scene every time and it massively improved performance.
http://jsfiddle.net/x00xsdrt/4/
This is how I did it:
Created a "template geometry" with ExtrudeGeometry using a dummy
10 sided polygon.
As before, created a bunch of "points", this time assigning each
point one of these template geometries.
On each frame, iterated through each geometry, updating each vertex
to that of the new one (using the voronoi alg as before).
If there are extra vertices left over, "bunch" them up into a single point. (see http://github.com/mrdoob/three.js/wiki/Updates.)
Looking at it now, it's quite a simple process. Before, the thought of manipulating each vertex seemed otherworldly to me, but it's not actually too tricky with simple shapes!
Here's how I did the iteration, polycColumn is just a 2 item array with the same polygon in each item:
// Set the vertex index
var v = 0;
// Iterate over both top and bottom of poly
for (var p=0;p<polyColumn.length;p++) {
// Iterate over half the vertices
for (var j=0;j<verts.length/2;j++) {
// create correct z-index depending on top/bottom
if (p == 1) {
var z = point.extrudeAmount;
} else {
var z = 0;
}
// If there are still legitimate verts
if (j < poly.length) {
verts[v].x = poly[j][0];
verts[v].y = poly[j][1];
verts[v].z = z;
// If we've got extra verts, bunch them up in the same place
} else {
verts[v].x = verts[v - 1].x;
verts[v].y = verts[v - 1].y;
verts[v].z = z;
}
v++;
}
}
point.mesh.geometry.verticesNeedUpdate = true;

Mesh becomes very angular after substracting with ThreeCSG

I experience a problem when substracting a mesh from an other mesh using ThreeCSG. My main mesh is a ring and the mesh to substract is a diamond. Before the process to scene looks like this: Mesh fine. But after substracting the meshes the ring becomes angular: Mesh Broken. I do apply the same material / shading as before. Here is the code I use:
var ring_bsp = new ThreeBSP(ring);
var stone_bsp = new ThreeBSP(stone);
var substract_bsp = ring_bsp.subtract( stone_bsp );
var result = substract_bsp.toMesh( ringMaterial );
result.geometry.computeVertexNormals();
result.material.needsUpdate = true;
result.geometry.buffersNeedUpdate = true;
result.geometry.uvsNeedUpdate = true;
result.scale.x = result.scale.y = result.scale.z = 19;
scene.remove(ring);
scene.add(result);
Update one:
If I remove "result.geometry.computeVertexNormals();" the result looks even worst: link.
Update two:
I created a jsfiddle with a minimal case
Update three:
After looking some more into the problem and Wilts last update, I saw that after I use ThreeBSP the vertexes are messed up. You can see this very well in this fiddle.
Update four:
The problem seems to be within the "fromGeometry / toGeometry" functions as I get the same broken mesh if I don't do any substraction at all.
It looks like (some of) your vertex normals get lost during translation (translating your geometry to CSG and translating back to Three.js). You should check out the source code to see where this goes wrong.
UPDATE 1:
I looked into the source code of ThreeCSG.js it seems there is a bug on line 48.
It should be:
vertex = new ThreeBSP.Vertex( vertex.x, vertex.y, vertex.z, face.vertexNormals[1], uvs );
The index for the vertexNormals should be 1 instead of 2.
Maybe that bug causes the wrong export result.
UPDATE 2:
Try updating the vertexNormals of the geometry before you convert to CSG:
var geometry = ring.geometry;
geometry.computeFaceNormals();
geometry.computeVertexNormals();
Note. You need to call computeNormals() first for the correct result.
UPDATE 3:
In the conversion of faces from Three.js geometries to CSG geometries the ThreeBSP.Polygon.prototype.classifySide method checks wheter the vertex of the adjacent face is in the front, in the back or coplanar to the current face. If the point is coplanar the CSG face will be defined as a Face with four vertex points. Because of this process some of your THREE.Face3 get converted to a 4 point CSG face. When later translating it back to a THREE.Face3 the Face vertexNormals become different from their initial values.
The vertex is classified FRONT, BACK or COPLANAR using an EPSILON value to compare the vertex normal with the face normal. If the difference is too small the Vertex is considered coplanar. By increasing the EPSILON value in your ThreeBSP library you can control the precision.
If you set EPSILON to 10 your triangles will never be considered coplanar and the conversion result will be correct.
So at line 5 of your ThreeBSP library set:
EPSILON = 10,

Three.js outlines

Is it possible to have an black outline on my 3d models with three.js?
I would have graphics which looks like Borderlands 2. (toon shading + black outlines)
I'm sure I came in late. Let's hope this would solve someone's question later.
Here's the deal, you don't need to render everything twice, the overhead actually is not substantial, all you need to do is duplicate the mesh and set the duplicate mesh's material side to "backside". No double passes. You will be rendering two meshes instead, with most of the outline's geometry culled by WebGL's "backface culling".
Here's an example:
var scene = new THREE.Scene();
//Create main object
var mesh_geo = new THREE.BoxGeometry(1, 1, 1);
var mesh_mat = new THREE.MeshBasicMaterial({color : 0xff0000});
var mesh = new THREE.Mesh(mesh_geo, mesh_mat);
scene.add(mesh);
//Create outline object
var outline_geo = new THREE.BoxGeometry(1, 1, 1);
//Notice the second parameter of the material
var outline_mat = new THREE.MeshBasicMaterial({color : 0x00ff00, side: THREE.BackSide});
var outline = new THREE.Mesh(outline_geo, outline_mat);
//Scale the object up to have an outline (as discussed in previous answer)
outline.scale.multiplyScalar(1.5);
scene.add(outline);
For more details on backface culling, check out: http://en.wikipedia.org/wiki/Back-face_culling
The above approach works well if you want to add an outline to objects, without adding a toon shader, and thus losing "realism".
Toon shading by itself supports edge detection. They've developed the 'cel' shader in Borderlands to achieve this effect.
In cel shading devs can either use the object duplication method (done at the [low] pipeline level), or can use image processing filters for edge detection. This is the point at which performance tradeoff is compared between the two techniques.
More info on cel: http://en.wikipedia.org/wiki/Cel_shading
Cheers!
Yes it is possible but not in a simple out-of-the-box way. For toon shading there are even shaders included in /examples/js/ShaderToon.js
For the outlines I think the most commonly suggested method is to render in two passes. First pass renders the models in black, and slightly larger scale. Second pass is normal scale and with the toon shaders. This way you'll see the larger black models as an outline. It's not perfect but I don't think there's an easy way out. You might have more success searching for "three.js hidden line rendering", as, while different look, somewhat similar method is used to achieve that.
Its a old question but here is what i did.
I created a Outlined Cel-shader for my CG course. Unfortunately it takes 3 rendering passes. Im currently trying to figure out how to remove one pass.
Here's the idea:
1) Render NormalDepth image to texture.
In vertex shader you do what you normally do, position to screen space and normal to screen space.
In fragment shader you calculate the depth of the pixel and then create the normal color with the depth as the alpha value
float ndcDepth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) / (gl_DepthRange.far - gl_DepthRange.near);
float clipDepth = ndcDepth / gl_FragCoord.w;
2) Render the scene on to a texture with cel-shading. I changed the scene override material.
3)Make quad and render both textures on the quad and have a orto camera look at it. Cel-shaded texture is just renderd on quad but the normaldepth shaded on that you use some edge detection and then with that you know when the pixel needs to be black(edge).

Categories

Resources