mirror of
https://github.com/ManimCommunity/manim.git
synced 2026-06-29 10:02:11 +00:00
Add keyboard controls
This commit is contained in:
parent
771a7325f2
commit
05a50ebdfa
5 changed files with 76 additions and 20 deletions
|
|
@ -8,14 +8,6 @@ from pathlib import Path
|
|||
# Lines that do not yet work with the Community Version are commented.
|
||||
|
||||
|
||||
class Test(Scene):
|
||||
def construct(self):
|
||||
circle = OpenGLCircle()
|
||||
self.play(circle.animate.shift(RIGHT))
|
||||
circle.add_updater(lambda s: s.move_to(self.mouse_point))
|
||||
self.interact()
|
||||
|
||||
|
||||
class InteractiveDevelopment(Scene):
|
||||
def construct(self):
|
||||
circle = OpenGLCircle()
|
||||
|
|
|
|||
|
|
@ -177,3 +177,5 @@ QUALITIES: typing.Dict[str, typing.Dict[str, typing.Union[str, int, None]]] = {
|
|||
|
||||
DEFAULT_QUALITY: str = "high_quality"
|
||||
DEFAULT_QUALITY_SHORT = QUALITIES[DEFAULT_QUALITY]["flag"]
|
||||
SHIFT_VALUE = 65505
|
||||
CTRL_VALUE = 65507
|
||||
|
|
|
|||
|
|
@ -91,12 +91,10 @@ class OpenGLCamera(OpenGLMobject):
|
|||
quaternion_from_angle_axis(phi, RIGHT, axis_normalized=True),
|
||||
quaternion_from_angle_axis(gamma, OUT, axis_normalized=True),
|
||||
)
|
||||
self.inverse_camera_rotation_matrix = rotation_matrix_transpose_from_quaternion(
|
||||
quat
|
||||
)
|
||||
self.inverse_rotation_matrix = rotation_matrix_transpose_from_quaternion(quat)
|
||||
|
||||
def rotate(self, angle, axis=OUT, **kwargs):
|
||||
curr_rot_T = self.inverse_camera_rotation_matrix
|
||||
curr_rot_T = self.inverse_rotation_matrix
|
||||
added_rot_T = rotation_matrix_transpose(angle, axis)
|
||||
new_rot_T = np.dot(curr_rot_T, added_rot_T)
|
||||
Fz = new_rot_T[2]
|
||||
|
|
@ -197,6 +195,7 @@ class OpenGLRenderer:
|
|||
self.context = moderngl.create_standalone_context()
|
||||
self.frame_buffer_object = self.get_frame_buffer_object(self.context, 0)
|
||||
self.frame_buffer_object.use()
|
||||
self.pressed_keys = set()
|
||||
|
||||
self.context.enable(moderngl.BLEND)
|
||||
self.context.blend_func = (
|
||||
|
|
@ -223,24 +222,24 @@ class OpenGLRenderer:
|
|||
def get_pixel_shape(self):
|
||||
return self.frame_buffer_object.viewport[2:4]
|
||||
|
||||
def refresh_perspective_uniforms(self, camera_frame):
|
||||
def refresh_perspective_uniforms(self, camera):
|
||||
pw, ph = self.get_pixel_shape()
|
||||
fw, fh = camera_frame.get_shape()
|
||||
fw, fh = camera.get_shape()
|
||||
# TODO, this should probably be a mobject uniform, with
|
||||
# the camera taking care of the conversion factor
|
||||
anti_alias_width = self.anti_alias_width / (ph / fh)
|
||||
# Orient light
|
||||
rotation = camera_frame.inverse_camera_rotation_matrix
|
||||
light_pos = camera_frame.light_source.get_location()
|
||||
rotation = camera.inverse_rotation_matrix
|
||||
light_pos = camera.light_source.get_location()
|
||||
light_pos = np.dot(rotation, light_pos)
|
||||
|
||||
self.perspective_uniforms = {
|
||||
"frame_shape": camera_frame.get_shape(),
|
||||
"frame_shape": camera.get_shape(),
|
||||
"anti_alias_width": anti_alias_width,
|
||||
"camera_center": tuple(camera_frame.get_center()),
|
||||
"camera_center": tuple(camera.get_center()),
|
||||
"camera_rotation": tuple(np.array(rotation).T.flatten()),
|
||||
"light_source_position": tuple(light_pos),
|
||||
"focal_distance": camera_frame.get_focal_distance(),
|
||||
"focal_distance": camera.get_focal_distance(),
|
||||
}
|
||||
|
||||
def render_mobjects(self, mobs):
|
||||
|
|
|
|||
|
|
@ -29,9 +29,33 @@ class Window(PygletWindow):
|
|||
|
||||
self.swap_buffers()
|
||||
|
||||
# Delegate event handling to scene
|
||||
# Delegate event handling to scene.
|
||||
def on_mouse_motion(self, x, y, dx, dy):
|
||||
super().on_mouse_motion(x, y, dx, dy)
|
||||
point = self.renderer.pixel_coords_to_space_coords(x, y)
|
||||
d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True)
|
||||
self.renderer.scene.on_mouse_motion(point, d_point)
|
||||
|
||||
def on_mouse_scroll(self, x, y, x_offset: float, y_offset: float):
|
||||
super().on_mouse_scroll(x, y, x_offset, y_offset)
|
||||
point = self.renderer.pixel_coords_to_space_coords(x, y)
|
||||
offset = self.renderer.pixel_coords_to_space_coords(
|
||||
x_offset, y_offset, relative=True
|
||||
)
|
||||
self.renderer.scene.on_mouse_scroll(point, offset)
|
||||
|
||||
def on_key_press(self, symbol, modifiers):
|
||||
self.renderer.pressed_keys.add(symbol)
|
||||
super().on_key_press(symbol, modifiers)
|
||||
self.renderer.scene.on_key_press(symbol, modifiers)
|
||||
|
||||
def on_key_release(self, symbol, modifiers):
|
||||
self.renderer.pressed_keys.remove(symbol)
|
||||
super().on_key_release(symbol, modifiers)
|
||||
self.renderer.scene.on_key_release(symbol, modifiers)
|
||||
|
||||
def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
|
||||
super().on_mouse_drag(x, y, dx, dy, buttons, modifiers)
|
||||
point = self.renderer.pixel_coords_to_space_coords(x, y)
|
||||
d_point = self.renderer.pixel_coords_to_space_coords(dx, dy, relative=True)
|
||||
self.renderer.scene.on_mouse_drag(point, d_point, buttons, modifiers)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ from ..utils.family import extract_mobject_family_members
|
|||
from ..renderer.cairo_renderer import CairoRenderer
|
||||
from ..utils.exceptions import EndSceneEarlyException
|
||||
from ..utils.family_ops import restructure_list_to_exclude_certain_family_members
|
||||
from ..utils.space_ops import rotate_vector
|
||||
|
||||
|
||||
class Scene(Container):
|
||||
|
|
@ -969,3 +970,41 @@ class Scene(Container):
|
|||
|
||||
def on_mouse_motion(self, point, d_point):
|
||||
self.mouse_point.move_to(point)
|
||||
if SHIFT_VALUE in self.renderer.pressed_keys:
|
||||
shift = -d_point
|
||||
shift[0] *= self.camera.get_width() / 2
|
||||
shift[1] *= self.camera.get_height() / 2
|
||||
transform = self.camera.inverse_rotation_matrix
|
||||
shift = np.dot(np.transpose(transform), shift)
|
||||
self.camera.shift(shift)
|
||||
|
||||
def on_mouse_scroll(self, point, offset):
|
||||
if CTRL_VALUE in self.renderer.pressed_keys:
|
||||
factor = 1 + np.arctan(-20 * offset[1])
|
||||
self.camera.scale(factor, about_point=point)
|
||||
|
||||
transform = self.camera.inverse_rotation_matrix
|
||||
shift = np.dot(np.transpose(transform), offset)
|
||||
if SHIFT_VALUE in self.renderer.pressed_keys:
|
||||
self.camera.shift(20.0 * np.array(rotate_vector(shift, PI / 2)))
|
||||
else:
|
||||
self.camera.shift(20.0 * shift)
|
||||
|
||||
def on_key_press(self, symbol, modifiers):
|
||||
try:
|
||||
char = chr(symbol)
|
||||
except OverflowError:
|
||||
logger.warning("The value of the pressed key is too large.")
|
||||
return
|
||||
|
||||
if char == "r":
|
||||
self.camera.to_default_state()
|
||||
elif char == "q":
|
||||
self.quit_interaction = True
|
||||
|
||||
def on_key_release(self, symbol, modifiers):
|
||||
pass
|
||||
|
||||
def on_mouse_drag(self, point, d_point, buttons, modifiers):
|
||||
self.camera.increment_theta(-d_point[0])
|
||||
self.camera.increment_phi(d_point[1])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue