Autodesk Creative Platform Core Version 1.19.0
A broad and deep collection of 2D and 3D capabilities.

Platonic Solid Generator - Part 1

The Autodesk Creative Platform Library Editor lets you write Shape Generators that construct 3D shapes in several different ways. A shape generated automatically becomes watertight so you can group it with other shapes, use it as a hole, and so on. Shape Generators are always procedural: the shape will be recomputed on the fly as needed, so the results of a Shape Generator are not set in stone once created. Even when the shape is included in a group, its form can be modified by visually tweaking parameters that were defined by the author of the Shape Generator.

This tutorial will introduce you to building unlimited 3D shapes out of individual points in space. There's another tutorial, Heart Extrusion Generator, which shows how a Shape Generator can produce shapes starting from 2D elements.

Table of contents

Introduction

At the heart of the Autodesk Creative Platform happens to be a solid modeler. The most typical representation of 3D shapes is only concerned with points and depthless surfaces and thus lacks any notion of volume within the shapes. This kind of 3D shape is usually called a "mesh" - you could visualize it as pieces of cloth wrapped over a wireframe of points. The points are called vertices, and the surface elements are faces. However because of the unique underlying technology in Autodesk's Creative Platform, even meshes that are not watertight can be converted into a solid.

Things in the real world are of course very much concerned with volume, so when designing anything that represents physical objects, the advantage of working in solids is clear. But meshes have their own practical advantages: it is easy to write code to generate meshes, and there is a large amount of mesh data in the wild. The Autodesk Creative Platform lets you combine the best of both worlds - generate meshes in your script, and they become solids.

This tutorial covers the most fundamental type of geometric solids, the five Platonic solids.

The Platonic solids are unique because they are the only convex regular polyhedra. In plain English, they are the only solids that can be built out of identical faces (either triangles, squares or pentagons), with the same number of faces meeting at each vertex, and with faces meeting each other always at the same angle at the edges.

These shapes are named after the Greek philosopher Plato. He was fascinated by these regular solids and claimed a mystic link between the five solids and the five classical elements discussed in Greek philosophy - Earth, Water, Air, Fire and the invisible Aether. Were he alive today, Plato would surely be an Autodesk Creative Platform user, as he was a man who understood the importance of being able to turn ideas into physical reality.

There are a great many ways to construct the Platonic solids because of their beautifully regular mathematical properties. This tutorial will demonstrate how to write Shape Generators for these solids in a “common sense” way that assumes only basic familiarity with JavaScript and some trigonometry. There are also more elegant, generalized mathematical formulations for building the solids - if you're interested; the Wikipedia article on the solids is a fine place to start.

Creating a Shape Generator

Before jumping into geometry, let's take a brief glance at the essentials of creating a Shape Generator.

Open the Autodesk Creative Platform Library Editor. If you're using Tinkercad, on the right-hand side expand Your Shape Generators and click New Shape Generator. Choose one of the example scripts as a starting point, for example Star.

Click Edit, and the Autodesk Creative Platform Library Editor pops up at the left-hand side of the window.

Script editor

Delete the existing code within the process() function and paste in the following:

function process(params) {
    var mesh = new Mesh3D();

    return Solid.make(mesh);
}

An empty mesh now awaits us, eager to be filled with vertices and faces. Note the call to Solid.make: the returned shape must be a solid, so we call this function to turn the mesh into a solid representation.

A quick note on the process() function: it is necessary because it's the so-called “entry point” for Shape Generators on the Autodesk Creative Platform. Without this function, the script would not be called to do any useful work. As it happens, this script doesn't do anything useful anyway currently, returning an empty mesh at it does. Let's fix that.

Tetrahedron

The tetrahedron, also known as a pyramid with a triangular base, is a fine starting point for a mesh tutorial because it's the simplest possible solid that can be defined as a mesh.

Consisting of four vertices and four faces, it's easy to mentally visualize the construction of the tetrahedron: all we need is an equilateral triangle for the base, i.e. a triangle whose angles are identical, and a “peak” vertex at the center.

Tetrahedron

To build the base triangle, we start with the angle in radians. Let's recall some trigonometry. A full circle is 2 × π, so each point of the equilateral triangle has an angle one-third of that:

var angle = 2 * Math.PI / 3;

The coordinates for the triangle's points can be calculated by imagining a circle around the triangle and calculating points on that circle separated by this angle. To define the size of the triangle - and consequently the whole tetrahedron - we'll need the radius of the circumscribing circle. For the moment, let's just define the radius as 10:

