3D modeling 3d printing open source

Twisted Vase in OpenSCAD

In this blog post I’ll continue a previous post about polyhedron in OpenSCAD. Now we create something more exiting, a twisted vase.

Earlier I explained how to use polyhedron to create a regular cylinder in OpenSCAD. Not very exciting but this method is very useful to create much more complex objects. As long as we’re able to find the right function we can create the object with this method.

As an example I’ll explain how to create a twisted or spiraled vase. You’ve probably seen them on Printables or Thingiverse and they exist in many varieties. In this post we first create one starting with a simple triangle and then other regular polygons.

Three examples of twisted vases created with this code. On the left in the front a twisted triangle (in blue), on the left in the back a twisted octagon and on the right a twisted regular polygon that consists if 36 edges or vertices.

The code in OpenSCAD

For that we use the same method as in the previous post about polyhedron: first we calculate the points of the vase and then we define the faces.

But first consider a regular triangular plane and extrude that in the height (z-direction). Now suppose we twist this triangular plane while extruding and to make it even more complex increase or decrease the size of the plane while extruding. How would that function look like. In this example I’ll use a sinusoid or sine wave function. A sinusoid is the representation of any mathematical sine (or cosine) function that is smooth periodic in nature. Here is the general formula.

f(z) = a + b * sin(c(z)+d);

By substituting values for a, b, c and d we get very different sine functions. In this example I’ll use:

f(z) = 2 + 2 * sin(z)

Before we’re able to calculate our points we need the following variables.

height = 160; //total height of the vase
radius = 30; //radius of the base
step = 1; //steps in z-direction. The lower the more faces
twist = 1.2; //increase to have more twist

The height is in the z-direction, the radius is the radius of the initial circle when all the three vertices of the regular triangle lie on that circle. Step is the step size in the z-direction and twist is the amount of twist that the vase gets. The higher is more twist. Then we need three angles to calculate the exact point of each triangle.

sh3 = [0,120,240]; //triangle

Now we can calculate all the points with the code below

p = [for (z = [0:step:height], angle = sh3) [radius*cos(angle+twist*z)*f(z),radius*sin(angle+twist*z)*f(z),z]];

It’s a nested loop where in the inner loop the angle is varied according to the values of sh3 and in the outer loop the value of z is varied. Hopefully you’ll see similarities the code below that we used in the earlier post to calculate the basic cylinder: [cos(angle) * r, sin(angle) * r, z].

The first two values in the inner square brackets define the position of a point in the xy-plane. Notice that compared with the our earlier formula we multiply x and y values within the brackets with our sine function f(z). We also changed the parameter of the sine and cosine by adding the twist variable and multiply in with z.

Lastly, like we did with the cylinder, we have to create the faces. The code is similar to the code we used with the cylinder but with some essential changes.

module shape(p,m,n) {

    fcs = [for (j = [1:m], i = [0:n-2])[(n*j)+i,(n*j)+1+i,(n*(j-1))+i+1,(n*(j-1))+i]];

    top = [for (i = [n*m:(n*m)+n-1]) i]; //connect points to create the top face

    bottom = [for (i = [0:n-1]) i]; //connect points to create the bottom

    stitches = [for (j = [0:m-1]) [j*n,((j+1)*n)-1,(((j+2)*n)-1),(j+1)*n]]; //connect points between the first and the last face per row

    //now connect all
    //reverse is used to reverse normal of top face
    fcsc = concat([bottom],fcs,stitches,[reverse(top)]); //concatenate the bottom, body and top

    color("teal") polyhedron(points=p, faces=fcsc);

The module shape takes as parameters a list of points (p) and the rows and columns of a matrix (m * n). The matrix is calculated as follows.

m = floor(height/step); //numbers of rows of the matrix
n = len(sh3); //number of columns in the matrix
Image from OpenSCAD of a twisted regular triangle. The twist variable has a value of 0.7.

Correcting the normals

Getting back to the shape module you’ll may be noticing that it differs from the cylinder version. One difference is can be found in the fcs list variable. When we watch closely we’ll notice that the for-loop for i has been reversed. This has been done to avoid errors in the stl file. As it turns out the normals of each face from fcs were pointing inwards into the object. OpenSCAD doesn’t complain about it but other programs like Prusaslicer do (see image below).

Prusaslicer auto-repaired 2240 errors in this stl file that was exported from OpenSCAD. These errors are all inward pointing normals that need to be reversed to point outward.

The top also prompted errors and this can be solved by reversing the order of the top list. To do this we need another function called reverse. It reverses the order of the list that is provided as a parameter to it.

function reverse(lt) = [for(i = len(lt) - 1; i > -1; i = i - 1) lt[i]];

Finishing the code

And this leaves only the last part of the code which is simply


The code that I’ll include with this post is a little more complicated. I added a Customizer to change some of the variables and I added a different sine function (g(z)) that provides a very different vase. I also added the angles for a pentagon, hexagon and octagon (sh5, sh6 and sh8) if you want to change the regular triangle for another regular polygon. If you do make sure to change sh3 on two places in the code: the value for the variable n and in the formula to calculate all points (p).

Screenshot of OpenSCAD where triangle is replaced by an octagon. Notice how the formula for p is changed accordingly.

The code can be found in this link:

Leave a Reply

Your email address will not be published. Required fields are marked *

Discover more from HomeHack

Subscribe now to keep reading and get access to the full archive.

Continue reading