Introduction to 3D Modeling. Section 6. Advanced Projects
6 Advanced Projects
Objectives:
- Practice your scripting skills.
- Create more complex designs.
- Learn to decompose complicated designs into smaller steps.
6.1 Carrousel
Let us start with something simple - a carrousel created by translating anf rotating a few thin
toruses:
r1 = 0.95
r2 = 1.0
r_mid = 0.5 * (r1 + r2)
h = 0.5 * (r2 - r1)
# Create two master toruses:
t1 = TORUS(r1, r2)
t2 = TORUS(r_mid*cos(PI/6) - h, r_mid*cos(PI/6) + h)
# Create two smaller horizontal toruses:
elevation = r_mid * sin(PI/6)
MOVE(t2, 0, 0, elevation)
t3 = COPY(t2)
MOVE(t3, 0, 0, -2 * elevation)
# Create six vertical toruses:
t4 = COPY(t1)
ROTATE(t4, 90, 1)
t5 = COPY(t4)
ROTATE(t5, 30, 3)
t6 = COPY(t5)
ROTATE(t6, 30, 3)
t7 = COPY(t6)
ROTATE(t7, 30, 3)
t8 = COPY(t7)
ROTATE(t8, 30, 3)
t9 = COPY(t8)
ROTATE(t9, 30, 3)
# Assign colors:
COLOR(t1, RED)
COLOR(t2, GREEN)
COLOR(t3, BLUE)
COLOR(t4, YELLOW)
COLOR(t5, YELLOW)
COLOR(t6, YELLOW)
COLOR(t7, YELLOW)
COLOR(t8, YELLOW)
COLOR(t9, YELLOW)
# Display everything:
SHOW(t1, t2, t3, t4, t5, t6, t7, t8, t9)
The outpur is shown in Fig. 95.
6.2 Temple
In this subsection we will build the temple that we have seen in Subsection 1.3:
Let us begin with defining variables for the radius and height of the columns:
r = 1.0
h = 12.0
Next let’s create one column:
basis = BOX(2*r*1.2, 2*r*1.2, h/12.0)
trunk = CYLINDER(r, (10.0/12.0)*h)
capital = COPY(basis)
beam = COPY(capital)
SCALE(beam, 3, 1, 1)
column = TOP(TOP(TOP(basis, trunk), capital), beam)
column = WELD(column)
The column is displayed in Fig. 97.
In the next step we will form a column row by placing n = 4 columns next to each other.
n = 4
# Column row:
colrow = []
for i in range(n):
newcol = COPY(column)
MOVE(newcol, i * 6*r*1.2, 0, 0)
colrow.append(newcol)
The column row is displayed in Fig. 98.
Now we can create the gable and position it on top of the column row:
triangle = TRIANGLE([0, 0], [n*3*2*r*1.2, 0], [n*3*r*1.2, h/2])
prism = PRISM(triangle, r*1.2)
gable = COPY(prism)
ROTATE(gable, 90, 1)
# Portal:
MOVE(gable, -2*r*1.2, 1.5*r*1.2, h/12.0 + (10.0/12.0)*h
+ 2*h/12.0)
portal = STRUCT(colrow, gable)
The portal is shown in Fig. 99.
Append m = 4 inner column rows, and then once more the portal at the end:
m = 4
# Temple base as a list:
temple_base = [portal]
for i in range(1, m+1):
newcolrow = COPY(colrow)
MOVE(newcolrow, 0, 6*i, 0)
temple_base.append(newcolrow)
newportal = COPY(portal)
MOVE(newportal, 0, 6*(m+1), 0)
temple_base.append(newportal)
The temple base is displayed in Fig. 100.
In the next step we create the foundation plate which is just a box of dimensions 32, 40 and 1
m.
ground = BOX(32, 40, 1)
MOVE(ground, -4.6, -3.8, -0.9)
The last component we need are the secondary roof beams. They are created using the GRID
and PRODUCT command that we learned in Subsection 2.25:
x_intervals = GRID(14 * [0.6, -1.2])
y_intervals = GRID([-0.7] + 5 * [-1, 5])
z_interval = GRID([-13, 0.6])
secondary_beams = POWER(POWER(x_intervals, y_intervals), z_interval)
The secondary roof beams are displayed in Fig. 101.
After putting everything together,
out = UNION(temple_base, secondary_beams, ground)
COLOR(out, WHITE)
we obtain the model from Fig. 96.
6.3 Sierpinski fractals
Sierpinski fractals are famous fractal sets that saw the light of the world around 1915 before the Mandelbrot’s and Julia’s fractals appeared. The Sierpinski triangle and carpet are shown in Fig. 102.
Both these fractals have their 3D versions, called the Sierpinski tetrahedron and Menger sponge,
respectively. They are easy to find in the Internet.
We will only discuss the triangle here since the other shapes work in a similar way. The triangle fractal is constructed by recursively subtracting smaller equilateral triangles from an original equilateral triangle, as shown in Fig. 103.
This process is infinite in mathematical theory, while in reality we only can perform a finite number of steps. Moreover, the procedure that we just described is good from the mathematical point of view, while it is not the best from the point of view of computer implementation. Why is this?
We learned in Subsection 4.5 that it is not a good idea to perform Boolean operations between complex objects with many faces. This leads to a large number of operations and the computation takes a long time. Subtracting a triangle from a fractal that already has many holes is exactly what we should avoid.
Fortunately, there is an elegant way around this which does not use any Boolean
operations at all. We start by creating an object st (Sierpinski Triangle) that will be just a
single equilateral triangle (0, 0), (1, 0), (1∕2,).
Then we add to the object st two identical objects that are obtained via translating st to
"east" by the 3D vector (1, 0, 0) and to "north-east" by the 3D vector (1∕2,, 0).
Of course we do not want our fractal to grow infinitely, so we rescale the new object st (that comprises three triangles now) by 1∕2 in the x and y directions.
Now it is sufficient to apply to the new object st the procedure that we described above –
adding two identical copies and rescale – as many times as we want. This will create the
Sierpinski Triangle fractal. The program looks as follows:
# Do not go much higher than 6, number of
# operations grows exponentially.
level = 6
# Height of equilateral triangle with unit base:
from numpy import sqrt
h = sqrt(0.75)
# Initial object ’st’ is a triangle.
st = TRIANGLE([0, 0], [1, 0], [0.5, h])
# Add two identical copies of ’st’
# and rescale back to (0, 1):
for i in range(level - 1):
st1 = COPY(st)
MOVE(st1, 0.5, h)
st2 = COPY(st)
MOVE(st2, 1.0, 0.0)
st = UNION(st, st1, st2)
SCALE(st, 0.5, 0.5)
# Display in blue color:
COLOR(st, BLUE)
SHOW(st)
The resulting geometry for k = 6 levels is shown in Fig. 107. It is easy to calculate that with k levels, the geometry consists of 3k-1 triangles. This means exponential growth – with k = 6 there are 243 triangles, with k = 7 there are 729, with k = 8 there are 2187 etc. Therefore, do not use k much higher than 6.
6.4 3D gear
In this section we will build the 3D gear that we have seen in Subsection 1.3. In the first step
let us define a color along with parameters and measures of one tooth, and create one tooth
as a convex hull.
N = 18
# Width of the tooth:
x0 = 8
dx1 = 1
dx2 = 2.5
# Height of the tooth:
y0 = 30
dy1 = 0.5
dy2 = 4
# Depth of the tooth:
z1 = 5
z2 = 8
# (Do not change these)
base_rin = 22
base_rout = 30
base_h = 32
# Vertices:
pts_base = [[0, 0, 0], [x0, 0, 0], [x0, y0, 0], [0, y0, 0]]
pts_mid = [[dx1, dy1, z1], [x0 - dx1, dy1, z1], [x0 - dx1, y0 - dy1, z1],
[dx1, y0 - dy1, z1]]
pts_top = [[dx2, dy2, z2], [x0 - dx2, dy2, z2], [x0 - dx2, y0 - dy2, z2],
[dx2, y0 - dy2, z2]]
# Merging the point lists:
pts = pts_base + pts_mid + pts_top
# Toothe is a convexhull of the points:
t = CHULL(pts)
The result is displayed in Fig. 108.
Next we create all teeth by translating and replicating the first one:
ROTATE(t, 90, 1)
ROTATE(t, 90, 3)
MOVE(t, base_rout - 0.3, -x0/2., 0)
# Calculate the angle of rotation:
angle = 360./N
# Create all teeth:
gear = []
for i in range(N):
ROTATE(t, i * angle, 3)
gear.append(t)
The result is displayed in Fig. 109.
In the next step we create the base of the gear:
base = TUBE(base_rin, base_rout, base_h, 128)
dz = (base_h - y0)/2.
MOVE(base, 0, 0, -dz)
The result is displayed in Fig. 110.
In order to construct the top ring, we use a regular and a truncated cone.
tc1 = TCONE(base_rout, base_rout - 1, 1)
MOVE(tc1, 0, 0, base_h)
# Regular cone:
cone = CONE(base_rout, base_rout)
ROTATE(cone, 180, 2)
MOVE(cone, 0, 0, 40)
# Assign colors:
COLOR(cone, RED)
COLOR(tc1, BRASS)
# Display the objects together:
SHOW(tc1, cone)
The result is displayed in Fig. 111.
The hole is drilled by subtracting the regular cone from the truncated one.
tc = DIFF(tc1, cone)
The result is displayed in Fig. 112.
Next the ring and the teeth are attached to the base.
base = TOP(base, tc)
# Attach teeth:
gear.append(base)
The result is displayed in Fig. 113.
Last we need to build the inner part of the gear. First, create a tube and three boxes:
inner_dr = 3
# Create inner tube:
inner = TUBE(base_rin - inner_dr, base_rin, base_h * 0.75)
MOVE(inner, 0, 0, base_h * 0.25)
# Define three boxes:
b1 = BOX(50, 10, 35)
MOVE(b1, -25, -5, 0)
b2 = COPY(b1)
ROTATE(b2, 60, 3)
b3 = COPY(b2)
ROTATE(b3, 60, 3)
str = [b1, b2, b3]
# Assign colors:
COLOR(inner, BRASS)
COLOR(str, RED)
# Display the objects together:
SHOW(inner, str)
The result is displayed in Fig. 114.
Next we subtract the three boxes from the tube.
inner = DIFF(inner, b1, b2, b3)
The result is displayed in Fig. 115.
Then we subtract the original cone from the inner part.
inner = DIFF(inner, cone)
# Translate the inner part:
MOVE(inner, 0, 0, -dz)
# Assign colors:
COLOR(inner, BRASS)
COLOR(cone, RED)
# Display the objects together:
SHOW(inner, cone)
The result is displayed in Figs. 116 and 117.
Finally we attach the inner part to the gear:
gear.append(inner)
# Display the gear:
COLOR(gear, BRASS)
SHOW(gear)
The final geometry is shown in Fig. 118.