I have created programmatically a simple mesh:
var CreateSimpleMesh = new function () {
var xy = [],
maxX = 7,
maxY = 10,
river = [[0, 5], [0, 4], [1, 3], [2, 2], [3, 2], [4, 1], [5, 1], [6, 0]],
grassGeometry = new THREE.BufferGeometry(),
grassVertexPositions = []
this.init = function () {
for (i = 0; i < maxX; i++) {
for (j = 0; j < maxY; j++) {
xy.push([i, j])
}
}
for (var i = 0; i < xy.length; i++) {
grassVertexPositions.push([xy[i][0], xy[i][1], 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1], 0])
grassVertexPositions.push([xy[i][0], xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0], xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1], 0])
}
for (var i = 0; i < grassVertexPositions.length; i++) {
for (var j = 0; j < river.length; j++) {
if (river[j][0] == grassVertexPositions[i][0] && river[j][1] == grassVertexPositions[i][1]) {
grassVertexPositions[i][2] = -0.5
}
}
}
var grassVertices = new Float32Array(grassVertexPositions.length * 3)
for (var i = 0; i < grassVertexPositions.length; i++) {
grassVertices[i * 3 + 0] = grassVertexPositions[i][0];
grassVertices[i * 3 + 1] = grassVertexPositions[i][1];
grassVertices[i * 3 + 2] = grassVertexPositions[i][2];
}
grassGeometry.addAttribute('position', new THREE.BufferAttribute(grassVertices, 3))
var grassMaterial = new THREE.MeshLambertMaterial({color: 0x00ff00}),
grassMesh = new THREE.Mesh(grassGeometry, grassMaterial)
grassMesh.rotation.x = -Math.PI / 2
Test.getScene().add(grassMesh);
}
}
Problem is that this mesh has only vertices. I have tried to add to it faces like in this question using THREE.Shape.Utils.triangulateShape but BufferGeometry is different than normal geometry and it does not work. Is it possible to add faces to BufferGeometry?
EDIT: Working fiddle
I have created programmatically a simple mesh:
var CreateSimpleMesh = new function () {
var xy = [],
maxX = 7,
maxY = 10,
river = [[0, 5], [0, 4], [1, 3], [2, 2], [3, 2], [4, 1], [5, 1], [6, 0]],
grassGeometry = new THREE.BufferGeometry(),
grassVertexPositions = []
this.init = function () {
for (i = 0; i < maxX; i++) {
for (j = 0; j < maxY; j++) {
xy.push([i, j])
}
}
for (var i = 0; i < xy.length; i++) {
grassVertexPositions.push([xy[i][0], xy[i][1], 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1], 0])
grassVertexPositions.push([xy[i][0], xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0], xy[i][1] + 1, 0])
grassVertexPositions.push([xy[i][0] + 1, xy[i][1], 0])
}
for (var i = 0; i < grassVertexPositions.length; i++) {
for (var j = 0; j < river.length; j++) {
if (river[j][0] == grassVertexPositions[i][0] && river[j][1] == grassVertexPositions[i][1]) {
grassVertexPositions[i][2] = -0.5
}
}
}
var grassVertices = new Float32Array(grassVertexPositions.length * 3)
for (var i = 0; i < grassVertexPositions.length; i++) {
grassVertices[i * 3 + 0] = grassVertexPositions[i][0];
grassVertices[i * 3 + 1] = grassVertexPositions[i][1];
grassVertices[i * 3 + 2] = grassVertexPositions[i][2];
}
grassGeometry.addAttribute('position', new THREE.BufferAttribute(grassVertices, 3))
var grassMaterial = new THREE.MeshLambertMaterial({color: 0x00ff00}),
grassMesh = new THREE.Mesh(grassGeometry, grassMaterial)
grassMesh.rotation.x = -Math.PI / 2
Test.getScene().add(grassMesh);
}
}
Problem is that this mesh has only vertices. I have tried to add to it faces like in this question using THREE.Shape.Utils.triangulateShape but BufferGeometry is different than normal geometry and it does not work. Is it possible to add faces to BufferGeometry?
EDIT: Working fiddle
Share Improve this question edited May 23, 2017 at 12:09 CommunityBot 11 silver badge asked Dec 8, 2015 at 2:58 Bartosz KrzeszewskiBartosz Krzeszewski 1672 silver badges12 bronze badges 2- 1 You need to start with an example that works and then slowly modify it. – WestLangley Commented Dec 8, 2015 at 6:23
- 1 This one is working. – Bartosz Krzeszewski Commented Dec 8, 2015 at 7:33
2 Answers
Reset to default 5Here is how to create a mesh having BufferGeometry
. This is the simpler "non-indexed" BufferGeometry
where vertices are not shared.
// non-indexed buffer geometry
var geometry = new THREE.BufferGeometry();
// number of triangles
var NUM_TRIANGLES = 10;
// attributes
var positions = new Float32Array( NUM_TRIANGLES * 3 * 3 );
var normals = new Float32Array( NUM_TRIANGLES * 3 * 3 );
var colors = new Float32Array( NUM_TRIANGLES * 3 * 3 );
var uvs = new Float32Array( NUM_TRIANGLES * 3 * 2 );
var color = new THREE.Color();
var scale = 15;
var size = 5;
var x, y, z;
for ( var i = 0, l = NUM_TRIANGLES * 3; i < l; i ++ ) {
if ( i % 3 === 0 ) {
x = ( Math.random() - 0.5 ) * scale;
y = ( Math.random() - 0.5 ) * scale;
z = ( Math.random() - 0.5 ) * scale;
} else {
x = x + size * ( Math.random() - 0.5 );
y = y + size * ( Math.random() - 0.5 );
z = z + size * ( Math.random() - 0.5 );
}
var index = 3 * i;
// positions
positions[ index ] = x;
positions[ index + 1 ] = y;
positions[ index + 2 ] = z;
//normals -- we will set normals later
// colors
color.setHSL( i / l, 1.0, 0.5 );
colors[ index ] = color.r;
colors[ index + 1 ] = color.g;
colors[ index + 2 ] = color.b;
// uvs
uvs[ index ] = Math.random(); // just something...
uvs[ index + 1 ] = Math.random();
}
geometry.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
geometry.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
// optional
geometry.puteBoundingBox();
geometry.puteBoundingSphere();
// set the normals
geometry.puteVertexNormals(); // puted vertex normals are orthogonal to the face for non-indexed BufferGeometry
See the three.js examples for many additional examples of creating BufferGeometry
. Also check out the source code for PlaneGeometry
and SphereGeometry
, which are reasonably easy to understand.
three.js r.143
You can add faces using three.js internal function- fromBufferGeometry
. In your case it would be something like this.
var directGeo = new THREE.Geometry();
directGeo.fromBufferGeometry(grassGeometry);
Then use directGeo
to build your mesh, and it will have faces.