*The post is part of a series on learning how to use manim. You can find the previous tutorial post in this series here and the overview of the entire series here.*

*Note: When extracting these scenes I’d recommend including the low quality command line argument l. These scenes can take several minutes to extract at higher qualities.*

**Important Note: These posts are based on an earlier version of manim which uses Python 2.7. The latest version of manim is using Python 3. To follow along with these posts, use Python 2.7 and the May 9, 2018 commit of manim .**

# 10.0 3D Scenes

The 3D scenes really aren’t any different than 2D scenes except you can now move the camera around using `self.move_camera()`

. Below is an example using the 2D vector field from my previous post.

class ExampleThreeD(ThreeDScene): CONFIG = { "plane_kwargs" : { "color" : RED_B }, "point_charge_loc" : 0.5*RIGHT-1.5*UP, } def construct(self): self.set_camera_position(0, -np.pi/2) plane = NumberPlane(**self.plane_kwargs) plane.main_lines.fade(.9) plane.add(plane.get_axis_labels()) self.add(plane) field2D = VGroup(*[self.calc_field2D(x*RIGHT+y*UP) for x in np.arange(-9,9,1) for y in np.arange(-5,5,1) ]) self.play(ShowCreation(field2D)) self.wait() self.move_camera(0.8*np.pi/2, -0.45*np.pi) self.begin_ambient_camera_rotation() self.wait(6) def calc_field2D(self,point): x,y = point[:2] Rx,Ry = self.point_charge_loc[:2] r = math.sqrt((x-Rx)**2 + (y-Ry)**2) efield = (point - self.point_charge_loc)/r**3 return Vector(efield).shift(point)

The differences between this code and the example from my previous post is (1) the parent class is `ThreeDScene`

rather than `Scene`

, (2) the `self.set_camera_position()`

command, (3) the `self.move_camera()`

command, and (4) the `self.begin_ambient_camera_rotation()`

command.

The `ThreeDScene()`

adds the ability to change the orientation of the camera. `set_camera_position()`

moves the camera to the specified location and orientation. The camera will abruptly jump to the given location. If we want a smooth camera transition (panning the camera) we’d use `move_camera()`

. The keyword arguments for `set_camera_position()`

are `phi`

, `theta`

, `distance`

, `center_x`

, `center_y`

, and `center_z`

. The point that the camera is pointing towards is given by `center_x`

, `center_y`

, `center_z`

. The other three arguments correspond to , , and in the figure below. Notice that the center point corresponds to the origin of the graph, with the camera located at the ‘x’, looking back towards the origin. This is why and corresponds to the normal 2D orientation with the x-axis pointing right and the y-axis pointing up on the screen. If you set we flip the screen over.

By Dmcq – Own work, CC BY-SA 3.0, Link

## 10.1 3D Vector Field

Drawing a three-dimensional vector field requires only a couple of tweaks to our original code. We will copy the code for `field2D`

and the method `calc_field2D`

to create `field3D`

and `calc_field3D`

. With `field3D`

we need to only add `for z in np.arange(-5,5,1)`

and then send the vector `x*RIGHT + y*UP + z*OUT`

to `calc_field3D`

. Next we add the z-coordinates to `calc_field3D`

. This means we don’t slice `point`

or `self.point_charge`

since we need all three components. We also need to add `(z-Rz)**2`

to the equation for `r`

.

class EFieldInThreeD(ThreeDScene): CONFIG = { "plane_kwargs" : { "color" : RED_B }, "point_charge_loc" : 0.5*RIGHT-1.5*UP, } def construct(self): self.set_camera_position(0.1, -np.pi/2) plane = NumberPlane(**self.plane_kwargs) plane.main_lines.fade(.9) plane.add(plane.get_axis_labels()) self.add(plane) field2D = VGroup(*[self.calc_field2D(x*RIGHT+y*UP) for x in np.arange(-9,9,1) for y in np.arange(-5,5,1) ]) field3D = VGroup(*[self.calc_field3D(x*RIGHT+y*UP+z*OUT) for x in np.arange(-9,9,1) for y in np.arange(-5,5,1) for z in np.arange(-5,5,1)]) self.play(ShowCreation(field3D)) self.wait() self.move_camera(0.8*np.pi/2, -0.45*np.pi) self.begin_ambient_camera_rotation() self.wait(6) def calc_field2D(self,point): x,y = point[:2] Rx,Ry = self.point_charge_loc[:2] r = math.sqrt((x-Rx)**2 + (y-Ry)**2) efield = (point - self.point_charge_loc)/r**3 return Vector(efield).shift(point) def calc_field3D(self,point): x,y,z = point Rx,Ry,Rz = self.point_charge_loc r = math.sqrt((x-Rx)**2 + (y-Ry)**2+(z-Rz)**2) efield = (point - self.point_charge_loc)/r**3 return Vector(efield).shift(point)

We don’t need `field2D`

or `calc_field2D`

anymore but I left them in for comparison to the updated code.

**Things to try**

– Rotate the camera so it is below the axes and to the left (or any other point you choose)

– Try plotting a different vector field

– Plot a constant field

– Try efield = np.array((-y,x,z))/math.sqrt(x**2+y**2+z**2)

– Come up with your own 3D vector field

Check out the next post in this series where we look at how to animate the electric field of a moving charge.

Pingback: Vector Fields – manim Series: Part 9 | Talking Physics

Pingback: Learning How To Animate Videos Using manim Series – A Journey | Talking Physics

Pingback: Fields of a Moving Charge – manim Series: Part 11 | Talking Physics