Download Article Assets

Extrusion

A very desirable operation to perform on a mesh is diplacing the triangles of which it is composed. Althoug not evident on closed meshes, when displaced, triangles look flat and volumeless. This patch uses a custom geometry script to account for that.

Let's thicken them up

Open the patch thickness.maxpat

This patch takes a Jitter geometry and extrudes the triangles along their vertex normals, forming truncated pyramids of user-defined height. It then performs a random displacement of such extruded triangles to show them in all their glorious thickness.

Let's take a look at the patch:

The first step consists in grabbing a mesh, turning it into a Jitter geometry, and computing vertex normals using jit.geom.normgen. Each vertex in the Jitter geometry structure now retains vertex normals.

Then, jit.geom.todict converts the Jitter geometry into a dictionary accessible by JavaScript.

Double-click on v8 geom.thickness.js to take a look at what the custom geometry script does.

// Go through all the faces
faces.forEach(face => {

  // get two halfedges on this face
  let he0 = face.halfedge;
  let he1 = geom.halfedges[he0].next;

  // get the index of the vertices of this face
  let v0 = geom.halfedges[he0].from;
  let v1 = geom.halfedges[he1].from;
  let v2 = geom.halfedges[he1].to;

  // get the vertex normals
  let n0 = geom.vertices[v0].normal;
  let n1 = geom.vertices[v1].normal;
  let n2 = geom.vertices[v2].normal;

  // get the position of the vertices
  let p0 = geom.vertices[v0].point;
  let p1 = geom.vertices[v1].point;
  let p2 = geom.vertices[v2].point;

  // create 3 new positions based on p0, p1, and p2, 
  // shifted by "thickness" along their normal vector
  let pt0 = translate(p0, n0);
  let pt1 = translate(p1, n0);
  let pt2 = translate(p2, n0);

The script iterates over the triangles reading the positions and the normal vectors of the 3 vertices. It then computes 3 new positions, shifting each vertex inwards along the direction of their vertex normals.

// Push the points into the list
// top face
triangleVertices.push(p0);
triangleVertices.push(p1);
triangleVertices.push(p2);

// bottom face
triangleVertices.push(pt0);
triangleVertices.push(pt1);
triangleVertices.push(pt2);


// side faces
triangleVertices.push(p0);
triangleVertices.push(pt0);
triangleVertices.push(p1);

triangleVertices.push(p1);
triangleVertices.push(pt0);
triangleVertices.push(pt1);

triangleVertices.push(p1);
triangleVertices.push(pt1);
triangleVertices.push(p2);

triangleVertices.push(p2);
triangleVertices.push(pt1);
triangleVertices.push(pt2);

triangleVertices.push(p2);
triangleVertices.push(pt2);
triangleVertices.push(p0);

triangleVertices.push(p0);
triangleVertices.push(pt2);
triangleVertices.push(pt0);

It then triangulates the old and the new positions forming a volume.

Now, open the [p animate] subpatch if you want to take a look at how is the mesh dancing.

The animation is achieved by offsetting the volumes' positions along their face normals using procedural noise provided by jit.bfg.