Generating geometry - part 1: Basics
Note: in every snippet and pen I use a self-made math library for vectors and matrices. If you want to use it too, then set the following link as resource in your pen. If you use it, then please credit me.
Link: http://yourjavascript.com/01666321507/math-min.js
Link to part 2: Link Link to part 3: Link
If you use Three.js, you probably came across with one of the many geometry object (they tend to end with "Geometry", like TubeGeometry
or IcosahedronGeometry
. They are quite easy to use, you just create a new icosahedron, add it to a scene, and boom, you have an icosahedron.
But most of us don't know how these objects actually work. This post series is intended to make things about these objects clearer.
The easiest of all - the plane
Let's start with an easy one, a plane. A plane consists of 4 vertices (points in 3d space). These 4 vertices create 2 triangles. Why triangles instead of a quad? Most GPUs don't like quads, they can only draw triangles on the screen, and when you give them a quad, then they need to slice it up into two triangles. This is however not as effective as if you'd do it on the CPU.
So, how do we create a plane? We create 4 vertices and an index array. The index array is used to tell in which order the vertices need to be used.
The vertices:
var width = 1;
var height = 1;
var vertices = [];
var indices = [];
vertices.push(new Vector3(0, 0, 0));
vertices.push(new Vector3(width, 0, 0));
vertices.push(new Vector3(width, 0, height));
vertices.push(new Vector3(0, 0, height));
indices = [
0, 1, 3,
3, 1, 2
];
This creates the vertices and indices for a plane. In the code above I use an object called Vector. Vectors are a way to represent a position in 3 dimensional space.
Now all the vertices are in place. If you actually render them with whatever technique you like, then you get this (I added animation and perspective to make it neater):
Little bit of trigonometry - A circle
Circles are made of triangles too. How many triangles it consists of defines how smooth the edges are.
To create the points, we need to use trigonometry. Each side of the polygon should create a triangle with the middle point
var vertices = [];
var indices = [];
var radius = 100;
var detail = 20;
// Middle vertex
vertices.push(new Vector3(0, 0, 0));
// Create vertices
for (var i = 0; i < detail; i++) {
var angle = 2 * Math.PI / detail * i;
var x = Math.cos(angle) * radius;
var y = Math.sin(angle) * radius;
vertices.push(new Vector3(x, 0, y));
}
// Loop trough each edge (there's detail-1 edge)
for (var i = 1; i < detail; i++) {
// Each index trio defines a triangle
// We connect a vertex with the next vertex on the circle and the middle
indices.push(i, i + 1, 0);
}
// Last triangle to close the shape off
indices.push(detail, 1, 0);
If everything is okay, then this should look like this (I set the detail to 20. If you use a higher value, like 150-200, then you won't notice the difference between this and a circle):
A little extra - Rotating shapes
To rotate shapes around the origin (0,0,0) you need to use matrix transformations. Each vertex should be multiplied by the rotation matrix.
// Vertices defined above
var deg = Math.PI / 180; // 1 degree in radian
var angle = [45 * deg, 30 * deg, -20 * deg]; // 45 degree around the x, 30 around the y and -20 around the z axis
// Matrices
var rotX = Matrix3.rotate(angle[0], 1, 0, 0); // This is the usual way to create a rotation matrix.
var rotY = Matrix3.rotate(angle[1], 0, 1, 0); // The first argument is the angle, the next three are
var rotZ = Matrix3.rotate(angle[2], 0, 0, 1); // used to tell on wich axis you need to apply the rotation.
// The complete rotation matrix.
var rot = rotZ.multiplyMatrix(rotY.multiplyMatrix(rotX));
for (var i = 0; i < vertices.length; i++) {
vertices[i] = rot.multiplyVectior(vertices[i]);
}