mirror of
https://github.com/3b1b/manim.git
synced 2025-11-14 22:47:45 +00:00
Refactor so that view matrix incorporates frame scaling
This commit is contained in:
parent
b85c3bd478
commit
277c471c90
8 changed files with 45 additions and 36 deletions
|
|
@ -231,12 +231,12 @@ class Camera(object):
|
|||
cam_pos = self.frame.get_implied_camera_location()
|
||||
|
||||
self.uniforms.update(
|
||||
view=tuple(view_matrix.T.flatten()),
|
||||
focal_distance=frame.get_focal_distance() / frame.get_scale(),
|
||||
frame_shape=frame.get_shape(),
|
||||
pixel_size=self.get_pixel_size(),
|
||||
view=tuple(view_matrix.T.flatten()),
|
||||
camera_position=tuple(cam_pos),
|
||||
light_position=tuple(light_pos),
|
||||
focal_distance=frame.get_focal_distance(),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import math
|
|||
|
||||
import numpy as np
|
||||
from scipy.spatial.transform import Rotation
|
||||
from pyrr import Matrix44
|
||||
|
||||
from manimlib.constants import DEGREES, RADIANS
|
||||
from manimlib.constants import FRAME_SHAPE
|
||||
|
|
@ -76,6 +77,9 @@ class CameraFrame(Mobject):
|
|||
def get_gamma(self):
|
||||
return self.get_euler_angles()[2]
|
||||
|
||||
def get_scale(self):
|
||||
return self.get_height() / FRAME_SHAPE[1]
|
||||
|
||||
def get_inverse_camera_rotation_matrix(self):
|
||||
return self.get_orientation().as_matrix().T
|
||||
|
||||
|
|
@ -84,13 +88,14 @@ class CameraFrame(Mobject):
|
|||
Returns a 4x4 for the affine transformation mapping a point
|
||||
into the camera's internal coordinate system
|
||||
"""
|
||||
result = self.view_matrix
|
||||
result[:] = np.identity(4)
|
||||
result[:3, 3] = -self.get_center()
|
||||
rotation = np.identity(4)
|
||||
rotation[:3, :3] = self.get_inverse_camera_rotation_matrix()
|
||||
result[:] = np.dot(rotation, result)
|
||||
return result
|
||||
shift = Matrix44.from_translation(-self.get_center()).T
|
||||
rotation = Matrix44.from_quaternion(self.uniforms["orientation"]).T
|
||||
self.view_matrix[:] = np.dot(rotation, shift)
|
||||
self.view_matrix[:3, :3] /= self.get_scale()
|
||||
return self.view_matrix
|
||||
|
||||
def get_inv_view_matrix(self):
|
||||
return np.linalg.inv(self.get_view_matrix())
|
||||
|
||||
def rotate(self, angle: float, axis: np.ndarray = OUT, **kwargs):
|
||||
rot = Rotation.from_rotvec(angle * normalize(axis))
|
||||
|
|
@ -160,6 +165,10 @@ class CameraFrame(Mobject):
|
|||
def get_shape(self):
|
||||
return (self.get_width(), self.get_height())
|
||||
|
||||
def get_aspect_ratio(self):
|
||||
width, height = self.get_shape()
|
||||
return width / height
|
||||
|
||||
def get_center(self) -> np.ndarray:
|
||||
# Assumes first point is at the center
|
||||
return self.get_points()[0]
|
||||
|
|
@ -183,6 +192,12 @@ class CameraFrame(Mobject):
|
|||
dist = self.get_focal_distance()
|
||||
return self.get_center() + dist * to_camera
|
||||
|
||||
def to_fixed_frame_point(self, point: Vect3):
|
||||
def to_fixed_frame_point(self, point: Vect3, relative: bool = False):
|
||||
view = self.get_view_matrix()
|
||||
return np.dot([*point, 1], view.T)[:3]
|
||||
point4d = [*point, 0 if relative else 1]
|
||||
return np.dot(point4d, view.T)[:3]
|
||||
|
||||
def from_fixed_frame_point(self, point: Vect3, relative: bool = False):
|
||||
inv_view = self.get_inv_view_matrix()
|
||||
point4d = [*point, 0 if relative else 1]
|
||||
return np.dot(point4d, inv_view.T)[:3]
|
||||
|
|
|
|||
|
|
@ -804,6 +804,7 @@ class Scene(object):
|
|||
point: Vect3,
|
||||
d_point: Vect3
|
||||
) -> None:
|
||||
assert(self.window is not None)
|
||||
self.mouse_point.move_to(point)
|
||||
|
||||
event_data = {"point": point, "d_point": d_point}
|
||||
|
|
@ -814,13 +815,13 @@ class Scene(object):
|
|||
frame = self.camera.frame
|
||||
# Handle perspective changes
|
||||
if self.window.is_key_pressed(ord(PAN_3D_KEY)):
|
||||
ff_d_point = np.dot(d_point, frame.get_view_matrix()[:3, :3].T)
|
||||
ff_d_point = frame.to_fixed_frame_point(d_point, relative=True)
|
||||
ff_d_point *= self.pan_sensitivity
|
||||
frame.increment_theta(-ff_d_point[0])
|
||||
frame.increment_phi(ff_d_point[1])
|
||||
# Handle frame movements
|
||||
elif self.window.is_key_pressed(ord(FRAME_SHIFT_KEY)):
|
||||
frame.shift(-d_point)
|
||||
frame.shift(-d_point / self.frame.get_scale())
|
||||
|
||||
def on_mouse_drag(
|
||||
self,
|
||||
|
|
@ -830,7 +831,7 @@ class Scene(object):
|
|||
modifiers: int
|
||||
) -> None:
|
||||
self.mouse_drag_point.move_to(point)
|
||||
self.frame.shift(-d_point)
|
||||
self.frame.shift(-d_point / self.frame.get_scale())
|
||||
|
||||
event_data = {"point": point, "d_point": d_point, "buttons": buttons, "modifiers": modifiers}
|
||||
propagate_event = EVENT_DISPATCHER.dispatch(EventType.MouseDragEvent, **event_data)
|
||||
|
|
@ -871,7 +872,7 @@ class Scene(object):
|
|||
return
|
||||
|
||||
frame = self.camera.frame
|
||||
ff_offset = offset * FRAME_HEIGHT / frame.get_height()
|
||||
ff_offset = offset / frame.get_scale()
|
||||
frame.scale(1 - ff_offset[1], about_point=point)
|
||||
|
||||
def on_key_release(
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
uniform float is_fixed_in_frame;
|
||||
uniform mat4 view;
|
||||
uniform vec2 frame_shape;
|
||||
uniform float focal_distance;
|
||||
|
||||
const vec2 DEFAULT_FRAME_SHAPE = vec2(8.0 * 16.0 / 9.0, 8.0);
|
||||
const float DEFAULT_FRAME_HEIGHT = 8.0;
|
||||
const float DEFAULT_FRAME_WIDTH = DEFAULT_FRAME_HEIGHT * 16.0 / 9.0;
|
||||
|
||||
vec4 get_gl_Position(vec3 point){
|
||||
bool is_fixed = bool(is_fixed_in_frame);
|
||||
vec4 result = vec4(point, 1.0);
|
||||
if(!is_fixed){
|
||||
if(!bool(is_fixed_in_frame)){
|
||||
result = view * result;
|
||||
}
|
||||
|
||||
vec2 shape = is_fixed ? DEFAULT_FRAME_SHAPE : frame_shape;
|
||||
result.x *= 2.0 / shape.x;
|
||||
result.y *= 2.0 / shape.y;
|
||||
result.x *= 2.0 / DEFAULT_FRAME_WIDTH;
|
||||
result.y *= 2.0 / DEFAULT_FRAME_HEIGHT;
|
||||
result.z /= focal_distance;
|
||||
result.w = 1.0 - result.z;
|
||||
// Flip and scale to prevent premature clipping
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@ uniform vec3 color6;
|
|||
uniform vec3 color7;
|
||||
uniform vec3 color8;
|
||||
|
||||
uniform vec2 frame_shape;
|
||||
|
||||
in vec3 xyz_coords;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ uniform float saturation_factor;
|
|||
uniform float black_for_cycles;
|
||||
uniform float is_parameter_space;
|
||||
|
||||
uniform vec2 frame_shape;
|
||||
|
||||
in vec3 xyz_coords;
|
||||
|
||||
out vec4 frag_color;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from moderngl_window.context.pyglet.window import Window as PygletWindow
|
|||
from moderngl_window.timers.clock import Timer
|
||||
from screeninfo import get_monitors
|
||||
|
||||
from manimlib.constants import FRAME_SHAPE
|
||||
from manimlib.utils.customization import get_customization
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
|
@ -78,16 +79,14 @@ class Window(PygletWindow):
|
|||
relative: bool = False
|
||||
) -> np.ndarray:
|
||||
pixel_shape = np.array(self.size)
|
||||
frame_shape = np.array(self.scene.frame.get_shape())
|
||||
frame_shape = np.array(FRAME_SHAPE)
|
||||
frame = self.scene.frame
|
||||
|
||||
coords = (frame_shape / pixel_shape) * np.array([px, py])
|
||||
view = self.scene.frame.get_view_matrix()
|
||||
|
||||
if relative:
|
||||
return np.dot([*coords, 0], view[:3, :3])
|
||||
|
||||
coords -= 0.5 * frame_shape
|
||||
return np.dot([*coords, 0, 1], np.linalg.inv(view).T)[:3]
|
||||
coords = np.zeros(3)
|
||||
coords[:2] = (frame_shape / pixel_shape) * np.array([px, py])
|
||||
if not relative:
|
||||
coords[:2] -= 0.5 * frame_shape
|
||||
return frame.from_fixed_frame_point(coords, relative)
|
||||
|
||||
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> None:
|
||||
super().on_mouse_motion(x, y, dx, dy)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ pydub
|
|||
pygments
|
||||
PyOpenGL
|
||||
pyperclip
|
||||
pyrr
|
||||
pyyaml
|
||||
rich
|
||||
scipy
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue