Introduction to 3D Modeling. Section 3. First Projects
3 First Projects
3.1 Aquarium stand
Objectives:
- Move objects using 3D vectors.
- Display differently colored objects in one scene.
- Merge multiple objects into a new solid object.
You just bought a new aquarium and need to build a stand for it. The stand that you have in mind is shown in Fig. 47.
The dimensions of the aquarium are 70 cm, 40 cm, and 50 cm. Therefore, the outer horizontal dimensions of the stand will be 70 cm and 40 cm. The stand will be made of 1 × 1 inch bars (1 inch = 2.54 cm), and including a half-inch thick wooden plate on top its height should be 60 cm. For stability reasons, the stand should be reinforced with horizontal bars located 10 cm above ground. Ready?
Design:
To begin with, create variables for all measures and dimensions. Doing this at the
beginning of every new project is a good habit – it allows you to easily tweak the design
later.
height = 60 # Height of stands including wood.
height_r = 10 # Height of reinforcements.
xdim = 70 # Width of the aquarium.
ydim = 40 # Depth of the aquarium.
zdim = 50 # Height of the aquarium.
Notice that the hash symbol ’#’ introduces a comment. This is another Python thing – all text
after this symbol till the end of line is ignored by the interpreter.
The first leg of the stand is defined using the BOX command:
Next we need to create the three other legs. For this we need to introduce the MOVE
command:
Minding the thickness of the bars, the remaining three legs of the satnd are created
via
MOVE(l2, xdim - e, 0, 0)
l3 = COPY(l1)
MOVE(l3, 0, ydim - e, 0)
l4 = COPY(l1)
MOVE(l4, xdim - e, ydim - e, 0, 0)
The partial design is displayed in steel color as follows:
Fig. 48 shows how our design looks at the moment.
Often there are multiple ways that lead to the same design. Here, the four legs together
form a Cartesian product geometry: Two intervals in the x-direction times two
intervals in the y-direction times one interval in the z-direction. So, the same could be
done using the GRID and PRODUCT commands that were introduced in Subsection
2.25:
g2 = GRID(e, -depth - 2*e, e)
g12 = PRODUCT(g1, g2)
g3 = GRID(height - 0.5 * e)
legs = PRODUCT(g12, g3)
Next let’s take care of the horizontal bars. First the top ring:
t1 = BOX(xdim, e, e)
MOVE(t1, 0, 0, height - 0.5*e - e)
t2 = COPY(t1)
MOVE(t2, 0, ydim - e, 0)
t3 = BOX(e, ydim, e)
MOVE(t3, 0, 0, height - 0.5*e - e)
t4 = COPY(t3)
MOVE(t4, xdim - e, 0, 0)
# Display the frame:
SHOW(l1, l2, l3, l4, t1, t2, t3, t4)
The design after this step is shown in Fig. 49.
The reinforcement ring is obtained by lowering the top ring by height - height_r:
b1 = COPY(t3)
MOVE(b1, 0, 0, -(height - height_r))
b2 = COPY(t4)
MOVE(b2, 0, 0, -(height - height_r))
b3 = COPY(t1)
MOVE(b3, 0, 0.5*(ydim - e), -(height - height_r))
Finally, we display the frame:
SHOW(l1, l2, l3, l4, t1, t2, t3, t4, b1, b2, b3)
The design after this step is shown in Fig. 50.
After checking visually that all parts of the frame are correct, let us create a new solid
object for the frame by merging all 12 bars together. For this, we use the command
UNION.
In our case we create the new object for the frame as follows:
frame = U(l1, l2, l3, l4, t1, t2, t3, t4, b1, b2, b3)
As every newly created object, frame has the default steel color. Last, the top plate is a
BOX(xdim, ydim, 0.5*e) that is lifted up by height - 0.5*e:
top = BOX(xdim, ydim, 0.5*e)
MOVE(top, 0, 0, height - 0.5*e)
# Display frame and top plate together:
wood = [102, 51, 0]
COLOR(top, wood)
SHOW(frame, top)
The final design is shown in Fig. 51.
3.2 Water molecule
Objectives: Rotate 3D objects.
Your task is to create a ball-and-stick model of the molecule of water (H2O) shown in Fig. 52.
The only physical parameter that you have to preserve is the angle between the two hydrogen atoms which is 104.45 degrees. All other dimensions of your model should be variable.
Design:
To begin with, define colors for the molecules and the bonds:
Color_H = [0, 200, 200]
Color_bond = [200, 200, 200]
Next create variables for all parameters of the model:
R_H = 0.7 # Radius of the H atom.
R_bond = 0.1 # Radius of the sticks.
L_bond = 0.2 # Distance of O and H atoms.
Angle = 104.45 # Angle between H atoms (in degrees).
For practical reasons, let us redefine the length of the bond to span the distance between the
centers of the O and H atoms:
Now create the atom of oxygen and one atom of hydrogen:
Sphere_H = SPHERE(R_H)
If we displayed them together right now, then the H atom would not be visible since it would
be inside the O atom. So, let us move the H atom by the length of the bond in the direction of
the x-axis:
The current state of our model is shown in Fig. 53.
Next create a cylinder (stick) representing the bond:
After this command, the situation is depicted in Fig. 54.
Of course this is not what we want – the bond need to be connecting the O and H atoms.
Hence we will need to rotate the cylinder by 90 degrees about the y-axis. This is done with
the ROTATE command.
Hence the following command will rotate the bond to the correct position:
The updated geometry is shown in Fig. 55.
Last, rotate both the cylinder and the hydrogen atom, assign colors, and diplay:
ROTATE(Bond_2, Angle, 3)
Sphere_H_2 = COPY(Sphere_H)
ROTATE(Sphere_H_2, Angle, 3)
COLOR(Sphere_O, Color_O)
COLOR(Sphere_H, Color_H)
COLOR(Sphere_H_2, Color_H)
COLOR(Bond, Color_bond)
COLOR(Bond_2, Color_bond)
SHOW(Sphere_O, Sphere_H, Bond, Sphere_H_2, Bond_2)
The final geometry of the molecule is displayed in Fig. 56.
3.3 Coffee table
Objectives:
- Scale objects.
- Subtract objects from each other.
Your third task is to create a model of an oval coffee table that is shown in Fig. 57.
This is a real coffee table that is sold by the Fong Brothers Company in Los Angeles. The width, depth and height of the table are 48, 24 and 18 inches, respectively.
Design:
As usual we first introduce variables for all design parameters:
d = 24.0 # Depth.
h = 18.0 # Height.
top_outer = 4.5 # Thickness of top (outer view).
top_inner = 1.0 # Thickness of top (inner view).
leg_width = 7.0 # Width of legs.
leg_depth = 2.0 # Depth of legs.
The departure point for the design will be a cylinder of radius d/2 and height
h:
which is shown in Fig. 58.
In the next step, the cylinder will be transformed to an oval cylinder via the SCALE
command.
We will be scaling an object body by w / d in the x-direction:
The result after scaling is shown in Fig. 59.
Now we need to cut off four corners in order to define the width of the legs. This is done via
the command DIFFERENCE.
The object to be subtracted from the oval cylinder will be constructed by subtracting two
boxes from a larger box:
MOVE(b, -w/2.0, -d/2.0, 0)
b_cut1 = COPY(b)
SCALE(b_cut1, leg_width / w, 1.0, 1.0)
b_cut2 = COPY(b)
SCALE(b_cut2, 1.0, leg_width / d, 1.0)
b = DIFF(b, b_cut1, b_cut2)
The object b is displayed in Fig. 60.
Next we subtract b from body,
and display the result in Fig. 61.
Note that we preserved the original oval cylinder in the variable body. Now we will scale it
down as needed in order to remove the interior part of the table:
SCALE(body, (w - 2*leg_depth) / w, \
(d - 2*leg_depth) / d, (h - top_inner) / h)
# Display it along with the object ~table~:
SHOW(table, body)
The situation is depicted in Fig. 62.
As the last step, we remove the object body from the object table:
The final design in shown in Fig. 63.
3.4 Geometry labs
Objectives:
- Intersect 3D objects with planes represented by thin 3D solids.
- Experiment with conic sections.
PLaSM makes it possible to intersect objects via the INTERSECTION command.
In this subsection we will be using cones and planes to construct conic sections. With what you learn here, you will be able to cut any other 3D objects.
Let us begin with creating a cone of radius r = 1 and height h = 2:
h = 2.0
cone = CONE(r, h, 128)
COLOR(cone, GOLD)
SHOW(cone)
The parameters r and h are variables that you can change them easily if needed. The optional third parameter 128 in the cone’s definition is used to make the surface smoother-looking (recall from Subsection 2.18 that the default value is 64). The cone is shown in Fig. 64.
Constructing a circle
A circle is obtained by cutting the cone with a plane that is normal (perpendicular) to its axis.
Hence, let’s add a plane, represented by a square of size s = 3. The square will be
created using the SQUARE3D command and displayed along with the cone in steel
color:
plane = SQUARE3D(s)
COLOR(cone, GOLD)
SHOW(cone, plane)
The two objects are shown together in Fig. 65.
We need to move the square in the xy-plane so that the z-axis passes through its center, and at
the same time to lift it by e in the z-direction. Hence the 3D translation vector is (-s/2.0,
-s/2.0, e):
MOVE(plane, -s/2.0, -s/2.0, e)
COLOR(cone, GOLD)
SHOW(cone, plane)
The situation is depicted in Fig. 66.
Now we can create the conic section:
COLOR(circle, GOLD)
SHOW(circle)
The intersection is shown in Fig. 67.
We can also visualize the intersection with the rest of the plane. For this, we subtract the cone
from the plane, and view it together with the circle:
COLOR(circle, GOLD)
SHOW(circle, pierced_plane)
The ensemble is shown in Fig. 68.
Let’s play some more! We can cut off the upper part of the cone, to obtain a truncated cone.
This can be done using the same sequence of operations as above, only the plane will be
replaced by a half-space, represented by a cube. Let us display the two objects together
first:
cube = CUBE(s)
e = 1.0
MOVE(cube, -s/2.0, -s/2.0, e)
COLOR(cone, GOLD)
SHOW(cone, cube)
The two objects are displayed in Fig. 69.
Next let us remove the half-space from the cone:
COLOR(tcone, GOLD)
SHOW(tcone)
The result is shown in Fig. 70.
The upper part of the cone is an intersection of the cone with the cube:
COLOR(tcone, GOLD)
SHOW(tcone, tip)
The truncated cone in gold color, along with the upper part in steel color, are shown in Fig. 71.
The math behind the scenes
The equation for the cone of radius r and height h shown in Fig. 64 is





