Merge pull request #4 from 3b1b/shaders

Update
This commit is contained in:
鹤翔万里 2021-01-22 19:34:49 +08:00 committed by GitHub
commit 9bd4f6714f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 318 additions and 270 deletions

View file

@ -21,10 +21,10 @@ If you want to hack on manimlib itself, clone this repository and in that direct
```sh
# Install python requirements
pip3 install -r requirements.txt
pip install -r requirements.txt
# Try it out
python3 -m manim example_scenes.py OpeningManimExample
python -m manim example_scenes.py OpeningManimExample
```
### Directly (Windows)
@ -34,8 +34,8 @@ python3 -m manim example_scenes.py OpeningManimExample
```sh
git clone https://github.com/3b1b/manim.git
cd manim
pip3 install -r requirements.txt
python3 manim.py example_scenes.py OpeningManimExample
pip install -r requirements.txt
python manim.py example_scenes.py OpeningManimExample
```
@ -50,14 +50,14 @@ After installing `virtualenv` and `virtualenvwrapper`
```sh
git clone https://github.com/3b1b/manim.git
mkvirtualenv -a manim -r requirements.txt manim
python3 -m manim example_scenes.py OpeningManimExample
python -m manim example_scenes.py OpeningManimExample
```
## Using manim
Try running the following:
```sh
python3 -m manim example_scenes.py OpeningManimExample
python -m manim example_scenes.py OpeningManimExample
```
This should pop up a window playing a simple scene.
@ -65,11 +65,11 @@ Some useful flags include:
* `-w` to write the scene to a file
* `-o` to write the scene to a file and open the result
* `-s` to skip to the end and just show the final frame.
* `-so` will asve the final frame to an image and show it
* `-so` will save the final frame to an image and show it
* `-n <number>` to skip ahead to the `n`'th animation of a scene.
* `-f` to make the playback window fullscreen
Take a look at custom_defaults.yml for further configuration. For example, there you can specify where videos should be output to, where manim should look for image files and sounds you want to read in, and other defaults regarding style and video quality. If you have a file name "custom_defaults.yml" in the same directory where you are calling manim, it will look to the configuration of that file instead of the one in manim itself.
Take a look at custom_defaults.yml for further configuration. To add your customization, you can either edit this file, or add another file by the same name "custom_defaults.yml" to whatever directory you are running manim from. For example [this is the one](https://github.com/3b1b/videos/blob/master/custom_defaults.yml) for 3blue1brown videos. There you can specify where videos should be output to, where manim should look for image files and sounds you want to read in, and other defaults regarding style and video quality.
Look through [https://github.com/3b1b/videos](https://github.com/3b1b/videos) to see the code for previous 3b1b videos. Note, however, that developments are often made to the library without considering backwards compatibility with those old projects. To run an old project with a guarantee that it will work, you will have to go back to the commit which completed that project.

View file

@ -10,8 +10,8 @@ from manimlib.imports import *
class OpeningManimExample(Scene):
def construct(self):
title = TextMobject("This is some \\LaTeX")
basel = TexMobject(
title = TexText("This is some \\LaTeX")
basel = Tex(
"\\sum_{n=1}^\\infty "
"\\frac{1}{n^2} = \\frac{\\pi^2}{6}"
)
@ -22,18 +22,18 @@ class OpeningManimExample(Scene):
)
self.wait()
transform_title = TextMobject("That was a transform")
transform_title.to_corner(UP + LEFT)
transform_title = Text("That was a transform")
transform_title.to_corner(UL)
self.play(
Transform(title, transform_title),
LaggedStartMap(FadeOut, basel, shift=DOWN),
)
self.wait()
fade_comment = TextMobject(
fade_comment = Text(
"""
You probably don't want to overuse\\\\
Transforms, though, a simple fade often\\\\
You probably don't want to overuse
Transforms, though, a simple fade often
looks nicer.
""",
font_size=36,
@ -48,7 +48,7 @@ class OpeningManimExample(Scene):
self.wait(3)
grid = NumberPlane((-10, 10), (-5, 5))
grid_title = TextMobject(
grid_title = Text(
"But manim is for illustrating math, not text",
)
grid_title.to_edge(UP)
@ -65,9 +65,9 @@ class OpeningManimExample(Scene):
matrix = [[1, 1], [0, 1]]
linear_transform_title = VGroup(
TextMobject("This is what the matrix"),
Text("This is what the matrix"),
IntegerMatrix(matrix, include_background_rectangle=True),
TextMobject("looks like")
Text("looks like")
)
linear_transform_title.arrange(RIGHT)
linear_transform_title.to_edge(UP)
@ -79,7 +79,7 @@ class OpeningManimExample(Scene):
self.play(grid.apply_matrix, matrix, run_time=3)
self.wait()
grid_transform_title = TextMobject(
grid_transform_title = Text(
"And this is a nonlinear transformation"
)
grid_transform_title.set_stroke(BLACK, 5, background=True)
@ -111,12 +111,12 @@ class TextExample(Scene):
text = Text("Here is a text", font="Consolas", font_size=90)
difference = Text(
"""
The most important difference between Text and TextMobject is that\n
you can change the font more easily, but can't use the LaTeX gramma
The most important difference between Text and TexText is that\n
you can change the font more easily, but can't use the LaTeX grammar
""",
font="Arial", font_size=24,
# t2c is a dict that you can choose color for different text
t2c={"Text": BLUE, "TextMobject": BLUE, "LaTeX": ORANGE}
t2c={"Text": BLUE, "TexText": BLUE, "LaTeX": ORANGE}
)
VGroup(text, difference).arrange(DOWN, buff=1)
self.play(Write(text))
@ -175,18 +175,18 @@ class TexTransformExample(Scene):
lines = VGroup(
# Surrounding substrings with double braces
# will ensure that those parts are separated
# out in the TexMobject. For example, here the
# TexMobject will have 5 submobjects, corresponding
# out in the Tex. For example, here the
# Tex will have 5 submobjects, corresponding
# to the strings [A^2, +, B^2, =, C^2]
TexMobject("{{A^2}} + {{B^2}} = {{C^2}}"),
TexMobject("{{A^2}} = {{C^2}} - {{B^2}}"),
Tex("{{A^2}} + {{B^2}} = {{C^2}}"),
Tex("{{A^2}} = {{C^2}} - {{B^2}}"),
# Alternatively, you can pass in the keyword argument
# isolate with a list of strings that should be out as
# their own submobject. So both lines below are equivalent
# to what you'd get by wrapping every instance of "B", "C"
# "=", "(" and ")" with double braces
TexMobject("{{A^2}} = (C + B)(C - B)", **kw),
TexMobject("A = \\sqrt{(C + B)(C - B)}", **kw)
Tex("{{A^2}} = (C + B)(C - B)", **kw),
Tex("A = \\sqrt{(C + B)(C - B)}", **kw)
)
lines.arrange(DOWN, buff=LARGE_BUFF)
for line in lines:
@ -258,8 +258,8 @@ class TexTransformExample(Scene):
# those of a target, regardless of the submobject hierarchy in
# each one, according to whether those pieces have the same
# shape (as best it can).
source = TextMobject("the morse code")
target = TextMobject("here come dots")
source = TexText("the morse code")
target = TexText("here come dots")
self.play(Write(source))
self.wait()
@ -343,7 +343,7 @@ class SurfaceExample(Scene):
# Set perspective
frame = self.camera.frame
frame.set_rotation(
frame.set_euler_angles(
theta=-30 * DEGREES,
phi=70 * DEGREES,
)
@ -388,7 +388,7 @@ class SurfaceExample(Scene):
self.play(light.move_to, 3 * IN, run_time=5)
self.play(light.shift, 10 * OUT, run_time=5)
drag_text = Text("Try clicking and dragging while pressing d")
drag_text = Text("Try moving the mouse while pressing d or s")
drag_text.move_to(light_text)
drag_text.fix_in_frame()

View file

@ -60,10 +60,10 @@ class Thumbnail(GraphScene):
triangle.scale(0.1)
#
x_label_p1 = TexMobject("a")
output_label_p1 = TexMobject("f(a)")
x_label_p2 = TexMobject("b")
output_label_p2 = TexMobject("f(b)")
x_label_p1 = Tex("a")
output_label_p1 = Tex("f(a)")
x_label_p2 = Tex("b")
output_label_p2 = Tex("f(b)")
v_line_p1 = get_v_line(input_tracker_p1)
v_line_p2 = get_v_line(input_tracker_p2)
h_line_p1 = get_h_line(input_tracker_p1)
@ -170,7 +170,7 @@ class Thumbnail(GraphScene):
# adding manim
picture = Group(*self.mobjects)
picture.scale(0.6).to_edge(LEFT, buff=SMALL_BUFF)
manim = TextMobject("Manim").set_height(1.5) \
manim = TexText("Manim").set_height(1.5) \
.next_to(picture, RIGHT) \
.shift(DOWN * 0.7)
self.add(manim)

View file

@ -8,7 +8,7 @@ from manimlib.mobject.mobject import Mobject
from manimlib.mobject.mobject import Group
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.mobject.types.vectorized_mobject import VMobject
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.utils.config_ops import digest_config
@ -122,7 +122,7 @@ class TransformMatchingShapes(TransformMatchingParts):
class TransformMatchingTex(TransformMatchingParts):
CONFIG = {
"mobject_type": TexMobject,
"mobject_type": Tex,
"group_type": VGroup,
}

View file

@ -10,7 +10,6 @@ from manimlib.constants import *
from manimlib.mobject.mobject import Mobject
from manimlib.mobject.mobject import Point
from manimlib.utils.config_ops import digest_config
from manimlib.utils.bezier import interpolate
from manimlib.utils.simple_functions import fdiv
from manimlib.utils.simple_functions import clip
from manimlib.utils.space_ops import angle_of_vector
@ -29,38 +28,39 @@ class CameraFrame(Mobject):
"focal_distance": 2,
}
def init_data(self):
super().init_data()
self.data["euler_angles"] = np.array(self.euler_angles, dtype=float)
self.refresh_rotation_matrix()
def init_points(self):
self.set_points([ORIGIN, LEFT, RIGHT, DOWN, UP])
self.set_width(self.frame_shape[0], stretch=True)
self.set_height(self.frame_shape[1], stretch=True)
self.move_to(self.center_point)
self.euler_angles = np.array(self.euler_angles, dtype='float64')
self.refresh_camera_rotation_matrix()
def to_default_state(self):
self.center()
self.set_height(FRAME_HEIGHT)
self.set_width(FRAME_WIDTH)
self.set_rotation(0, 0, 0)
self.set_euler_angles(0, 0, 0)
return self
def get_inverse_camera_position_matrix(self):
mat = np.identity(4)
# Shift so that origin of real space coincides with camera origin
mat[:3, 3] = -self.get_center().T
# Rotate based on camera orientation
mat[:3, :4] = np.dot(self.inverse_camera_rotation_matrix, mat[:3, :4])
return mat
def get_euler_angles(self):
return self.data["euler_angles"]
def refresh_camera_rotation_matrix(self):
theta, phi, gamma = self.euler_angles
def get_inverse_camera_rotation_matrix(self):
return self.inverse_camera_rotation_matrix
def refresh_rotation_matrix(self):
# Rotate based on camera orientation
theta, phi, gamma = self.get_euler_angles()
quat = quaternion_mult(
quaternion_from_angle_axis(theta, OUT, axis_normalized=True),
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)
return self
def rotate(self, angle, axis=OUT, **kwargs):
curr_rot_T = self.get_inverse_camera_rotation_matrix()
@ -74,38 +74,44 @@ class CameraFrame(Mobject):
rotation_matrix_transpose(theta, OUT),
)
gamma = angle_of_vector(np.dot(partial_rot_T, new_rot_T.T)[:, 0])
# TODO, write a function that converts quaternions to euler angles
self.euler_angles[:] = theta, phi, gamma
self.set_euler_angles(theta, phi, gamma)
return self
def set_rotation(self, theta=None, phi=None, gamma=None):
def set_euler_angles(self, theta=None, phi=None, gamma=None):
if theta is not None:
self.euler_angles[0] = theta
self.data["euler_angles"][0] = theta
if phi is not None:
self.euler_angles[1] = phi
self.data["euler_angles"][1] = phi
if gamma is not None:
self.euler_angles[2] = gamma
self.refresh_camera_rotation_matrix()
self.data["euler_angles"][2] = gamma
self.refresh_rotation_matrix()
return self
def set_theta(self, theta):
return self.set_rotation(theta=theta)
return self.set_euler_angles(theta=theta)
def set_phi(self, phi):
return self.set_rotation(phi=phi)
return self.set_euler_angles(phi=phi)
def set_gamma(self, gamma):
return self.set_rotation(gamma=gamma)
return self.set_euler_angles(gamma=gamma)
def increment_theta(self, dtheta):
return self.set_rotation(theta=self.euler_angles[0] + dtheta)
self.data["euler_angles"][0] += dtheta
self.refresh_rotation_matrix()
return self
def increment_phi(self, dphi):
new_phi = clip(self.euler_angles[1] + dphi, 0, PI)
return self.set_rotation(phi=new_phi)
phi = self.data["euler_angles"][1]
new_phi = clip(phi + dphi, 0, PI)
self.data["euler_angles"][1] = new_phi
self.refresh_rotation_matrix()
return self
def increment_gamma(self, dgamma):
return self.set_rotation(theta=self.euler_angles[2] + dgamma)
self.data["euler_angles"][2] += dgamma
self.refresh_rotation_matrix()
return self
def get_shape(self):
return (self.get_width(), self.get_height())
@ -125,11 +131,9 @@ class CameraFrame(Mobject):
def get_focal_distance(self):
return self.focal_distance * self.get_height()
def interpolate(self, frame1, frame2, alpha, path_func):
self.euler_angles[:] = interpolate(frame1.euler_angles, frame2.euler_angles, alpha)
self.refresh_camera_rotation_matrix()
# TODO, can probably safely call super
self.set_points(interpolate(frame1.get_points(), frame2.get_points(), alpha))
def interpolate(self, *args, **kwargs):
super().interpolate(*args, **kwargs)
self.refresh_rotation_matrix()
class Camera(object):
@ -412,20 +416,24 @@ class Camera(object):
pass
def refresh_perspective_uniforms(self):
frame = self.frame
pw, ph = self.get_pixel_shape()
fw, fh = self.frame.get_shape()
fw, fh = frame.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)
transform = self.frame.get_inverse_camera_position_matrix()
light = self.light_source.get_location()
transformed_light = np.dot(transform, [*light, 1])[:3]
# Orient light
rotation = frame.get_inverse_camera_rotation_matrix()
light_pos = self.light_source.get_location()
light_pos = np.dot(rotation, light_pos)
self.perspective_uniforms = {
'to_screen_space': tuple(transform.T.flatten()),
'frame_shape': self.frame.get_shape(),
'focal_distance': self.frame.get_focal_distance(),
'anti_alias_width': anti_alias_width,
'light_source_position': tuple(transformed_light),
"frame_shape": frame.get_shape(),
"anti_alias_width": anti_alias_width,
"camera_center": tuple(frame.get_center()),
"camera_rotation": tuple(np.array(rotation).T.flatten()),
"light_source_position": tuple(light_pos),
"focal_distance": frame.get_focal_distance(),
}
def init_textures(self):

View file

@ -7,6 +7,8 @@ import sys
import yaml
from screeninfo import get_monitors
from manimlib.utils.config_ops import merge_dicts_recursively
def parse_cli():
try:
@ -147,14 +149,22 @@ def get_module(file_name):
def get_custom_defaults():
# See if there's a custom_defaults file in current directory,
# otherwise fall back on the one in manimlib
filename = "custom_defaults.yml"
if not os.path.exists(filename):
filename = os.path.join(get_manim_dir(), filename)
with open(filename, "r") as file:
manim_defaults_file = os.path.join(get_manim_dir(), filename)
with open(manim_defaults_file, "r") as file:
custom_defaults = yaml.safe_load(file)
# See if there's a custom_defaults file in current directory,
# and if so, it further updates the defaults based on it.
if os.path.exists(filename):
with open(filename, "r") as file:
local_defaults = yaml.safe_load(file)
if local_defaults:
custom_defaults = merge_dicts_recursively(
custom_defaults,
local_defaults,
)
return custom_defaults
@ -198,31 +208,12 @@ def get_configuration(args):
# Default to putting window in the upper right of screen,
# but make it full screen if -f is passed in
monitor = get_monitors()[0]
if args.full_screen:
window_width = monitor.width
else:
window_width = monitor.width / 2
window_height = window_width * 9 / 16
custom_position = custom_defaults["window_position"]
if "," in custom_position:
posx, posy = map(int, custom_position.split(","))
else:
if custom_position[1] == "L":
posx = 0
elif custom_position[1] == "O":
posx = int((monitor.width - window_width) / 2)
elif custom_position[1] == "R":
posx = int(monitor.width - window_width)
if custom_position[0] == "U":
posy = 0
elif custom_position[0] == "O":
posy = int((monitor.height - window_height) / 2)
elif custom_position[0] == "D":
posy = int(monitor.height - window_height)
window_position = (posx, posy)
if not args.full_screen:
window_width //= 2
window_height = window_width * 9 // 16
config["window_config"] = {
"size": (window_width, window_height),
"position": window_position,
}
# Arguments related to skipping

View file

@ -6,7 +6,7 @@ from manimlib.mobject.functions import ParametricCurve
from manimlib.mobject.geometry import Arrow
from manimlib.mobject.geometry import Line
from manimlib.mobject.number_line import NumberLine
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.utils.config_ops import merge_dicts_recursively
from manimlib.utils.simple_functions import binary_search
@ -69,7 +69,7 @@ class CoordinateSystem():
)
def get_axis_label(self, label_tex, axis, edge, direction, buff=MED_SMALL_BUFF):
label = TexMobject(label_tex)
label = Tex(label_tex)
label.next_to(
axis.get_edge_center(edge), direction,
buff=buff

View file

@ -5,8 +5,8 @@ from manimlib.constants import *
from manimlib.mobject.numbers import DecimalNumber
from manimlib.mobject.numbers import Integer
from manimlib.mobject.shape_matchers import BackgroundRectangle
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import TextMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.svg.tex_mobject import TexText
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.mobject.types.vectorized_mobject import VMobject
@ -28,7 +28,7 @@ def matrix_to_tex_string(matrix):
def matrix_to_mobject(matrix):
return TexMobject(matrix_to_tex_string(matrix))
return Tex(matrix_to_tex_string(matrix))
def vector_coordinate_label(vector_mob, integer_labels=True,
@ -61,7 +61,7 @@ class Matrix(VMobject):
"bracket_v_buff": MED_SMALL_BUFF,
"add_background_rectangles_to_entries": False,
"include_background_rectangle": False,
"element_to_mobject": TexMobject,
"element_to_mobject": Tex,
"element_to_mobject_config": {},
"element_alignment_corner": DR,
}
@ -108,7 +108,7 @@ class Matrix(VMobject):
def add_brackets(self):
height = self.matrix.shape[0]
bracket_pair = TexMobject("".join([
bracket_pair = Tex("".join([
"\\left[",
"\\begin{array}{c}",
*height * ["\\quad \\\\"],
@ -173,22 +173,22 @@ class MobjectMatrix(Matrix):
def get_det_text(matrix, determinant=None, background_rect=False, initial_scale_factor=2):
parens = TexMobject("(", ")")
parens = Tex("(", ")")
parens.scale(initial_scale_factor)
parens.stretch_to_fit_height(matrix.get_height())
l_paren, r_paren = parens.split()
l_paren.next_to(matrix, LEFT, buff=0.1)
r_paren.next_to(matrix, RIGHT, buff=0.1)
det = TextMobject("det")
det = TexText("det")
det.scale(initial_scale_factor)
det.next_to(l_paren, LEFT, buff=0.1)
if background_rect:
det.add_background_rectangle()
det_text = VGroup(det, l_paren, r_paren)
if determinant is not None:
eq = TexMobject("=")
eq = Tex("=")
eq.next_to(r_paren, RIGHT, buff=0.1)
result = TexMobject(str(determinant))
result = Tex(str(determinant))
result.next_to(eq, RIGHT, buff=0.2)
det_text.add(eq, result)
return det_text

View file

@ -1145,8 +1145,14 @@ class Mobject(object):
def align_family(self, mobject):
mob1 = self
mob2 = mobject
n1 = len(mob1.submobjects)
n2 = len(mob2.submobjects)
n1 = len(mob1)
n2 = len(mob2)
while n1 == 1 and n2 > 1:
mob1.set_submobjects(mob1[0].submobjects)
n1 = len(mob1)
while n2 == 1 and n1 > 1:
mob2.set_submobjects(mob2[0].submobjects)
n2 = len(mob2)
if n1 != n2:
mob1.add_n_more_submobjects(max(0, n2 - n1))
mob2.add_n_more_submobjects(max(0, n1 - n2))
@ -1169,9 +1175,10 @@ class Mobject(object):
curr = len(self.submobjects)
if curr == 0:
# If empty, simply add n point mobjects
center = self.get_center()
null_mob = self.copy()
null_mob.set_points([self.get_center()])
self.set_submobjects([
self.copy().set_points([center])
null_mob.copy()
for k in range(n)
])
return self
@ -1276,6 +1283,7 @@ class Mobject(object):
for mob in self.get_family():
func(mob)
mob.refresh_shader_wrapper_id()
return self
return wrapper
@affects_shader_info_id

View file

@ -1,5 +1,5 @@
from manimlib.constants import *
from manimlib.mobject.svg.tex_mobject import SingleStringTexMobject
from manimlib.mobject.svg.tex_mobject import SingleStringTex
from manimlib.mobject.svg.tex_mobject import tex_string_to_mob_map
from manimlib.mobject.svg.tex_mobject import SCALE_FACTOR_PER_FONT_POINT
from manimlib.mobject.types.vectorized_mobject import VMobject
@ -89,7 +89,7 @@ class DecimalNumber(VMobject):
return self.data["font_size"][0]
def string_to_mob(self, tex_string):
# Could just call SingleStringTexMobject, and there is
# Could just call SingleStringTex, and there is
# some code repetition here by looking to the same cache,
# but it keeps things from initializing a new object
# more than is necessary
@ -98,7 +98,7 @@ class DecimalNumber(VMobject):
result.scale(self.get_font_size() * SCALE_FACTOR_PER_FONT_POINT)
return result
else:
return SingleStringTexMobject(tex_string, font_size=self.get_font_size())
return SingleStringTex(tex_string, font_size=self.get_font_size())
def get_formatter(self, **kwargs):
"""

View file

@ -3,8 +3,8 @@ from manimlib.mobject.geometry import Line
from manimlib.mobject.geometry import Rectangle
from manimlib.mobject.mobject import Mobject
from manimlib.mobject.svg.brace import Brace
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import TextMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.svg.tex_mobject import TexText
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.utils.color import color_gradient
from manimlib.utils.iterables import listify
@ -26,7 +26,7 @@ class SampleSpace(Rectangle):
def add_title(self, title="Sample space", buff=MED_SMALL_BUFF):
# TODO, should this really exist in SampleSpaceScene
title_mob = TextMobject(title)
title_mob = TexText(title)
if title_mob.get_width() > self.get_width():
title_mob.set_width(self.get_width())
title_mob.next_to(self, UP, buff=buff)
@ -97,7 +97,7 @@ class SampleSpace(Rectangle):
if isinstance(label, Mobject):
label_mob = label
else:
label_mob = TexMobject(label)
label_mob = Tex(label)
label_mob.scale(self.default_label_scale_val)
label_mob.next_to(brace, direction, buff)
@ -188,7 +188,7 @@ class BarChart(VGroup):
if self.label_y_axis:
labels = VGroup()
for tick, value in zip(ticks, values):
label = TexMobject(str(np.round(value, 2)))
label = Tex(str(np.round(value, 2)))
label.set_height(self.y_axis_label_height)
label.next_to(tick, LEFT, SMALL_BUFF)
labels.add(label)
@ -211,7 +211,7 @@ class BarChart(VGroup):
bar_labels = VGroup()
for bar, name in zip(bars, self.bar_names):
label = TexMobject(str(name))
label = Tex(str(name))
label.scale(self.bar_label_scale_val)
label.next_to(bar, DOWN, SMALL_BUFF)
bar_labels.add(label)

View file

@ -4,14 +4,14 @@ from manimlib.animation.composition import AnimationGroup
from manimlib.constants import *
from manimlib.animation.fading import FadeIn
from manimlib.animation.growing import GrowFromCenter
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import TextMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.svg.tex_mobject import TexText
from manimlib.mobject.types.vectorized_mobject import VMobject
from manimlib.utils.config_ops import digest_config
from manimlib.utils.space_ops import get_norm
class Brace(TexMobject):
class Brace(Tex):
CONFIG = {
"buff": 0.2,
"width_multiplier": 2,
@ -34,7 +34,7 @@ class Brace(TexMobject):
self.min_num_quads, self.max_num_quads
)
tex_string = "\\underbrace{%s}" % (num_quads * "\\qquad")
TexMobject.__init__(self, tex_string, **kwargs)
Tex.__init__(self, tex_string, **kwargs)
self.tip_point_index = np.argmin(self.get_all_points()[:, 1])
self.stretch_to_fit_width(target_width)
self.shift(left - self.get_corner(UP + LEFT) + self.buff * DOWN)
@ -56,12 +56,12 @@ class Brace(TexMobject):
return self
def get_text(self, *text, **kwargs):
text_mob = TextMobject(*text)
text_mob = TexText(*text)
self.put_at_tip(text_mob, **kwargs)
return text_mob
def get_tex(self, *tex, **kwargs):
tex_mob = TexMobject(*tex)
tex_mob = Tex(*tex)
self.put_at_tip(tex_mob, **kwargs)
return tex_mob
@ -78,7 +78,7 @@ class Brace(TexMobject):
class BraceLabel(VMobject):
CONFIG = {
"label_constructor": TexMobject,
"label_constructor": Tex,
"label_scale": 1,
}
@ -135,5 +135,5 @@ class BraceLabel(VMobject):
class BraceText(BraceLabel):
CONFIG = {
"label_constructor": TextMobject
"label_constructor": TexText
}

View file

@ -9,8 +9,8 @@ from manimlib.mobject.geometry import Rectangle
from manimlib.mobject.geometry import Square
from manimlib.mobject.mobject import Mobject
from manimlib.mobject.svg.svg_mobject import SVGMobject
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import TextMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.svg.tex_mobject import TexText
from manimlib.mobject.three_dimensions import Cube
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.mobject.types.vectorized_mobject import VMobject
@ -21,7 +21,7 @@ from manimlib.utils.space_ops import complex_to_R3
from manimlib.utils.space_ops import rotate_vector
class Checkmark(TextMobject):
class Checkmark(TexText):
CONFIG = {
"color": GREEN
}
@ -30,7 +30,7 @@ class Checkmark(TextMobject):
super().__init__("\\ding{51}")
class Exmark(TextMobject):
class Exmark(TexText):
CONFIG = {
"color": RED
}
@ -71,7 +71,7 @@ class Speedometer(VMobject):
for index, angle in enumerate(tick_angle_range):
vect = rotate_vector(RIGHT, angle)
tick = Line((1 - self.tick_length) * vect, vect)
label = TexMobject(str(10 * index))
label = Tex(str(10 * index))
label.set_height(self.tick_length)
label.shift((1 + self.tick_length) * vect)
self.add(tick, label)
@ -365,7 +365,7 @@ class Bubble(SVGMobject):
return self.content
def write(self, *text):
self.add_content(TextMobject(*text))
self.add_content(TexText(*text))
return self
def resize_to_content(self):

View file

@ -20,7 +20,7 @@ SCALE_FACTOR_PER_FONT_POINT = 0.001
tex_string_to_mob_map = {}
class SingleStringTexMobject(VMobject):
class SingleStringTex(VMobject):
CONFIG = {
"fill_opacity": 1.0,
"stroke_width": 0,
@ -28,7 +28,7 @@ class SingleStringTexMobject(VMobject):
"font_size": 48,
"height": None,
"organize_left_to_right": False,
"alignment": "", # Could be "\\centering",
"alignment": "\\centering",
"math_mode": True,
}
@ -131,7 +131,7 @@ class SingleStringTexMobject(VMobject):
def balance_braces(self, tex):
"""
Makes TexMobject resiliant to unmatched { at start
Makes Tex resiliant to unmatched { at start
"""
num_lefts, num_rights = [tex.count(char) for char in "{}"]
while num_rights > num_lefts:
@ -150,7 +150,7 @@ class SingleStringTexMobject(VMobject):
return self
class TexMobject(SingleStringTexMobject):
class Tex(SingleStringTex):
CONFIG = {
"arg_separator": " ",
# Note, use of isolate is largely rendered
@ -205,7 +205,7 @@ class TexMobject(SingleStringTexMobject):
tex_string = tex_string.strip()
if len(tex_string) == 0:
continue
sub_tex_mob = SingleStringTexMobject(tex_string, **config)
sub_tex_mob = SingleStringTex(tex_string, **config)
num_submobs = len(sub_tex_mob)
if num_submobs == 0:
continue
@ -227,7 +227,7 @@ class TexMobject(SingleStringTexMobject):
return tex1 == tex2
return VGroup(*filter(
lambda m: isinstance(m, SingleStringTexMobject) and test(tex, m.get_tex()),
lambda m: isinstance(m, SingleStringTex) and test(tex, m.get_tex()),
self.submobjects
))
@ -271,14 +271,14 @@ class TexMobject(SingleStringTexMobject):
return self
class TextMobject(TexMobject):
class TexText(Tex):
CONFIG = {
"math_mode": False,
"arg_separator": "",
}
class BulletedList(TextMobject):
class BulletedList(TexText):
CONFIG = {
"buff": MED_LARGE_BUFF,
"dot_scale_factor": 2,
@ -287,9 +287,9 @@ class BulletedList(TextMobject):
def __init__(self, *items, **kwargs):
line_separated_items = [s + "\\\\" for s in items]
TextMobject.__init__(self, *line_separated_items, **kwargs)
TexText.__init__(self, *line_separated_items, **kwargs)
for part in self:
dot = TexMobject("\\cdot").scale(self.dot_scale_factor)
dot = Tex("\\cdot").scale(self.dot_scale_factor)
dot.next_to(part[0], LEFT, SMALL_BUFF)
part.add_to_back(dot)
self.arrange(
@ -313,7 +313,7 @@ class BulletedList(TextMobject):
other_part.set_fill(opacity=opacity)
class TexMobjectFromPresetString(TexMobject):
class TexFromPresetString(Tex):
CONFIG = {
# To be filled by subclasses
"tex": None,
@ -322,11 +322,11 @@ class TexMobjectFromPresetString(TexMobject):
def __init__(self, **kwargs):
digest_config(self, kwargs)
TexMobject.__init__(self, self.tex, **kwargs)
Tex.__init__(self, self.tex, **kwargs)
self.set_color(self.color)
class Title(TextMobject):
class Title(TexText):
CONFIG = {
"scale_factor": 1,
"include_underline": True,
@ -337,7 +337,7 @@ class Title(TextMobject):
}
def __init__(self, *text_parts, **kwargs):
TextMobject.__init__(self, *text_parts, **kwargs)
TexText.__init__(self, *text_parts, **kwargs)
self.scale(self.scale_factor)
self.to_edge(UP)
if self.include_underline:

View file

@ -4,7 +4,7 @@ import copy
import hashlib
import cairo
from manimlib.constants import *
from manimlib.mobject.geometry import Dot, Rectangle
from manimlib.mobject.geometry import Dot
from manimlib.mobject.svg.svg_mobject import SVGMobject
from manimlib.utils.config_ops import digest_config
from manimlib.utils.customization import get_customization

View file

@ -8,6 +8,8 @@ from manimlib.utils.iterables import resize_preserving_order
DEFAULT_DOT_CLOUD_RADIUS = 0.05
DEFAULT_GRID_HEIGHT = 6
DEFAULT_BUFF_RATIO = 0.5
class DotCloud(PMobject):
@ -34,36 +36,57 @@ class DotCloud(PMobject):
self.data["radii"] = np.zeros((1, 1))
self.set_radii(self.radii)
def set_points_by_grid(self, n_rows, n_cols, height=None, width=None):
# TODO, add buff/hbuff/vbuff args...
new_points = np.zeros((n_rows * n_cols, 3))
new_points[:, 0] = np.tile(range(n_cols), n_rows)
new_points[:, 1] = np.repeat(range(n_rows), n_cols)
new_points[:, 2] = 0
self.set_points(new_points)
def to_grid(self, n_rows, n_cols, n_layers=1,
buff_ratio=None,
h_buff_ratio=1.0,
v_buff_ratio=1.0,
d_buff_ratio=1.0,
height=DEFAULT_GRID_HEIGHT,
):
n_points = n_rows * n_cols * n_layers
points = np.repeat(range(n_points), 3, axis=0).reshape((n_points, 3))
points[:, 0] = points[:, 0] % n_cols
points[:, 1] = (points[:, 1] // n_cols) % n_rows
points[:, 2] = points[:, 2] // (n_rows * n_cols)
self.set_points(points.astype(float))
radius = self.data["radii"].max()
if height is None:
height = n_rows * 3 * radius
if width is None:
width = n_cols * 3 * radius
if buff_ratio is not None:
v_buff_ratio = buff_ratio
h_buff_ratio = buff_ratio
d_buff_ratio = buff_ratio
self.set_height(height, stretch=True)
self.set_width(width, stretch=True)
radius = self.get_radius()
ns = [n_cols, n_rows, n_layers]
brs = [h_buff_ratio, v_buff_ratio, d_buff_ratio]
for n, br, dim in zip(ns, brs, range(3)):
self.rescale_to_fit(2 * radius * (1 + br) * (n - 1), dim, stretch=True)
if height is not None:
self.set_height(height)
self.center()
return self
def set_radii(self, radii):
if not isinstance(radii, numbers.Number):
radii = resize_preserving_order(radii, self.get_num_points())
self.data["radii"][:, 0] = radii
radii = resize_preserving_order(radii, len(self.data["radii"]))
self.data["radii"][:] = radii
return self
def get_radii(self):
return self.data["radii"]
def get_radius(self):
return self.get_radii().max()
def scale(self, scale_factor, scale_radii=True, **kwargs):
super().scale(scale_factor, **kwargs)
if scale_radii:
self.data["radii"] *= scale_factor
self.set_radii(scale_factor * self.get_radii())
return self
def make_3d(self, gloss=0.5, shadow=0.2):
self.set_gloss(gloss)
self.set_shadow(shadow)
self.apply_depth_test()
return self
def get_shader_data(self):

View file

@ -816,10 +816,12 @@ class VMobject(Mobject):
@triggers_refreshed_triangulation
def set_points(self, points):
super().set_points(points)
return self
@triggers_refreshed_triangulation
def set_data(self, data):
super().set_data(data)
return self
# TODO, how to be smart about tangents here?
@triggers_refreshed_triangulation
@ -832,6 +834,7 @@ class VMobject(Mobject):
@triggers_refreshed_triangulation
def flip(self, *args, **kwargs):
super().flip(*args, **kwargs)
return self
# For shaders
def init_shader_data(self):

View file

@ -2,7 +2,7 @@ import numpy as np
from manimlib.animation.animation import Animation
from manimlib.constants import *
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.scene.scene import Scene
@ -66,7 +66,7 @@ class RearrangeEquation(Scene):
"""
num_start_terms = len(start_terms)
all_mobs = np.array(
TexMobject(start_terms).split() + TexMobject(end_terms).split())
Tex(start_terms).split() + Tex(end_terms).split())
all_terms = np.array(start_terms + end_terms)
for term in set(all_terms):
matches = all_terms == term
@ -86,7 +86,7 @@ class FlipThroughSymbols(Animation):
}
def __init__(self, tex_list, **kwargs):
mobject = TexMobject(self.curr_tex).shift(start_center)
mobject = Tex(self.curr_tex).shift(start_center)
Animation.__init__(self, mobject, **kwargs)
def interpolate_mobject(self, alpha):
@ -94,7 +94,7 @@ class FlipThroughSymbols(Animation):
if new_tex != self.curr_tex:
self.curr_tex = new_tex
self.mobject = TexMobject(new_tex).shift(self.start_center)
self.mobject = Tex(new_tex).shift(self.start_center)
if not all(self.start_center == self.end_center):
self.mobject.center().shift(
(1 - alpha) * self.start_center + alpha * self.end_center

View file

@ -1,6 +1,6 @@
from manimlib.constants import *
from manimlib.mobject.numbers import Integer
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.types.vectorized_mobject import VMobject, VGroup
from manimlib.scene.scene import Scene
from manimlib.utils.simple_functions import choose
@ -45,7 +45,7 @@ class CountingScene(Scene):
self.add(*mobjects)
for mob, num in zip(mobjects, it.count(1)):
if display_numbers:
num_mob = TexMobject(str(num))
num_mob = Tex(str(num))
num_mob.center().shift(num_offset)
self.add(num_mob)
if mode == "highlight":
@ -74,7 +74,7 @@ class CountingScene(Scene):
raise Warning("Unknown mode")
frame_time = run_time / (len(regions))
for region, count in zip(regions, it.count(1)):
num_mob = TexMobject(str(count))
num_mob = Tex(str(count))
num_mob.center().shift(num_offset)
self.add(num_mob)
self.set_color_region(region)
@ -113,7 +113,7 @@ class GeneralizedPascalsTriangle(VMobject):
]
for n, k in self.coords:
center = self.coords_to_center(n, k)
num_mob = self.submob_class(n, k) # TexMobject(str(num))
num_mob = self.submob_class(n, k) # Tex(str(num))
scale_factor = min(
1,
self.portion_to_fill * self.cell_height / num_mob.get_height(),
@ -137,7 +137,7 @@ class GeneralizedPascalsTriangle(VMobject):
def generate_n_choose_k_mobs(self):
self.coords_to_n_choose_k = {}
for n, k in self.coords:
nck_mob = TexMobject(r"{%d \choose %d}" % (n, k))
nck_mob = Tex(r"{%d \choose %d}" % (n, k))
scale_factor = min(
1,
self.portion_to_fill * self.cell_height / nck_mob.get_height(),
@ -161,7 +161,7 @@ class GeneralizedPascalsTriangle(VMobject):
return self
def generate_sea_of_zeros(self):
zero = TexMobject("0")
zero = Tex("0")
self.sea_of_zeros = []
for n in range(self.nrows):
for a in range((self.nrows - n) / 2 + 1):

View file

@ -6,7 +6,7 @@ from manimlib.constants import *
from manimlib.mobject.geometry import Arrow
from manimlib.mobject.geometry import Circle
from manimlib.mobject.geometry import Dot
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.scene.scene import Scene
@ -26,7 +26,7 @@ class CountingScene(Scene):
self.dots = VGroup()
self.number = 0
self.max_place = 0
self.number_mob = VGroup(TexMobject(str(self.number)))
self.number_mob = VGroup(Tex(str(self.number)))
self.number_mob.scale(self.num_scale_factor)
self.number_mob.shift(self.num_start_location)
@ -159,7 +159,7 @@ class CountingScene(Scene):
place = 0
max_place = self.max_place
while place < max_place:
digit = TexMobject(str(self.get_place_num(num, place)))
digit = Tex(str(self.get_place_num(num, place)))
if place >= len(self.digit_place_colors):
self.digit_place_colors += self.digit_place_colors
digit.set_color(self.digit_place_colors[place])

View file

@ -8,7 +8,7 @@ from manimlib.constants import *
from manimlib.mobject.geometry import Circle
from manimlib.mobject.geometry import Line
from manimlib.mobject.matrix import Matrix
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.scene.scene import Scene
@ -48,7 +48,7 @@ class NumericalMatrixMultiplication(Scene):
for c in range(k)
for prefix in ["" if c == 0 else "+"]
]
mob_matrix[a][b] = TexMobject(parts, next_to_buff=0.1)
mob_matrix[a][b] = Tex(parts, next_to_buff=0.1)
return Matrix(mob_matrix)
def add_lines(self, left, right):
@ -80,7 +80,7 @@ class NumericalMatrixMultiplication(Scene):
self.show_frame()
def organize_matrices(self, left, right, result):
equals = TexMobject("=")
equals = Tex("=")
everything = VGroup(left, right, equals, result)
everything.arrange()
everything.set_width(FRAME_WIDTH - 1)

View file

@ -9,8 +9,8 @@ from manimlib.mobject.geometry import Line
from manimlib.mobject.geometry import Rectangle
from manimlib.mobject.geometry import RegularPolygon
from manimlib.mobject.number_line import NumberLine
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import TextMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.svg.tex_mobject import TexText
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.mobject.types.vectorized_mobject import VectorizedPoint
from manimlib.scene.scene import Scene
@ -84,7 +84,7 @@ class GraphScene(Scene):
self.x_labeled_nums = [x for x in self.x_labeled_nums if x != 0]
x_axis.add_numbers(*self.x_labeled_nums)
if self.x_axis_label:
x_label = TextMobject(self.x_axis_label)
x_label = TexText(self.x_axis_label)
x_label.next_to(
x_axis.get_tick_marks(), UP + RIGHT,
buff=SMALL_BUFF
@ -118,7 +118,7 @@ class GraphScene(Scene):
self.y_labeled_nums = [y for y in self.y_labeled_nums if y != 0]
y_axis.add_numbers(*self.y_labeled_nums)
if self.y_axis_label:
y_label = TextMobject(self.y_axis_label)
y_label = TexText(self.y_axis_label)
y_label.next_to(
y_axis.get_corner(UP + RIGHT), UP + RIGHT,
buff=SMALL_BUFF
@ -201,7 +201,7 @@ class GraphScene(Scene):
buff=MED_SMALL_BUFF,
color=None,
):
label = TexMobject(label)
label = Tex(label)
color = color or graph.get_color()
label.set_color(color)
if x_val is None:
@ -395,11 +395,11 @@ class GraphScene(Scene):
labels = VGroup()
if dx_label is not None:
group.dx_label = TexMobject(dx_label)
group.dx_label = Tex(dx_label)
labels.add(group.dx_label)
group.add(group.dx_label)
if df_label is not None:
group.df_label = TexMobject(df_label)
group.df_label = Tex(df_label)
labels.add(group.df_label)
group.add(group.df_label)
@ -444,9 +444,9 @@ class GraphScene(Scene):
triangle.set_fill(color, 1)
triangle.set_stroke(width=0)
if label is None:
T_label = TexMobject(self.variable_point_label, fill_color=color)
T_label = Tex(self.variable_point_label, fill_color=color)
else:
T_label = TexMobject(label, fill_color=color)
T_label = Tex(label, fill_color=color)
T_label.next_to(triangle, DOWN)
v_line = self.get_vertical_line_to_graph(

View file

@ -118,9 +118,13 @@ class Scene(object):
shell = InteractiveShellEmbed()
# Have the frame update after each command
shell.events.register('post_run_cell', lambda *a, **kw: self.update_frame())
# Stack depth of 2 means the shell will use
# the namespace of the caller, not this method
shell(stack_depth=2)
# Use the locals of the caller as the local namespace
# once embeded, and add a few custom shortcuts
local_ns = inspect.currentframe().f_back.f_locals
local_ns["touch"] = self.interact
for term in ("play", "add", "remove", "clear"):
local_ns[term] = getattr(self, term)
shell(local_ns=local_ns, stack_depth=2)
# End scene when exiting an embed.
raise EndSceneEarlyException()
@ -510,13 +514,20 @@ class Scene(object):
# Event handling
def on_mouse_motion(self, point, d_point):
self.mouse_point.move_to(point)
def on_mouse_drag(self, point, d_point, buttons, modifiers):
self.mouse_drag_point.move_to(point)
frame = self.camera.frame
if self.window.is_key_pressed(ord("d")):
frame.increment_theta(-d_point[0])
frame.increment_phi(d_point[1])
elif self.window.is_key_pressed(ord("s")):
shift = -d_point
shift[0] *= frame.get_width() / 2
shift[1] *= frame.get_height() / 2
transform = frame.get_inverse_camera_rotation_matrix()
shift = np.dot(np.transpose(transform), shift)
frame.shift(shift)
def on_mouse_drag(self, point, d_point, buttons, modifiers):
self.mouse_drag_point.move_to(point)
def on_mouse_press(self, point, button, mods):
pass
@ -529,11 +540,10 @@ class Scene(object):
if self.window.is_key_pressed(ord("z")):
factor = 1 + np.arctan(10 * offset[1])
frame.scale(factor, about_point=point)
elif self.window.is_key_pressed(ord("s")):
transform = frame.get_inverse_camera_position_matrix()
shift = np.dot(transform[:3, :3].T, offset)
shift *= 10 * frame.get_height()
frame.shift(-shift)
else:
transform = frame.get_inverse_camera_rotation_matrix()
shift = np.dot(np.transpose(transform), offset)
frame.shift(-20.0 * shift)
def on_key_release(self, symbol, modifiers):
pass

View file

@ -20,8 +20,8 @@ from manimlib.mobject.matrix import Matrix
from manimlib.mobject.matrix import VECTOR_LABEL_SCALE_FACTOR
from manimlib.mobject.matrix import vector_coordinate_label
from manimlib.mobject.mobject import Mobject
from manimlib.mobject.svg.tex_mobject import TexMobject
from manimlib.mobject.svg.tex_mobject import TextMobject
from manimlib.mobject.svg.tex_mobject import Tex
from manimlib.mobject.svg.tex_mobject import TexText
from manimlib.mobject.types.vectorized_mobject import VGroup
from manimlib.mobject.types.vectorized_mobject import VMobject
from manimlib.scene.scene import Scene
@ -123,10 +123,10 @@ class VectorScene(Scene):
rotate=False,
color=None,
label_scale_factor=VECTOR_LABEL_SCALE_FACTOR):
if not isinstance(label, TexMobject):
if not isinstance(label, Tex):
if len(label) == 1:
label = "\\vec{\\textbf{%s}}" % label
label = TexMobject(label)
label = Tex(label)
if color is None:
color = vector.get_color()
label.set_color(color)
@ -419,7 +419,7 @@ class LinearTransformationScene(VectorScene):
def add_title(self, title, scale_factor=1.5, animate=False):
if not isinstance(title, Mobject):
title = TextMobject(title).scale(scale_factor)
title = TexText(title).scale(scale_factor)
title.to_edge(UP)
title.add_background_rectangle()
if animate:

View file

@ -1,10 +1,6 @@
#version 330
uniform vec2 frame_shape;
uniform float anti_alias_width;
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
uniform float focal_distance;
#INSERT camera_uniform_declarations.glsl
uniform sampler2D Texture;

View file

@ -0,0 +1,6 @@
uniform vec2 frame_shape;
uniform float anti_alias_width;
uniform vec3 camera_center;
uniform mat3 camera_rotation;
uniform float is_fixed_in_frame;
uniform float focal_distance;

View file

@ -1,9 +1,8 @@
// Assumes the following uniforms exist in the surrounding context:
// uniform mat4 to_screen_space;
// uniform vec3 camera_center;
// uniform mat3 camera_rotation;
vec3 get_rotated_surface_unit_normal_vector(vec3 point, vec3 du_point, vec3 dv_point){
// normal = get_unit_normal(point, du_point, dv_point);
// return normalize((to_screen_space * vec4(normal, 0.0)).xyz);
vec3 cp = cross(
(du_point - point),
(dv_point - point)
@ -13,6 +12,5 @@ vec3 get_rotated_surface_unit_normal_vector(vec3 point, vec3 du_point, vec3 dv_p
vec3 v2 = dv_point - point;
cp = cross(cross(v2, point), v2);
}
// The zero is deliberate, as we only want to rotate and not shift
return normalize((to_screen_space * vec4(cp, 0.0)).xyz);
return normalize(rotate_point_into_frame(cp));
}

View file

@ -1,12 +1,19 @@
// Assumes the following uniforms exist in the surrounding context:
// uniform mat4 to_screen_space;
// uniform float is_fixed_in_frame;
// uniform vec3 camera_center;
// uniform mat3 camera_rotation;
vec3 rotate_point_into_frame(vec3 point){
if(bool(is_fixed_in_frame)){
return point;
}
return camera_rotation * point;
}
vec3 position_point_into_frame(vec3 point){
if(bool(is_fixed_in_frame)){
return point;
}else{
// Simply apply the pre-computed to_screen_space matrix.
return (to_screen_space * vec4(point, 1)).xyz;
}
return rotate_point_into_frame(point - camera_center);
}

View file

@ -1,7 +1,6 @@
#version 330
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
#INSERT camera_uniform_declarations.glsl
in vec4 color;
in float fill_all; // Either 0 or 1e

View file

@ -1,7 +1,6 @@
#version 330
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
#INSERT camera_uniform_declarations.glsl
in vec3 point;
in vec3 unit_normal;
@ -18,7 +17,7 @@ out float v_vert_index;
void main(){
bp = position_point_into_frame(point);
v_global_unit_normal = normalize(to_screen_space * vec4(unit_normal, 0)).xyz;
v_global_unit_normal = rotate_point_into_frame(unit_normal);
v_color = color;
v_vert_index = vert_index;
}

View file

@ -1,8 +1,6 @@
#version 330
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
uniform vec3 light_source_position;
#INSERT camera_uniform_declarations.glsl
in vec2 uv_coords;
in vec2 uv_b2;

View file

@ -1,7 +1,6 @@
#version 330
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
#INSERT camera_uniform_declarations.glsl
in vec3 point;
in vec3 prev_point;
@ -28,7 +27,7 @@ void main(){
bp = position_point_into_frame(point);
prev_bp = position_point_into_frame(prev_point);
next_bp = position_point_into_frame(next_point);
v_global_unit_normal = normalize(to_screen_space * vec4(unit_normal, 0)).xyz;
v_global_unit_normal = rotate_point_into_frame(unit_normal);
v_stroke_width = STROKE_WIDTH_CONVERSION * stroke_width;
v_color = color;

View file

@ -1,10 +1,6 @@
#version 330
uniform vec2 frame_shape;
uniform float anti_alias_width;
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
uniform float focal_distance;
#INSERT camera_uniform_declarations.glsl
in vec3 point;

View file

@ -1,10 +1,6 @@
#version 330
uniform vec2 frame_shape;
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
uniform float focal_distance;
uniform vec3 light_source_position;
#INSERT camera_uniform_declarations.glsl
in vec3 point;
in vec3 du_point;

View file

@ -1,10 +1,6 @@
#version 330
uniform vec2 frame_shape;
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
uniform float focal_distance;
uniform vec3 light_source_position;
#INSERT camera_uniform_declarations.glsl
in vec3 point;
in vec3 du_point;

View file

@ -1,10 +1,6 @@
#version 330
uniform vec2 frame_shape;
uniform float anti_alias_width;
uniform mat4 to_screen_space;
uniform float is_fixed_in_frame;
uniform float focal_distance;
#INSERT camera_uniform_declarations.glsl
in vec3 point;
in float radius;

View file

@ -1,8 +1,10 @@
import moderngl_window as mglw
from moderngl_window.context.pyglet.window import Window as PygletWindow
from moderngl_window.timers.clock import Timer
from screeninfo import get_monitors
from manimlib.utils.config_ops import digest_config
from manimlib.utils.customization import get_customization
class Window(PygletWindow):
@ -18,16 +20,33 @@ class Window(PygletWindow):
digest_config(self, kwargs)
self.scene = scene
self.title = str(scene)
if "position" in kwargs:
self.position = kwargs["position"]
self.pressed_keys = set()
self.position = self.find_initial_position()
mglw.activate_context(window=self)
self.timer = Timer()
self.config = mglw.WindowConfig(ctx=self.ctx, wnd=self, timer=self.timer)
self.timer.start()
def find_initial_position(self):
custom_position = get_customization()["window_position"]
monitor = get_monitors()[0]
window_width, window_height = self.size
# Position might be specified with a string of the form
# x,y for integers x and y
if "," in custom_position:
return tuple(map(int, custom_position.split(",")))
# Alternatively, it might be specified with a string like
# UR, OO, DL, etc. specifiying what corner it should go to
char_to_n = {"L": 0, "U": 0, "O": 1, "R": 2, "D": 2}
width_diff = monitor.width - window_width
height_diff = monitor.height - window_height
return (
char_to_n[custom_position[1]] * width_diff // 2,
char_to_n[custom_position[0]] * height_diff // 2,
)
# Delegate event handling to scene
def pixel_coords_to_space_coords(self, px, py, relative=False):
return self.scene.camera.pixel_coords_to_space_coords(px, py, relative)