var r = 10;

Now we can create the vertices for the triangle's base:

var sides = [];
for (var i = 0; i < 3; i++) {
    var x = r * Math.cos(i * angle);
    var y = r * Math.sin(i * angle);
    sides.push( [x, y, 0] );
}

Note that we're passing zero for the z coordinate, and the x and y coordinates are around the origin. By default, this tetrahedron will lie at the center of the workplace when placed into your design.

Next we need to place the peak vertex. Its x and y coordinates are obviously at the center of the base triangle, i.e. point (0, 0). But what is the z coordinate? We can use good old Pythagoras to figure this out, but we need to know the length of a tetrahedron's edge in relation to the radius we used to construct the base. I'll skip the formulation and simply tell you that the length of the edge is √3r - you can find this and other possibly useful formulas at the Wikipedia article on tetrahedrons.

Armed with the radius a and edge length b, we can calculate the height of our tetrahedron using the Pythagorean theorem:

Recall that b, edge length, is √3r. When we insert this into the equation above, it simplifies neatly down to √2r.

var h = Math.sqrt(2) * r;

Let's store the last vertex:

var peak = [0, 0, h];

Now we have all the vertices in memory as arrays. We can call methods on the Mesh3D object to define the four faces of the tetrahedron based on these vertices:

mesh.triangle(sides[0], sides[2], sides[1]);
mesh.triangle(sides[0], sides[1], peak);
mesh.triangle(sides[1], sides[2], peak);
mesh.triangle(sides[2], sides[0], peak);

The first triangle is the base. By the way, the Mesh3D.triangle method is flexible about input. We can pass vertices as individual arrays like we did here, but it's equally possible to pass a single array containing nine numbers for all the three points' coordinates, or to pass the nine numbers as individual arguments.

The ordering of vertices in these calls is critical. If you try flipping some of the indices within one of the Mesh3D.triangle calls, for example by changing the parameters of the first triangle call to (sides[0], sides[2], sides[1]). You won't see anything rendered in the editor.

It's not enough that the indices define a valid triangle. We must also pay attention to the “winding order” of the indices - in other words, whether the triangle is defined in clockwise or counter-clockwise order.

The winding order essentially defines which side of the triangle is "on the outside" and which is "on the inside" of the shape. The important point is that all your triangles must use the same winding order. You can use either direction, as long as it's the same for all triangles. To see an example of this in practice, you can try flipping the first two coordinates of each triangle() call. This will reverse the winding order but visually the shape is unaffected.

The Autodesk Creative Platform can sometimes allow either winding order for Shape Generators because of the underlying technology. In traditional 3D applications that work exclusively on meshes, the winding order usually must be the same for all polygons defined in the whole system, not just within one object. But in the Autodesk Creative Platform your mesh will be converted into a special solid representation by the geometry engine anyway, so the winding order of polygons just needs to be consistent within your own script.

Here is the complete function. You can copy and paste it into the script editor, then click Save

function process(params) {
    var r = params.radius;
    var angle = 2*Math.PI / 3;
    var h = Math.sqrt(2) * r;

    var sides = [];
    for (var i = 0; i < 3; i++) {
        var x = r * Math.cos(i * angle);
        var y = r * Math.sin(i * angle);
        sides.push([x, y, 0]);
    }
    var peak = [0, 0, h];

    var mesh = new Mesh3D();
    mesh.triangle(sides[0], sides[2], sides[1]);
    mesh.triangle(sides[0], sides[1], peak);
    mesh.triangle(sides[1], sides[2], peak);
    mesh.triangle(sides[2], sides[0], peak);
    
    return Solid.make(mesh);
}

Adding parameters

Tetrahedron Tools menu

Our custom tetrahedron shape is currently fixed at a specific size. We can always resize the shape in an application such as Tinkercad, but perhaps it would be useful to have a way to control the radius value we used in creating the tetrahedron. This can be accomplished by adding a custom parameter.

As you can see from the screenshot on the right, once a Shape Generator has parameters, they become accessible directly by the user. This way you can easily change parameter values for a single shape or a whole selection of shapes.

Parameters are defined by adding an object called params into the script, alongside the required process() function.

Here's the parameter definition for a Radius slider:

params = [
  {
    "id": "radius", 
    "displayName": "Radius",
    "type": "float",
    "rangeMin": 1,
    "rangeMax": 50,
    "default": 20
  }
];

