Created
March 5, 2025 10:25
-
-
Save gastonmorixe/c56e63a1b2b8e4274a410110057c6beb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from manimlib import * | |
import random | |
class ShadowMappingIllustration(Scene): | |
def construct(self): | |
# ------------------------------------------------------------- | |
# INTRO TITLE | |
# ------------------------------------------------------------- | |
title = Text("Shadow Mapping: Two-Pass Technique") | |
title.scale(1.2) | |
title.to_edge(UP) | |
self.play(Write(title)) | |
self.wait() | |
intro_text = Text("A powerful real-time shadow technique", font_size=30) | |
intro_text.next_to(title, DOWN) | |
self.play(FadeIn(intro_text)) | |
self.wait(2) | |
self.play(FadeOut(intro_text)) | |
# ------------------------------------------------------------- | |
# SCENE SETUP (2D Conceptual) | |
# ------------------------------------------------------------- | |
# Light source (conceptually at top-left) | |
light_dot = Dot(LEFT * 4 + UP * 2, color=YELLOW) | |
light_label = Text("Light") | |
light_label.set_color(YELLOW) | |
light_label.next_to(light_dot, UP) | |
# Camera (conceptually at bottom-right) | |
camera_dot = Dot(RIGHT * 4 + DOWN, color=GREEN) | |
camera_label = Text("Camera") | |
camera_label.set_color(GREEN) | |
camera_label.next_to(camera_dot, DOWN) | |
# Ground plane line | |
ground_line = Line(LEFT * 6 + DOWN * 2, RIGHT * 6 + DOWN * 2).set_color(GREY) | |
# An object in the scene: a polygon | |
shape = Polygon( | |
np.array([-1, -1, 0]), | |
np.array([-1.5, 0, 0]), | |
np.array([-0.5, 1, 0]), | |
np.array([0.5, 1, 0]), | |
np.array([1, -0.5, 0]), | |
color=BLUE, | |
) | |
shape.set_fill(BLUE, opacity=0.4) | |
# Put everything on screen | |
self.play( | |
FadeIn(light_dot), | |
FadeIn(light_label), | |
FadeIn(camera_dot), | |
FadeIn(camera_label), | |
ShowCreation(ground_line), | |
ShowCreation(shape), | |
) | |
self.wait() | |
# ------------------------------------------------------------- | |
# THE PROBLEM OF SHADOWS (Introduction) | |
# ------------------------------------------------------------- | |
prob_title = Text("The Challenge of Shadow Generation") | |
prob_title.scale(0.8) | |
prob_title.to_edge(UP).shift(DOWN * 0.8) | |
self.play(ReplacementTransform(title, prob_title)) | |
self.wait() | |
# Add shadow line explanation | |
problem_text = Text( | |
"How do we determine which points are in shadow?", font_size=24 | |
) | |
problem_text.to_corner(UL).shift(DOWN * 2.5 + RIGHT * 1.5) | |
self.play(Write(problem_text)) | |
self.wait() | |
# Show the core shadow question | |
light_ray1 = Arrow( | |
light_dot.get_center(), shape.get_center(), buff=0.1, color=YELLOW | |
) | |
light_ray2 = DashedLine( | |
shape.get_center(), | |
ground_line.point_from_proportion(0.7), | |
color=YELLOW_D, | |
dash_length=0.1, | |
) | |
shadow_point = Dot(ground_line.point_from_proportion(0.7), color=RED) | |
self.play(ShowCreation(light_ray1)) | |
self.play(ShowCreation(light_ray2), FadeIn(shadow_point)) | |
shadow_q = Text("Is this point in shadow?", font_size=24, color=RED) | |
shadow_q.next_to(shadow_point, DOWN) | |
self.play(Write(shadow_q)) | |
self.wait(2) | |
# Clean up | |
self.play( | |
FadeOut(shadow_q), | |
FadeOut(light_ray1), | |
FadeOut(light_ray2), | |
FadeOut(shadow_point), | |
FadeOut(problem_text), | |
) | |
# ------------------------------------------------------------- | |
# STEP 1: RENDER FROM LIGHT'S PERSPECTIVE (Shadow Map Creation) | |
# ------------------------------------------------------------- | |
step1_title = Text("Step 1: Render from Light's Perspective") | |
step1_title.scale(0.8) | |
step1_title.to_edge(UP).shift(DOWN * 0.8) | |
self.play(ReplacementTransform(prob_title, step1_title)) | |
self.wait() | |
# We'll create an arrow showing the light's viewpoint | |
light_view_arrow = Arrow( | |
start=light_dot.get_center() + RIGHT * 0.5, | |
end=shape.get_center(), | |
buff=0, | |
color=YELLOW, | |
) | |
light_view_label = Text("Light View") | |
light_view_label.scale(0.7) | |
light_view_label.set_color(YELLOW) | |
light_view_label.next_to(light_view_arrow, UP) | |
self.play(ShowCreation(light_view_arrow), FadeIn(light_view_label)) | |
self.wait() | |
# Mathematical explanation of light space transform | |
light_matrix = Tex(r"M_{light} = P_{light} \cdot V_{light}") | |
light_matrix.scale(0.7) | |
light_matrix.to_corner(UR) | |
light_matrix.shift(LEFT * 2 + DOWN * 0.5) | |
self.play(FadeIn(light_matrix)) | |
self.wait() | |
# Show a "Depth Map" box on the side | |
shadow_map_box = Rectangle(width=2.5, height=2, color=WHITE) | |
shadow_map_box.shift(LEFT * 3.5 + DOWN * 2.5) | |
shadow_map_label = Text("Shadow Map\n(Depth Texture)") | |
shadow_map_label.scale(0.6) | |
shadow_map_label.move_to(shadow_map_box.get_center()) | |
self.play(ShowCreation(shadow_map_box), FadeIn(shadow_map_label)) | |
self.wait() | |
# Conceptual arrow: "Scene -> Depth Map" | |
arrow_to_shadowmap = Arrow( | |
start=shape.get_center() + DOWN * 0.5, | |
end=shadow_map_box.get_top(), | |
buff=0.1, | |
color=WHITE, | |
) | |
self.play(ShowCreation(arrow_to_shadowmap)) | |
self.wait() | |
# Describe the depth map mathematically | |
depth_eq = Tex(r"depth(x,y) = z_{light}") | |
depth_eq.scale(0.6) | |
depth_eq.next_to(shadow_map_box, DOWN) | |
self.play(Write(depth_eq)) | |
self.wait(2) | |
# ------------------------------------------------------------- | |
# STEP 2: RENDER FROM CAMERA & DEPTH COMPARISON | |
# ------------------------------------------------------------- | |
step2_title = Text("Step 2: Render from Camera & Compare Depth") | |
step2_title.scale(0.8) | |
step2_title.to_edge(UP).shift(DOWN * 0.8) | |
self.play(ReplacementTransform(step1_title, step2_title)) | |
self.wait() | |
# Indicate camera's perspective | |
camera_view_arrow = Arrow( | |
start=camera_dot.get_center() + LEFT * 0.5, | |
end=shape.get_center(), | |
buff=0, | |
color=GREEN, | |
) | |
camera_view_label = Text("Camera View") | |
camera_view_label.scale(0.7) | |
camera_view_label.set_color(GREEN) | |
camera_view_label.next_to(camera_view_arrow, DOWN) | |
self.play(ShowCreation(camera_view_arrow), FadeIn(camera_view_label)) | |
self.wait() | |
# Add a "depth compare" label | |
compare_label = Text("Compare fragment depth\nwith Shadow Map depth") | |
compare_label.scale(0.7) | |
compare_label.next_to(shadow_map_box, RIGHT, buff=0.5).shift(UP * 0.3) | |
self.play(FadeIn(compare_label)) | |
self.wait() | |
# Mathematical formula for the comparison | |
compare_eq = Tex( | |
r"\text{is\_shadowed} = \begin{cases} true & \text{if } depth_{current} > depth_{map} \\ false & \text{otherwise} \end{cases}" | |
) | |
compare_eq.scale(0.6) | |
compare_eq.next_to(compare_label, DOWN, buff=0.5) | |
self.play(Write(compare_eq)) | |
self.wait() | |
# A final "Shadowed" region (conceptual) | |
shadow_region = Polygon( | |
np.array([0.5, -2, 0]), | |
np.array([2, -2, 0]), | |
np.array([2, -1, 0]), | |
np.array([0.5, -1, 0]), | |
color=BLACK, | |
) | |
shadow_region.set_fill(BLACK, opacity=0.4) | |
self.play(FadeIn(shadow_region)) | |
self.wait() | |
# ------------------------------------------------------------- | |
# TRANSITION TO 3D | |
# ------------------------------------------------------------- | |
transition_title = Text("From 2D to 3D") | |
transition_title.scale(0.8) | |
transition_title.to_edge(UP).shift(DOWN * 0.8) | |
self.play( | |
ReplacementTransform(step2_title, transition_title), | |
FadeOut(light_matrix), | |
FadeOut(depth_eq), | |
FadeOut(compare_eq), | |
FadeOut(compare_label), | |
FadeOut(camera_view_label), | |
FadeOut(camera_view_arrow), | |
FadeOut(light_view_label), | |
FadeOut(light_view_arrow), | |
FadeOut(arrow_to_shadowmap), | |
FadeOut(shadow_map_label), | |
FadeOut(shadow_map_box), | |
FadeOut(shadow_region), | |
) | |
self.wait() | |
transition_text = Text("Moving to a full 3D implementation...") | |
transition_text.scale(0.7) | |
transition_text.next_to(transition_title, DOWN) | |
self.play(Write(transition_text)) | |
self.wait(2) | |
# Fade out 2D elements | |
self.play( | |
FadeOut(light_dot), | |
FadeOut(light_label), | |
FadeOut(camera_dot), | |
FadeOut(camera_label), | |
FadeOut(ground_line), | |
FadeOut(shape), | |
FadeOut(transition_text), | |
) | |
self.wait() | |
# Final text to transition to next scene | |
next_scene = Text("Next: 3D Shadow Mapping Implementation") | |
next_scene.scale(0.9) | |
self.play(ReplacementTransform(transition_title, next_scene)) | |
self.wait(2) | |
self.play(FadeOut(next_scene)) | |
self.wait() | |
class ShadowMapping3D(Scene): | |
def construct(self): | |
# Set up the scene | |
title = Text("3D Shadow Mapping") | |
title.to_edge(UP) | |
self.play(Write(title)) | |
self.wait() | |
# Create a more advanced 3D demonstration using perspective drawings | |
# -------------------------------- | |
# STEP 1: SHOW THE BASIC 3D SETUP | |
# -------------------------------- | |
# Create a perspective grid to represent 3D space | |
grid_h_lines = VGroup( | |
*[ | |
Line( | |
LEFT * 5 + UP * (i * 0.5 - 2), | |
RIGHT * 5 + UP * (i * 0.5 - 2), | |
stroke_width=1, | |
color=GREY, | |
) | |
for i in range(9) | |
] | |
) | |
grid_v_lines = VGroup( | |
*[ | |
Line( | |
LEFT * (i - 5) + UP * 2, | |
LEFT * (i - 5) + DOWN * 2, | |
stroke_width=1, | |
color=GREY, | |
) | |
for i in range(11) | |
] | |
) | |
# Create a ground plane with perspective | |
ground_corners = [ | |
LEFT * 4 + DOWN * 2, # Bottom left | |
RIGHT * 4 + DOWN * 2, # Bottom right | |
RIGHT * 4 + DOWN * 1, # Top right (perspective) | |
LEFT * 4 + DOWN * 1, # Top left (perspective) | |
] | |
ground = Polygon( | |
*ground_corners, fill_color=GREY, fill_opacity=0.3, stroke_color=GREY | |
) | |
# Add axes labels for clarity | |
x_axis = Arrow(ORIGIN, RIGHT * 3, color=RED) | |
y_axis = Arrow(ORIGIN, UP * 2, color=GREEN) | |
z_axis = Arrow(ORIGIN, OUT * 2 + LEFT * 1, buff=0, color=BLUE) # Perspective | |
axes_labels = VGroup( | |
Text("X", font_size=24, color=RED).next_to(x_axis, RIGHT), | |
Text("Y", font_size=24, color=GREEN).next_to(y_axis, UP), | |
Text("Z", font_size=24, color=BLUE).next_to( | |
z_axis.get_end(), LEFT, buff=0.1 | |
), | |
) | |
# Create 3D objects | |
# Cube (drawn with perspective) | |
cube_center = LEFT * 2 + UP * 0 | |
cube_size = 1.2 | |
cube_corners = [ | |
# Front face (closer to viewer) | |
cube_center + LEFT * cube_size / 2 + DOWN * cube_size / 2, | |
cube_center + RIGHT * cube_size / 2 + DOWN * cube_size / 2, | |
cube_center + RIGHT * cube_size / 2 + UP * cube_size / 2, | |
cube_center + LEFT * cube_size / 2 + UP * cube_size / 2, | |
# Back face (with perspective - smaller and shifted) | |
cube_center | |
+ LEFT * cube_size / 2.5 | |
+ DOWN * cube_size / 2.5 | |
+ OUT * cube_size / 1.2, | |
cube_center | |
+ RIGHT * cube_size / 2.5 | |
+ DOWN * cube_size / 2.5 | |
+ OUT * cube_size / 1.2, | |
cube_center | |
+ RIGHT * cube_size / 2.5 | |
+ UP * cube_size / 2.5 | |
+ OUT * cube_size / 1.2, | |
cube_center | |
+ LEFT * cube_size / 2.5 | |
+ UP * cube_size / 2.5 | |
+ OUT * cube_size / 1.2, | |
] | |
# Draw cube faces | |
cube_front = Polygon( | |
cube_corners[0], | |
cube_corners[1], | |
cube_corners[2], | |
cube_corners[3], | |
fill_color=BLUE, | |
fill_opacity=0.5, | |
stroke_color=BLUE_E, | |
) | |
cube_top = Polygon( | |
cube_corners[3], | |
cube_corners[2], | |
cube_corners[6], | |
cube_corners[7], | |
fill_color=BLUE_D, | |
fill_opacity=0.6, | |
stroke_color=BLUE_E, | |
) | |
cube_right = Polygon( | |
cube_corners[1], | |
cube_corners[5], | |
cube_corners[6], | |
cube_corners[2], | |
fill_color=BLUE_A, | |
fill_opacity=0.4, | |
stroke_color=BLUE_E, | |
) | |
cube = VGroup(cube_front, cube_top, cube_right) | |
# Sphere (represented by circle with shading) | |
sphere_center = RIGHT * 2.5 + UP * 0.5 | |
sphere = Circle( | |
radius=0.8, fill_color=RED, fill_opacity=0.6, stroke_color=RED_E | |
) | |
sphere.move_to(sphere_center) | |
# Add a dot in the center and a line to the ground to show 3D position | |
sphere_center_dot = Dot(sphere_center, color=RED_E) | |
sphere_ground_line = DashedLine( | |
sphere_center, | |
[sphere_center[0], sphere_center[1] - 1.5, 0], | |
color=GREY, | |
dash_length=0.1, | |
) | |
# Light source (positioned at upper left with perspective) | |
light_pos = LEFT * 3.5 + UP * 3 + OUT * 2 | |
light = Dot(light_pos, color=YELLOW, radius=0.2) | |
light_glow = Circle( | |
radius=0.4, fill_color=YELLOW, fill_opacity=0.3, stroke_width=0 | |
) | |
light_glow.move_to(light_pos) | |
light_label = Text("Light Source", font_size=24, color=YELLOW) | |
light_label.next_to(light_glow, UP) | |
# Camera (positioned at lower right with perspective) | |
camera_pos = RIGHT * 4 + UP * 1.5 + OUT * 1 | |
camera = Dot(camera_pos, color=GREEN, radius=0.15) | |
camera_body = ( | |
Triangle( | |
stroke_color=GREEN, stroke_width=2, fill_color=GREEN, fill_opacity=0.4 | |
) | |
.scale(0.4) | |
.rotate(45 * DEGREES) | |
) | |
camera_body.move_to(camera_pos) | |
camera_label = Text("Camera", font_size=24, color=GREEN) | |
camera_label.next_to(camera_body, RIGHT) | |
# Add 3D setup elements to scene | |
self.play( | |
ShowCreation(grid_h_lines), ShowCreation(grid_v_lines), ShowCreation(ground) | |
) | |
self.wait(0.5) | |
self.play( | |
ShowCreation(x_axis), | |
ShowCreation(y_axis), | |
ShowCreation(z_axis), | |
Write(axes_labels), | |
) | |
self.wait() | |
# Animate 3D objects appearing | |
self.play(ShowCreation(cube)) | |
self.play( | |
ShowCreation(sphere), | |
ShowCreation(sphere_center_dot), | |
ShowCreation(sphere_ground_line), | |
) | |
self.wait() | |
# Add light and camera | |
self.play(FadeIn(light), FadeIn(light_glow), Write(light_label)) | |
self.play(FadeIn(camera), FadeIn(camera_body), Write(camera_label)) | |
self.wait(2) | |
# Explain the setup | |
setup_title = Text("3D Scene Setup with Light and Camera", font_size=30) | |
setup_title.next_to(title, DOWN) | |
self.play(Write(setup_title)) | |
self.wait(2) | |
# ------------------------------------------- | |
# STEP 2: TRANSITION TO LIGHT'S PERSPECTIVE | |
# ------------------------------------------- | |
# Create a "light POV" frame that we'll transition to | |
light_pov_frame = Rectangle( | |
width=7, height=5, stroke_color=YELLOW, stroke_width=3 | |
) | |
light_pov_frame.to_edge(DOWN, buff=0.5) | |
light_pov_label = Text("Light's Perspective", color=YELLOW, font_size=28) | |
light_pov_label.next_to(light_pov_frame, UP) | |
step1_text = Text("Step 1: Render from Light's Perspective", font_size=28) | |
step1_text.next_to(title, DOWN) | |
self.play( | |
ReplacementTransform(setup_title, step1_text), | |
ShowCreation(light_pov_frame), | |
Write(light_pov_label), | |
) | |
self.wait() | |
# Draw rays from light to objects to show what the light "sees" | |
light_ray1 = Arrow(light_pos, cube_center, color=YELLOW, buff=0.1) | |
light_ray2 = Arrow(light_pos, sphere_center, color=YELLOW, buff=0.1) | |
self.play(ShowCreation(light_ray1), ShowCreation(light_ray2)) | |
self.wait() | |
# Create a "light view" of the scene (simplified for clarity) | |
light_view_cube = Square( | |
side_length=0.8, stroke_color=BLUE, fill_color=BLUE, fill_opacity=0.5 | |
) | |
light_view_sphere = Circle( | |
radius=0.5, stroke_color=RED, fill_color=RED, fill_opacity=0.5 | |
) | |
# Position light view objects | |
light_view_cube.move_to(light_pov_frame.get_center() + LEFT * 1.5 + DOWN * 0.5) | |
light_view_sphere.move_to(light_pov_frame.get_center() + RIGHT * 1.5 + UP * 0.5) | |
# Create a depth buffer visualization | |
depth_label = Text("Depth Values", font_size=20, color=YELLOW) | |
depth_label.move_to(light_pov_frame.get_top() + DOWN * 0.5) | |
depth_values = VGroup( | |
Tex("d_{cube} = 4.2", color=BLUE), Tex("d_{sphere} = 5.7", color=RED) | |
).arrange(RIGHT, buff=1) | |
depth_values.next_to(depth_label, DOWN) | |
# Animate the light view appearing in the frame | |
self.play(FadeIn(light_view_cube), FadeIn(light_view_sphere)) | |
self.play(Write(depth_label), Write(depth_values)) | |
self.wait(2) | |
# Create a "shadow map" texture | |
shadow_map = Rectangle(width=2, height=1.5) | |
shadow_map.set_fill(BLACK, opacity=0.2) | |
shadow_map.set_stroke(YELLOW) | |
shadow_map.to_corner(UL).shift(DOWN + RIGHT) | |
shadow_map_label = Text("Shadow Map\n(Depth Texture)", font_size=20) | |
shadow_map_label.next_to(shadow_map, DOWN) | |
# Create visualization of shadow map with depth values | |
# Using a more basic approach since ImageMobject might not be available | |
shadow_map_viz = Rectangle( | |
width=shadow_map.get_width() * 0.9, height=shadow_map.get_height() * 0.9 | |
) | |
shadow_map_viz.set_fill(color=GREY_E, opacity=0.8) | |
shadow_map_viz.move_to(shadow_map) | |
# Add some dots to represent depth values | |
depth_dots = VGroup( | |
*[ | |
Dot( | |
shadow_map_viz.get_center() | |
+ np.array( | |
[random.uniform(-0.7, 0.7), random.uniform(-0.5, 0.5), 0] | |
), | |
radius=0.03, | |
color=GREY_D, | |
) | |
for _ in range(20) | |
] | |
) | |
self.play( | |
ShowCreation(shadow_map), | |
FadeIn(shadow_map_viz), | |
*[FadeIn(dot) for dot in depth_dots], | |
Write(shadow_map_label), | |
) | |
self.wait(2) | |
# ---------------------------------------- | |
# STEP 3: CAMERA PERSPECTIVE AND COMPARISON | |
# ---------------------------------------- | |
step2_text = Text("Step 2: Render from Camera's Perspective", font_size=28) | |
step2_text.next_to(title, DOWN) | |
# Create camera POV frame similar to light POV | |
camera_pov_frame = Rectangle( | |
width=7, height=5, stroke_color=GREEN, stroke_width=3 | |
) | |
camera_pov_frame.to_edge(DOWN, buff=0.5) | |
camera_pov_label = Text("Camera's Perspective", color=GREEN, font_size=28) | |
camera_pov_label.next_to(camera_pov_frame, UP) | |
self.play( | |
ReplacementTransform(step1_text, step2_text), | |
ReplacementTransform(light_pov_frame, camera_pov_frame), | |
ReplacementTransform(light_pov_label, camera_pov_label), | |
FadeOut(light_view_cube), | |
FadeOut(light_view_sphere), | |
FadeOut(depth_label), | |
FadeOut(depth_values), | |
) | |
self.wait() | |
# Draw rays from camera to objects | |
camera_ray1 = Arrow(camera_pos, cube_center, color=GREEN, buff=0.1) | |
camera_ray2 = Arrow(camera_pos, sphere_center, color=GREEN, buff=0.1) | |
self.play(ShowCreation(camera_ray1), ShowCreation(camera_ray2)) | |
self.wait() | |
# Create camera view objects | |
camera_view_cube = Square( | |
side_length=1, stroke_color=BLUE, fill_color=BLUE, fill_opacity=0.5 | |
) | |
camera_view_sphere = Circle( | |
radius=0.65, stroke_color=RED, fill_color=RED, fill_opacity=0.5 | |
) | |
# Position camera view objects | |
camera_view_cube.move_to(camera_pov_frame.get_center() + LEFT * 2) | |
camera_view_sphere.move_to(camera_pov_frame.get_center() + RIGHT * 1.5) | |
self.play(FadeIn(camera_view_cube), FadeIn(camera_view_sphere)) | |
self.wait() | |
# ------------------------------------------- | |
# STEP 4: SHADOW COMPARISON AND CALCULATION | |
# ------------------------------------------- | |
step3_text = Text("Step 3: Compare Depths to Determine Shadows", font_size=28) | |
step3_text.next_to(title, DOWN) | |
self.play(ReplacementTransform(step2_text, step3_text)) | |
self.wait() | |
# Create shadow rays to show shadow projection | |
shadow_ray1 = DashedLine( | |
cube_center, | |
[cube_center[0] * 1.2, cube_center[1] * 1.2, -2], | |
color=YELLOW_E, | |
dash_length=0.1, | |
) | |
shadow_ray2 = DashedLine( | |
sphere_center, | |
[sphere_center[0] * 1.1, sphere_center[1] * 1.1, -2], | |
color=YELLOW_E, | |
dash_length=0.1, | |
) | |
self.play(ShowCreation(shadow_ray1), ShowCreation(shadow_ray2)) | |
self.wait() | |
# Create shadows on the ground | |
shadow1 = Square( | |
side_length=1, fill_color=BLACK, fill_opacity=0.6, stroke_width=0 | |
) | |
shadow1.move_to([cube_center[0] * 1.2, cube_center[1] * 1.2, -1.95]) | |
shadow1.stretch(0.2, 1) # Flatten to look like it's on the ground | |
shadow2 = Circle(radius=0.6, fill_color=BLACK, fill_opacity=0.6, stroke_width=0) | |
shadow2.move_to([sphere_center[0] * 1.1, sphere_center[1] * 1.1, -1.95]) | |
shadow2.stretch(0.15, 1) # Flatten to look like it's on the ground | |
self.play(FadeIn(shadow1), FadeIn(shadow2)) | |
self.wait(2) | |
# Explain the shadow comparison process | |
comparison_text = VGroup( | |
Text("For each fragment in camera view:", font_size=22), | |
Text("1. Transform to light space", font_size=22), | |
Text("2. Compare with stored depth", font_size=22), | |
Text("3. If fragment's depth > stored depth → shadow", font_size=22), | |
).arrange(DOWN, aligned_edge=LEFT, buff=0.3) | |
comparison_text.next_to(camera_pov_frame, RIGHT).shift(UP) | |
self.play(Write(comparison_text), run_time=3) | |
self.wait(2) | |
# Show comparison example for a specific point | |
point_in_shadow = Dot(camera_view_sphere.get_center() + DOWN * 0.3, color=RED) | |
point_transform_eq = Tex(r"P_{light} = M_{light} \cdot P_{world}", font_size=26) | |
point_transform_eq.next_to(comparison_text, DOWN, buff=0.5) | |
depth_compare_eq = Tex(r"6.2 > 5.7 \Rightarrow \text{in shadow}", font_size=26) | |
depth_compare_eq.next_to(point_transform_eq, DOWN, buff=0.3) | |
depth_compare_eq.set_color(RED) | |
self.play(FadeIn(point_in_shadow), Write(point_transform_eq)) | |
self.wait() | |
self.play(Write(depth_compare_eq)) | |
self.wait(2) | |
# Apply shadowing to the camera view | |
camera_view_shadow = Circle( | |
radius=0.65, fill_color=BLACK, fill_opacity=0.7, stroke_width=0 | |
) | |
camera_view_shadow.move_to(camera_view_sphere.get_center()) | |
camera_view_shadow.scale(0.8) # Slightly smaller to show edge | |
self.play(FadeIn(camera_view_shadow)) | |
self.wait(2) | |
# ----------------------- | |
# CONCLUSION | |
# ----------------------- | |
conclusion_text = Text( | |
"Shadow Mapping: Dynamic Shadow Generation in Real-time", font_size=28 | |
) | |
conclusion_text.to_edge(DOWN) | |
self.play(Write(conclusion_text)) | |
self.wait(2) | |
# Final fade out | |
self.play(*[FadeOut(mob) for mob in self.mobjects]) | |
self.wait() | |
class CompleteDemo(Scene): | |
def construct(self): | |
title = Text("Advanced Shadow Mapping Techniques") | |
title.scale(1.2) | |
self.play(Write(title)) | |
self.wait() | |
# Create techniques text more manually since we need to avoid VGroup | |
advanced_techniques = [ | |
Text("• Percentage Closer Filtering (PCF)", font_size=30), | |
Text("• Variance Shadow Maps (VSM)", font_size=30), | |
Text("• Cascaded Shadow Maps (CSM)", font_size=30), | |
Text("• Moment Shadow Mapping", font_size=30), | |
Text("• Screen Space Shadows", font_size=30), | |
] | |
# Position the texts manually | |
for i, text in enumerate(advanced_techniques): | |
text.move_to(UP * (1.5 - i * 0.7)) | |
text.align_to(LEFT * 3, LEFT) | |
# Fade in each technique | |
for technique in advanced_techniques: | |
self.play(FadeIn(technique)) | |
self.wait(0.5) | |
self.wait() | |
# Show some benefits | |
benefits = Text( | |
"Benefits:\n" | |
+ "• Reduced shadow acne\n" | |
+ "• Better quality soft shadows\n" | |
+ "• More efficient for large scenes\n" | |
+ "• Higher quality at screen edges", | |
font_size=24, | |
) | |
benefits.to_corner(DR) | |
self.play(Write(benefits)) | |
self.wait(2) | |
# Final thank you | |
thanks = Text("Thank you for watching!") | |
thanks.scale(1.5) | |
self.play( | |
FadeOut(title), | |
*[FadeOut(tech) for tech in advanced_techniques], | |
FadeOut(benefits), | |
run_time=1, | |
) | |
self.play(Write(thanks)) | |
self.wait(2) | |
self.play(FadeOut(thanks)) | |
self.wait() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment