Merge pull request #109 from frozar/3D_camera_moving

[3D CAMERA] Center of rotation
This commit is contained in:
Grant Sanderson 2018-02-13 15:46:21 -08:00 committed by GitHub
commit 921dc1a6d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 97 additions and 6 deletions

View file

@ -24,6 +24,8 @@ from topics.number_line import *
from topics.combinatorics import *
from topics.three_dimensions import *
from topics.three_dimensions import *
# To watch one of these scenes, run the following:
# python extract_scene.py file_name <SceneName> -p
#
@ -59,6 +61,67 @@ class WriteStuff(Scene):
self.play(Write(TextMobject("Stuff").scale(3)))
class Rotation3d(ThreeDScene):
def construct(self):
# STEP 1
# Build two cube in the 3D scene, one for around the origin,
# the other shifted along the vector RIGHT + UP + OUT
cube_origin = Cube(fill_opacity = 0.8, stroke_width = 1.,
side_length = 1., fill_color = WHITE)
# RIGHT side: Red
# UP side: Green
# OUT side: Blue
orientations = [IN, OUT, LEFT, RIGHT, UP, DOWN]
for face, orient in zip(cube_origin.family_members_with_points(), orientations):
if np.array_equal(orient, RIGHT):
face.set_style_data(fill_color = RED)
elif np.array_equal(orient, UP):
face.set_style_data(fill_color = GREEN)
elif np.array_equal(orient, OUT):
face.set_style_data(fill_color = BLUE)
cube_shifted = Cube(fill_opacity = 0.8, stroke_width = 1.,
side_length = 1., fill_color = BLUE)
shift_vec = 2*(RIGHT + UP + OUT)
cube_shifted.shift(shift_vec)
# STEP 2
# Add the cubes in the 3D scene
self.add(cube_origin)
self.add(cube_shifted)
# STEP 3
# Setup the camera position
phi, theta, distance = ThreeDCamera().get_spherical_coords()
angle_factor = 0.9
phi += 2*np.pi/4*angle_factor
theta += 3*2*np.pi/8
self.set_camera_position(phi, theta, distance)
self.wait()
# STEP 4
# Animation
# Animation 1: rotation around the Z-axis with the ORIGIN of the space
# as center of rotation
theta += 2*np.pi
self.move_camera(phi, theta, distance,
run_time = 5)
# Animation 2: shift the space in order of to get the center of the shifted cube
# as the next center of rotation
cube_center = cube_shifted.get_center()
self.move_camera(center_x = cube_center[0],
center_y = cube_center[1],
center_z = cube_center[2],
run_time = 2)
# Animation 3: rotation around the Z-axis with the center of the shifted cube
# as center of rotation
theta += 2*np.pi
self.move_camera(phi, theta, distance,
run_time = 5)
class SpinAroundCube(ThreeDScene):
# Take a look at ThreeDSCene in three_dimensions.py.

View file

@ -36,8 +36,11 @@ class ThreeDCamera(CameraWithPerspective):
def __init__(self, *args, **kwargs):
Camera.__init__(self, *args, **kwargs)
self.unit_sun_vect = self.sun_vect/np.linalg.norm(self.sun_vect)
## Lives in the phi-theta-distance space
## rotation_mobject lives in the phi-theta-distance space
self.rotation_mobject = VectorizedPoint()
## moving_center lives in the x-y-z space
## It representes the center of rotation
self.moving_center = VectorizedPoint(self.space_center)
self.set_position(self.phi, self.theta, self.distance)
def modified_rgb(self, vmobject, rgb):
@ -128,10 +131,24 @@ class ThreeDCamera(CameraWithPerspective):
np.cos(phi)
])
def set_position(self, phi = None, theta = None, distance = None):
def get_center_of_rotation(self, x = None, y = None, z = None):
curr_x, curr_y, curr_z = self.moving_center.points[0]
if x is None:
x = curr_x
if y is None:
y = curr_y
if z is None:
z = curr_z
return np.array([x, y, z])
def set_position(self, phi = None, theta = None, distance = None,
center_x = None, center_y = None, center_z = None):
point = self.get_spherical_coords(phi, theta, distance)
self.rotation_mobject.move_to(point)
self.phi, self.theta, self.distance = point
center_of_rotation = self.get_center_of_rotation(center_x, center_y, center_z)
self.moving_center.move_to(center_of_rotation)
self.space_center = self.moving_center.points[0]
def get_view_transformation_matrix(self):
return (self.default_distance / self.get_distance()) * np.dot(
@ -142,6 +159,8 @@ class ThreeDCamera(CameraWithPerspective):
def points_to_pixel_coords(self, points):
matrix = self.get_view_transformation_matrix()
new_points = np.dot(points, matrix.T)
self.space_center = self.moving_center.points[0]
return Camera.points_to_pixel_coords(self, new_points)
class ThreeDScene(Scene):
@ -150,8 +169,9 @@ class ThreeDScene(Scene):
"ambient_camera_rotation" : None,
}
def set_camera_position(self, phi = None, theta = None, distance = None):
self.camera.set_position(phi, theta, distance)
def set_camera_position(self, phi = None, theta = None, distance = None,
center_x = None, center_y = None, center_z = None):
self.camera.set_position(phi, theta, distance, center_x, center_y, center_z)
def begin_ambient_camera_rotation(self, rate = 0.01):
self.ambient_camera_rotation = AmbientMovement(
@ -167,8 +187,9 @@ class ThreeDScene(Scene):
self.ambient_camera_rotation = None
def move_camera(
self,
self,
phi = None, theta = None, distance = None,
center_x = None, center_y = None, center_z = None,
added_anims = [],
**kwargs
):
@ -178,10 +199,17 @@ class ThreeDScene(Scene):
target_point,
**kwargs
)
target_center = self.camera.get_center_of_rotation(center_x, center_y, center_z)
movement_center = ApplyMethod(
self.camera.moving_center.move_to,
target_center,
**kwargs
)
is_camera_rotating = self.ambient_camera_rotation in self.continual_animations
if is_camera_rotating:
self.remove(self.ambient_camera_rotation)
self.play(movement, *added_anims)
self.play(movement, movement_center, *added_anims)
target_point = self.camera.get_spherical_coords(phi, theta, distance)
if is_camera_rotating:
self.add(self.ambient_camera_rotation)