The ‘params' object is a JavaScript array containing JavaScript objects describing each parameter. More specifically, this list of parameter definitions is a JSON array. Each key (such as “displayName”) must be quoted, and the array's contents must not end with a comma. (This may seem like a somewhat arbitrary restriction, but using JSON ensures that the parameters can always be parsed separately from actual script execution.)

Tetrahedron

It's not enough to just define a slider; we also need to use that value in our processing function. The parameter values are passed to the function in an argument called params. Change the var r = ... line to the following:

var r = params.radius;

Click Save, and the slider is ready for use. We're done with the tetrahedron.

Cube

The next solid is the cube, and despite having more vertices and faces than the tetrahedron, it is easier to construct because the faces meet at right angles. This cube Shape Generator is also useful starting point for any block-like angular shapes (for example a slanted block or a wedge with a tapered end).

To keep things simple, we will not touch parameters again for the rest of this tutorial. All of the regular solids need only one parameter for the size, and so we can just reuse the "Radius" parameter we created for the tetrahedron.

Cube

To construct a cube, we are more interested in the edge length, which is √2r. (You can confirm this by imagining a right-angled triangle whose 90° angle lies at the center of the cube base. The edge length is the hypotenuse of this triangle.)

Since we want the cube center to lie at the origin, that means the x/y coordinates of the corners of the cube base are half of the edge length from the origin. Let us call this half-edge-length variable he and build the base:

var r = params.radius;
var e = Math.sqrt(2) * r;
var he = e / 2;

var bot = [];  // Bottom face vertices
bot.push( [-he, -he, 0] );
bot.push( [he, -he, 0] );
bot.push( [he, he, 0] );
bot.push( [-he, he, 0] );

Building the top of the cube is simply a matter of setting the right height:

var top = [];  // Top face vertices
top.push( [-he, -he, e] );
top.push( [he, -he, e] );
top.push( [he, he, e] );
top.push( [-he, he, e] );

These are the vertices for the cube. The Mesh3D object has a Mesh3D.quad method that we can use to define the six faces of the cube:

var mesh = new Mesh3D();
mesh.quad(bot[3], bot[2], bot[1], bot[0]);
mesh.quad(top[0], top[1], top[2], top[3]);

mesh.quad(bot[0], bot[1], top[1], top[0]);
mesh.quad(bot[1], bot[2], top[2], top[1]);
mesh.quad(bot[2], bot[3], top[3], top[2]);
mesh.quad(bot[3], bot[0], top[0], top[3]);

Below is the complete script for the cube.

params = [
  { 
    "id": "radius",
    "displayName": "Radius",
    "type": "float",
    "rangeMin": 1,
    "rangeMax": 50,
    "default": 20 }
];

function process(params) { 
  var r = params.radius;
  var e = Math.sqrt(2) * r;
  var he = e / 2;

  var bot = [];
  bot.push( [-he, -he, 0] );
  bot.push( [he, -he, 0] );
  bot.push( [he, he, 0] );
  bot.push( [-he, he, 0] );

  var top = [];
  top.push( [-he, -he, e] );
  top.push( [he, -he, e] );
  top.push( [he, he, e] );
  top.push( [-he, he, e] );

  var mesh = new Mesh3D();
  mesh.quad(bot[3], bot[2], bot[1], bot[0]);
  mesh.quad(top[0], top[1], top[2], top[3]);

  mesh.quad(bot[0], bot[1], top[1], top[0]);
  mesh.quad(bot[1], bot[2], top[2], top[1]);
  mesh.quad(bot[2], bot[3], top[3], top[2]);
  mesh.quad(bot[3], bot[0], top[0], top[3]);

  return Solid.make(mesh);
}

Exercises

To practice 3D thinking, you can try changing those vertex definitions. There are many kinds of blocks that can be created with minimal changes to this cube-generating script. How would you make a slanted box? Or a wedge that has a thin rectangle at the other end and a larger rectangle at the other end?

How about a twisted cube where the top face is rotated? To compute the rotated vertices, take a look back at the Tetrahedron construction. The necessary rotation math is all there - you just need to change a few numbers so that the for loop produces a square instead of an equilateral triangle.

Twisting the cube breaks the planarity of the side faces and reveals that the shape is in fact built out of triangles:

If you are a cubist sculptor, this is probably exactly the shape you were looking for. But for the rest of us, it would be interesting to make the twist smoother. Rather than one sharp diagonal edge across the side, we would want the rotation to progress in steps. To accomplish this we will need to add subdivisions - but that is a great topic for another tutorial later on.