Platonic solids, named after the philosopher Plato, are highly symmetrical, three-dimensional shapes. Each face of a Platonic solid is the same regular polygon, and the same number of polygons meet at each vertex. This sketch demonstrates the rendering of Platonic solids using the p5.platonic library, showcasing both the immediate mode and retained mode rendering of the shapes. Check out the platonic cells example, which fills quadrille cells with the Platonic solids introduced here.

code
const colors = [
  [1, 0, 0, 1],    // Red
  [0, 1, 0, 1],    // Green
  [0, 0, 1, 1],    // Blue
  [0, 1, 1, 1],    // Cyan
  [1, 0, 1, 1],    // Magenta
  [1, 1, 0, 1],    // Yellow
  [0.5, 0, 0, 1],  // Dark Red
  [0, 0.5, 0, 1],  // Dark Green
  [0, 0, 0.5, 1],  // Dark Blue
  [0, 0.5, 0.5, 1],// Teal
  [0.5, 0, 0.5, 1],// Purple
  [0.5, 0.5, 0, 1],// Olive
  [1, 0.5, 0, 1],  // Orange
  [1, 0, 0.5, 1],  // Pink
  [0.5, 1, 0, 1],  // Lime
  [0, 1, 0.5, 1],  // Spring Green
  [0.5, 0.5, 0.5, 1],// Grey
  [0.5, 1, 0.5, 1],// Mint
  [1, 0.5, 0.5, 1],// Salmon
  [1, 1, 0.5, 1]   // Cream
]
let dodecahedronGeometry

function setup() {
  createCanvas(600, 400, WEBGL)
  colorMode(RGB, 1)
  strokeWeight(2)
  stroke('white')
  dodecahedronGeometry = platonicGeometry(dodecahedron, 80, true, colors)
}

function draw() {
  background(0)
  orbitControl()

  push()
  rotateX(frameCount * 0.01)
  rotateY(frameCount * 0.01)
  rotateZ(frameCount * 0.01)
  model(dodecahedronGeometry)
  pop()

  push()
  translate(-width / 4, -height / 4, 0)
  rotateY(frameCount * 0.01)
  fill('DarkTurquoise')
  tetrahedron()
  pop()

  push()
  translate(width / 4, -height / 4, 0)
  rotateZ(frameCount * 0.01)
  hexahedron(colors, true)
  pop()

  push()
  translate(-width / 4, height / 4, 0)
  rotateX(frameCount * 0.01)
  octahedron(colors, 120)
  pop()

  push()
  translate(width / 4, height / 4, 0)
  rotateY(frameCount * 0.01)
  icosahedron(colors, 80)
  pop()
}

Immediate Mode

Immediate mode is a graphics rendering technique where each frame is redrawn from scratch. In p5.js, this is implemented using functions like beginShape and endShape. All Platonic solids in the p5.platonic library, such as tetrahedron, hexahedron (or cube), octahedron, dodecahedron and icosahedron, are implemented in this mode.

The following code snippet demonstrates how various Platonic solids are drawn in immediate mode:

function draw() {
  // ...
  // tetrahedron
  push()
  translate(-width / 4, -height / 4, 0)
  rotateY(frameCount * 0.01)
  fill('DarkTurquoise')
  tetrahedron()
  pop()
  // hexahedron may also be called as cube
  push()
  translate(width / 4, -height / 4, 0)
  rotateZ(frameCount * 0.01)
  hexahedron(colors, true)
  pop()
  // octahedron
  push()
  translate(-width / 4, height / 4, 0)
  rotateX(frameCount * 0.01)
  octahedron(colors, 120)
  pop()
  // icosahedron
  push()
  translate(width / 4, height / 4, 0)
  rotateY(frameCount * 0.01)
  icosahedron(colors, 80)
  pop()
}

Retained Mode

Retained mode is a graphics rendering technique where graphical objects are stored and managed, reducing the need to redraw them every frame. In p5.js, retained mode can be implemented using 3D primitives and the beginGeometry function.

The following code snippet demonstrates how a dodecahedron is rendered in retained mode:

let dodecahedronGeometry

function setup() {
  // ...
  strokeWeight(2)
  stroke('white')
  // pass dodecahedron drawing function followed by the params used to render it
  dodecahedronGeometry = platonicGeometry(dodecahedron, 80, true, colors)
}

function draw() {
  // ...
  push()
  rotateX(frameCount * 0.01)
  rotateY(frameCount * 0.01)
  rotateZ(frameCount * 0.01)
  // render dodecahedronGeometry using model
  model(dodecahedronGeometry)
  pop()
  // ...
}

The platonicGeometry function in the p5.platonic library is used to create and store the geometry of a Platonic solid for rendering in retained mode. This function takes the solid’s drawing function and parameters as arguments, making it easy to manage and display complex shapes efficiently.

Coloring

Platonic solids may be colored in different ways. The boolean fuse parameter in the function calls specifies whether to blend colors along the polygons’ faces.

const colors = [
  [1, 0, 0, 1],      // Red
  [0, 1, 0, 1],      // Green
  [0, 0, 1, 1],      // Blue
  [0, 1, 1, 1],      // Cyan
  [1, 0, 1, 1],      // Magenta
  [1, 1, 0, 1],      // Yellow
  [0.5, 0, 0, 1],    // Dark Red
  [0, 0.5, 0, 1],    // Dark Green
  [0, 0, 0.5, 1],    // Dark Blue
  [0, 0.5, 0.5, 1],  // Teal
  [0.5, 0, 0.5, 1],  // Purple
  [0.5, 0.5, 0, 1],  // Olive
  [1, 0.5, 0, 1],    // Orange
  [1, 0, 0.5, 1],    // Pink
  [0.5, 1, 0, 1],    // Lime
  [0, 1, 0.5, 1],    // Spring Green
  [0.5, 0.5, 0.5, 1],// Grey
  [0.5, 1, 0.5, 1],  // Mint
  [1, 0.5, 0.5, 1],  // Salmon
  [1, 1, 0.5, 1]     // Cream
]