Constructing an ellipse
An ellipse is obtained by intersecting the cone with a plane that is not normal to the cone
axis, but that is also not steeper that the slope of the cone. For this example we will use the
cone from Fig. 64, but we will make it three times bigger (both r and h) and move it by -4
units on the z-axis so that its apex is at z = 2 as before:
h = 6.0
cone = CONE(r, h, 128)
MOVE(cone, 0, 0, -4)
Next we add a plane represented by a square of size s = 7, move it so that its center lies on
the z-axis, and rotate by 45 degrees about the y-axis:
plane = SQUARE3D(s)
MOVE(plane, -s/2.0, -s/2.0, 0)
ROTATE(plane, 45, 2)
COLOR(cone, GOLD)
SHOW(cone, plane)
The situation is shown in Fig. 72.
With both objects in place, we can create their elliptic intersection. It will be displayed in gold
color along with the rest of the plane in steel color:
pierced_place = DIFF(plane, cone)
COLOR(ellipse, GOLD)
SHOW(ellipse, pierced_plane)
The result is shown in Fig. 73.
Finally, if we like to, we can remove the upper part of the cone in the same way we did before – replacing the plane with a cube, translating and rotating the cube in the same way as the plane, and subtracting it from the cone. The result is shown in Fig. 74.
Constructing a parabola
Parabola is obtained when a cone is intersected with a plane that has the same slope as the
surface of the cone, and that does not pass through its apex. We will stay with the same cone
as before, just the plane will be enlarged:
plane = SQUARE3D(s)
MOVE(plane, -s/2.0, -s/2.0, 0)
To calculate the slope of the plane, we import the arctan function from Numpy, Python’s
numerical computation library:
alpha = arctan(h/r) * 180 / PI
Next we rotate the plane by angle alpha about the y-axis:
COLOR(cone, GOLD)
SHOW(cone, plane)
Note that this rotation is in radians, not in degrees – this is because the function arctan returns angles in radians. The two objects are shown in Fig. 75.
Now we can calculate the intersection of the plane with the cone, and display it along with
the rest of the plane:
pierced_plane = DIFF(plane, parabola)
COLOR(parabola, GOLD)
SHOW(parabola, pierced_plane)
The parabola is shown in Fig. 76.
Note that the parabola is truncated because both the cone and the plane are represented by objects of finite size. Ideally, if both of them were infinite, also the parabola would extend to infinity.
Last we can replace the plane with a cube, and remove the upper part of the cone:
cube = CUBE(s)
MOVE(cube, -s/2.0, -s/2.0, 0)
ROTATE(cube, alpha, 2)
tcone = DIFF(cone, cube)
COLOR(tcone, GOLD)
SHOW(tcone)
The result is shown in Fig. 77.
Constructing a hyperbola
Hyperbola is obtained by intersecting the cone with a plane that is either parallel to the axis of the cone, or its slope is steeper than the slope of the surface of the cone.
Hyperbolas have two arms, therefore we will use the full mathematical form of the cone
which we did not need until now. It consists of two "usual" cones that share the same axis
and touch at the apex. They are constructed as follows:
h = 6.0
cone1 = CONE(r, h, 128)
MOVE(cone1, 0, 0, -6)
cone2 = COPY(cone1)
ROTATE(cone2, 180, 1)
cone = UNION(cone1, cone2)
The double cone is shown in Fig. 78.
Next let us create the plane. We will create a sufficiently large square using the SQUARE3D
command, and move it so that its center lies on the z-axis:
plane = SQUARE3D(s)
MOVE(plane, -s/2.0, -s/2.0, 0)
The plane is rotated by angle alpha about the y-axis. This angle does not have to be 90
degrees as in our example below. But the slope of the cone must not become less than
or equal to the slope of the cone – otherwise we would end up with an ellipse or
parabola:
ROTATE(plane, alpha, 2)
The plane should not pass through the apex:
MOVE(plane, D, 0, 0)
Let’s display the two objects together:
SHOW(cone, plane)
The double cone and the plane are shown in Fig. 79.
Now we can already create the hyperbolic intersection:
pierced_plane = DIFF(plane, hyperbola)
COLOR(hyperbola, GOLD)
SHOW(hyperbola, pierced_plane)
The output is shown in Fig. 80.
Finally, as we did in the previous examples, let us replace the plane with a cube, and expose
the hyperbolic cut by removing part of the double cone:
# and rotate it in the same way, and subtract
# from the cone:
s = 12.0
cube = CUBE(s)
MOVE(cube, -s/2.0, -s/2.0, 0)
# Rotate the cube by 90 degrees
# about the y-axis.
alpha = 90
ROTATE(cube, alpha, 2)
D = -0.5
MOVE(cube, D, 0, 0)
# Subtract the cube from the cone:
tcone = DIFF(cone, cube)
COLOR(tcone, GOLD)
SHOW(tcone)
What remains of the double cone is shown in Fig. 81.
3.5 3D puzzle
Objectives: Intersect 3D objects.
Task
Construct a 3D object that can fit exactly into all three holes in the wooden piece shown in Fig. 82!
The three holes have the following parameters:
- 2 × 2 inch square,
- symmetric triangle of base 2 inches and height 2 inches,
- circle of radius 1.0 inches.
Impossible? Turn the page.
Solution
Here is the script that creates the object:
c = CUBE(2.0)
# Move the cube so that its center lies at (0, 0, 0):
MOVE(c, -1, -1, -1)
# Next create a cylinder with radius 1 and height 2:
cyl = CYL(1, 2)
# Move also the cylinder so that its center lies at (0, 0, 0):
MOVE(cyl, 0, 0, -1)
# Create a prism via convex hull:
p = CHULL([1, -1, -1], [1, 0, 1], [1, 1, -1], \
[-1, -1, -1], [-1, 0, 1], [-1, 1, -1])
# Calculate the intersection of the three objects:
out = INTERSECTION(c, cyl, p)