52

I've asked this and got the answer:

var geom = new THREE.Geometry(); 
var v1 = new THREE.Vector3(0,0,0);
var v2 = new THREE.Vector3(0,500,0);
var v3 = new THREE.Vector3(0,500,500);

geom.vertices.push(new THREE.Vertex(v1));
geom.vertices.push(new THREE.Vertex(v2));
geom.vertices.push(new THREE.Vertex(v3));

var object = new THREE.Mesh( geom, new THREE.MeshNormalMaterial() );
scene.addObject(object);

I expected this to work but it didn't.

gman
  • 100,619
  • 31
  • 269
  • 393
MaiaVictor
  • 51,090
  • 44
  • 144
  • 286
  • 4
    I know this question is old but just for reference [this article](https://threejsfundamentals.org/threejs/lessons/threejs-custom-geometry.html) and [this one](https://threejsfundamentals.org/threejs/lessons/threejs-custom-buffergeometry.html) cover this topic – gman Jun 14 '19 at 06:58

3 Answers3

79

You've added vertices, but forgot to put those vertices into a face and add that to the geometry:

geom.faces.push( new THREE.Face3( 0, 1, 2 ) );

so your snippet becomes:

var geom = new THREE.Geometry(); 
var v1 = new THREE.Vector3(0,0,0);
var v2 = new THREE.Vector3(0,500,0);
var v3 = new THREE.Vector3(0,500,500);

geom.vertices.push(v1);
geom.vertices.push(v2);
geom.vertices.push(v3);

geom.faces.push( new THREE.Face3( 0, 1, 2 ) );

var object = new THREE.Mesh( geom, new THREE.MeshNormalMaterial() );
scene.addObject(object);

The idea is that a Face3 instance references 3 vertices(the x,y,z coords you've added previously to the geometry) by using the indices of the vertices in the list/array. Currently you only have 3 vertices and you want to connect them,so your face references index 0,1 and 2 in the vertices array.

Since you're using a mesh normals material, you might want to compute normals for the geometry. Also, make sure your object can be visible (is not to big or to close to the camera to be clipped out, is facing the right direction - towards the camera, etc.) Since you're drawing in the YZ plane, to see your triangle, something like this should work:

var geom = new THREE.Geometry(); 
var v1 = new THREE.Vector3(0,0,0);
var v2 = new THREE.Vector3(0,500,0);
var v3 = new THREE.Vector3(0,500,500);

geom.vertices.push(v1);
geom.vertices.push(v2);
geom.vertices.push(v3);
                
geom.faces.push( new THREE.Face3( 0, 1, 2 ) );
geom.computeFaceNormals();
                
var object = new THREE.Mesh( geom, new THREE.MeshNormalMaterial() );
                
object.position.z = -100;//move a bit back - size of 500 is a bit big
object.rotation.y = -Math.PI * .5;//triangle is pointing in depth, rotate it -90 degrees on Y
                
scene.add(object);

Update: THREE.Geometry and THREE.Face3 are deprecated: THREE.BufferGeometry is recommended instead.

const geometry = new THREE.BufferGeometry();

const positions = [
0,   0, 0,    // v1
0, 500, 0,   // v2
0, 500, 500  // v3
];

geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );
geometry.computeVertexNormals();

const object = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial() );
scene.add(object);

In short, as opposed to providing vertex positions and Face3 objects with 3 vertex indices now you would use a flat array in x1, y1, z1, x2, y2, z2, ..., xn, yn, zn order (every 3 x,y,z triplets in order define a face).

Additionally, it's possible to compute and provide vertex colours and normals. There are plenty of three.js example to start with, including:

webgl_buffergeometry three.js triangles example

webgl_buffergeometry_indexed three.js subdivided plane example

Steve
  • 4,372
  • 26
  • 37
George Profenza
  • 50,687
  • 19
  • 144
  • 218
  • 1
    Well, `THREE.Geometry` was deprecated after some years.. mainly for performance https://discourse.threejs.org/t/three-geometry-will-be-removed-from-core-with-r125/22401/ – jiyinyiyong May 27 '21 at 17:54
  • 1
    @jiyinyiyong Thank you for that ! It's been a while since I posted this answer :) I've added a few minimal notes. – George Profenza May 27 '21 at 21:07
  • 1
    Haha, I just debugged that last night, turned out `.computeVertexNormals()` must be called, otherwise the object is not displayed in correct color without normals. – jiyinyiyong May 28 '21 at 05:05
29

You can automate your triangulation

For big polygons it can be quite a job to manually add the faces. You can automate the process of adding faces to the mesh using the triangulateShape method in THREE.ShapeUtils like this:

var vertices = [your vertices array];
var holes = [];
var triangles, mesh;
var geometry = new THREE.Geometry();
var material = new THREE.MeshBasicMaterial();

geometry.vertices = vertices;

triangles = THREE.ShapeUtils.triangulateShape( vertices, holes );

for( var i = 0; i < triangles.length; i++ ){

    geometry.faces.push( new THREE.Face3( triangles[i][0], triangles[i][1], triangles[i][2] ));

}

mesh = new THREE.Mesh( geometry, material );

Where vertices is your array of vertices and with holes you can define holes in your polygon.

Note: Be careful, if your polygon is self intersecting it will throw an error. Make sure your vertices array is representing a valid (non intersecting) polygon.

Wilt
  • 41,477
  • 12
  • 152
  • 203
  • 2
    This method seems to completely ignore Z axis, and work only in 2D. Doesn't work at all with 3d vertices. – Marcin Raczkowski Oct 11 '15 at 23:23
  • `THREE.Shape.Utils.triangulateShape` doesn't work anymore. – ioan Jul 12 '16 at 11:31
  • 1
    @GamsterKatalin Check my updated answer. In newer versions it is: `THREE.ShapeUtils.triangulateShape`. – Wilt Jul 12 '16 at 11:32
  • Your answer doesn't automate triangulation for 3d vertices (giving me a lot of warnings because x-y points are duplicated, triangulation failing in the end), so now I am trying to figure out the rationale behind generating those index points that face3 is built out of: https://github.com/josdirksen/learning-threejs/blob/master/chapter-02/05-custom-geometry.html#L98 considering that they are hundreds of vertices from autocad objects. – ioan Jul 12 '16 at 11:59
  • 1
    @GamsterKatalin Triangulation is only for 2D shapes. Currently you won't find any triangulation libraries in javascript that work in 3D. You will have to work around. One solution would be to use a rotation matrix to rotate your 3D shape into the x-y plane and then triangulate and rotate the result back with the inverse matrix. – Wilt Jul 12 '16 at 12:39
11

THREE.Vertex has been deprecated in the newest version of Three.js so that part is not needed anymore:

geom.vertices.push(v1);
geom.vertices.push(v2);
geom.vertices.push(v3);
BenMorel
  • 34,448
  • 50
  • 182
  • 322
BishopZ
  • 6,269
  • 8
  • 45
  • 58
  • 8
    Note that this refers to an earlier revision of George Profenza's answer. Nothing should be removed from Profenza's current code. – Sphinxxx Aug 03 '15 at 14:47