diff --git a/manimlib/files/Bubbles_speech.svg b/manimlib/files/Bubbles_speech.svg
new file mode 100644
index 00000000..173ebf35
--- /dev/null
+++ b/manimlib/files/Bubbles_speech.svg
@@ -0,0 +1,11 @@
+
+
+
diff --git a/manimlib/files/Bubbles_thought.svg b/manimlib/files/Bubbles_thought.svg
new file mode 100644
index 00000000..c77ebca4
--- /dev/null
+++ b/manimlib/files/Bubbles_thought.svg
@@ -0,0 +1,18 @@
+
+
+
diff --git a/manimlib/files/PiCreatures_plain.svg b/manimlib/files/PiCreatures_plain.svg
new file mode 100644
index 00000000..552043d6
--- /dev/null
+++ b/manimlib/files/PiCreatures_plain.svg
@@ -0,0 +1,24 @@
+
+
+
diff --git a/manimlib/scene/three_d_scene.py b/manimlib/scene/three_d_scene.py
index b0ba826f..1abe82c0 100644
--- a/manimlib/scene/three_d_scene.py
+++ b/manimlib/scene/three_d_scene.py
@@ -1,14 +1,26 @@
from manimlib.animation.transform import ApplyMethod
from manimlib.camera.three_d_camera import ThreeDCamera
-from manimlib.constants import *
+from manimlib.constants import DEGREES
+from manimlib.constants import PRODUCTION_QUALITY_FRAME_DURATION
from manimlib.continual_animation.update import ContinualGrowValue
+from manimlib.mobject.coordinate_systems import ThreeDAxes
+from manimlib.mobject.geometry import Line
+from manimlib.mobject.three_dimensions import Sphere
+from manimlib.mobject.types.vectorized_mobject import VGroup
+from manimlib.mobject.types.vectorized_mobject import VectorizedPoint
from manimlib.scene.scene import Scene
+from manimlib.utils.config_ops import digest_config
+from manimlib.utils.config_ops import merge_config
class ThreeDScene(Scene):
CONFIG = {
"camera_class": ThreeDCamera,
"ambient_camera_rotation": None,
+ "default_angled_camera_orientation_kwargs": {
+ "phi": 70 * DEGREES,
+ "theta": -135 * DEGREES,
+ }
}
def set_camera_orientation(self, phi=None, theta=None, distance=None, gamma=None):
@@ -21,7 +33,7 @@ class ThreeDScene(Scene):
if gamma is not None:
self.camera.set_gamma(gamma)
- def begin_ambient_camera_rotation(self, rate=0.05):
+ def begin_ambient_camera_rotation(self, rate=0.02):
self.ambient_camera_rotation = ContinualGrowValue(
self.camera.theta_tracker,
rate=rate
@@ -85,3 +97,90 @@ class ThreeDScene(Scene):
def remove_fixed_in_frame_mobjects(self, *mobjects):
self.camera.remove_fixed_in_frame_mobjects(*mobjects)
+
+ ##
+ def set_to_default_angled_camera_orientation(self, **kwargs):
+ config = dict(self.default_camera_orientation_kwargs)
+ config.update(kwargs)
+ self.set_camera_orientation(**config)
+
+
+class SpecialThreeDScene(ThreeDScene):
+ CONFIG = {
+ "cut_axes_at_radius": True,
+ "camera_config": {
+ "should_apply_shading": True,
+ "exponential_projection": True,
+ },
+ "three_d_axes_config": {
+ "num_axis_pieces": 1,
+ "number_line_config": {
+ "unit_size": 2,
+ "tick_frequency": 1,
+ "numbers_with_elongated_ticks": [0, 1, 2],
+ "stroke_width": 2,
+ }
+ },
+ "sphere_config": {
+ "radius": 2,
+ "resolution": (24, 48),
+ },
+ "default_angled_camera_position": {
+ "phi": 70 * DEGREES,
+ "theta": -110 * DEGREES,
+ },
+ # When scene is extracted with -l flag, this
+ # configuration will override the above configuration.
+ "low_quality_config": {
+ "camera_config": {
+ "should_apply_shading": False,
+ },
+ "three_d_axes_config": {
+ "num_axis_pieces": 1,
+ },
+ "sphere_config": {
+ "resolution": (12, 24),
+ }
+ }
+ }
+
+ def __init__(self, **kwargs):
+ digest_config(self, kwargs)
+ if self.frame_duration == PRODUCTION_QUALITY_FRAME_DURATION:
+ config = {}
+ else:
+ config = self.low_quality_config
+ ThreeDScene.__init__(self, **merge_config([kwargs, config]))
+
+ def get_axes(self):
+ axes = ThreeDAxes(**self.three_d_axes_config)
+ for axis in axes:
+ if self.cut_axes_at_radius:
+ p0 = axis.main_line.get_start()
+ p1 = axis.number_to_point(-1)
+ p2 = axis.number_to_point(1)
+ p3 = axis.main_line.get_end()
+ new_pieces = VGroup(
+ Line(p0, p1), Line(p1, p2), Line(p2, p3),
+ )
+ for piece in new_pieces:
+ piece.shade_in_3d = True
+ new_pieces.match_style(axis.pieces)
+ axis.pieces.submobjects = new_pieces.submobjects
+ for tick in axis.tick_marks:
+ tick.add(VectorizedPoint(
+ 1.5 * tick.get_center(),
+ ))
+ return axes
+
+ def get_sphere(self, **kwargs):
+ config = merge_config([kwargs, self.sphere_config])
+ return Sphere(**config)
+
+ def get_default_camera_position(self):
+ return self.default_angled_camera_position
+
+ def set_camera_to_default_position(self):
+ self.set_camera_orientation(
+ **self.default_angled_camera_position
+ )