Tutorial: A Spinning 3D Cube
Your first 3D program: a lit cube that spins, then the same cube with a floor, outlined edges, and a camera you can turn by dragging. For the pieces in more depth, see 3D scenes.
1. The cube
# the renderer draws on the preview
renderer = THREE.WebGLRenderer(canvas=canvas, antialias=True)
renderer.setPixelRatio(pixel_ratio)
renderer.setSize(width, height, False)
# the world, and where we look at it from
scene = THREE.Scene()
scene.background = THREE.Color("#14141c")
camera = THREE.PerspectiveCamera(60, width / height, 0.1, 100)
camera.position.z = 3
# a cube: a box shape with a material that reacts to light
cube = THREE.Mesh(
THREE.BoxGeometry(1, 1, 1),
THREE.MeshStandardMaterial(color="dodgerblue"),
)
scene.add(cube)
# light: a soft fill everywhere, and one bright light from the top right
scene.add(THREE.AmbientLight("white", 0.5))
light = THREE.DirectionalLight("white", 2.5)
light.position.set(2, 3, 4)
scene.add(light)
def draw():
cube.rotation.x += 0.01
cube.rotation.y += 0.015
renderer.render(scene, camera)
Reading it from the top:
- The renderer draws the 3D picture on the preview. These three lines start every 3D program; copy them as they are.
- The scene is the world. Its background is a dark grey.
- The camera is your eye.
60is how wide it sees, in degrees;width / heightis the shape of the preview; it sees things between 0.1 and 100 units away. It sits 3 units back from the middle (position.z = 3), looking at the middle. - The cube is a mesh: a shape (
BoxGeometry, 1 unit each way) plus a material (MeshStandardMaterial, blue). - The lights: without light, a standard material is black. The ambient light lights everything a little; the directional light shines from one direction like the sun, which is what makes the sides different shades.
draw()turns the cube a little more each frame and draws the scene.
Rotations are in radians, so 0.01 a frame at 60 frames a second is about 34 degrees a second.
2. Turn it with your finger
Add orbit controls and the camera circles the cube as you drag. A floor grid and outlined edges make the shape easier to read.
renderer = THREE.WebGLRenderer(canvas=canvas, antialias=True)
renderer.setPixelRatio(pixel_ratio)
renderer.setSize(width, height, False)
scene = THREE.Scene()
scene.background = THREE.Color("#14141c")
camera = THREE.PerspectiveCamera(60, width / height, 0.1, 100)
camera.position.set(2, 2, 3)
# drag to turn, pinch or scroll to zoom
controls = addons.OrbitControls(camera, canvas)
controls.enableDamping = True
geometry = THREE.BoxGeometry(1, 1, 1)
cube = THREE.Mesh(geometry, THREE.MeshStandardMaterial(color="dodgerblue", roughness=0.4))
cube.position.y = 0.8
scene.add(cube)
# white lines along the cube's edges, added to the cube so they turn with it
edges = THREE.LineSegments(
THREE.EdgesGeometry(geometry),
THREE.LineBasicMaterial(color="white"),
)
cube.add(edges)
scene.add(THREE.GridHelper(6, 12, "#555", "#333"))
scene.add(THREE.AmbientLight("white", 0.5))
light = THREE.DirectionalLight("white", 2.5)
light.position.set(2, 3, 4)
scene.add(light)
spinning = True
def on_key_down(key):
global spinning
if key == " ":
spinning = not spinning
def draw():
if spinning:
cube.rotation.y += 0.015
controls.update()
renderer.render(scene, camera)
addons.OrbitControls(camera, canvas)moves the camera when you drag on the preview.enableDampinglets it glide to a stop, andcontrols.update()indraw()keeps it moving.cube.add(edges)puts the lines inside the cube, so they move and turn with it.- Press space (after clicking the preview) to pause and restart the spin.
You never need to handle resizing: when the preview changes size, the picture and the camera are refitted for you.
Try this
- Swap
BoxGeometry(1, 1, 1)forTorusKnotGeometry(0.5, 0.15, 128, 16). - Make it metal:
MeshStandardMaterial(color="silver", metalness=1, roughness=0.3). - Make a row of cubes with a
forloop, each with its ownposition.xand colour, and keep them in a list to spin indraw().
Related
- 3D scenes
- Next: lighting a scene