Example Gallery - 62firelight/manimRT-490 GitHub Wiki
This gallery is a collection of the scenes that I created to demonstrate ManimRT's capabilities during development. These are not meant to be the neatest images or animations (in terms of visual appeal and coding style), but will hopefully be useful as a starting point for different scenes. Feel free to use them as a template.
Camera and Ray
from manim import *
from manim_rt import *
class CameraAndRay(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=-45*DEGREES, frame_center=[0, 0, 0.25], zoom=5.5)
camera = RTCamera([0, 0, 1], focal_length=1)
red_ray = camera.draw_ray(8, 5, color=RED, length=1.75, thickness=0.005)
self.add(camera, red_ray)
Ray-Sphere Intersection
from manim import *
from manim_rt import *
class RaySphereIntersection(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=75 * DEGREES, theta=-95 * DEGREES)
axes = ThreeDAxes()
red_ray = Ray3D([-3, 0, 0], RIGHT, 5, color=RED)
sphere = RTSphere(color=BLUE)
hit_points = sphere.get_intersection(red_ray)
for hit_point in hit_points:
hit_point_obj = Dot3D(hit_point)
self.add(hit_point_obj)
self.add(axes, red_ray, sphere)
Ray-Sphere Intersections (Transformed Sphere)
from manim import *
from manim_rt import *
class RaySphereIntersectionTransformed(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=75 * DEGREES, theta=-90 * DEGREES)
axes = ThreeDAxes()
x_label = MathTex("x").next_to(axes.get_x_axis().get_end(), buff=0.25).shift([-0.5, 0.5, 0])
z_label = MathTex("z").next_to(axes.get_z_axis().get_end(), buff=0.25).shift([0, 3, 0])
red_ray = Ray3D([-4, 0, 0], RIGHT, 8, color=RED)
camera = RTCamera([-4, 1.75, 0], image_width=3, image_height=3).rotate(90*DEGREES, RIGHT).rotate(90*DEGREES, IN)
sphere = RTSphere([0, 0, 0], x_scale=2, y_scale=2, z_scale=2)
sphere.set_color(BLUE)
hit_points = sphere.get_intersection(red_ray)
intersections_text = VGroup()
intersections_text = VGroup(Tex("\\textbf{Hit Points}"), MathTex("(-2, 0, 0)"), MathTex("(2, 0, 0)"))
for hit_point in hit_points:
hit_point_obj = Dot3D(hit_point)
self.add(hit_point_obj)
intersections_text.arrange(DOWN).to_corner(DR, buff=1.5).scale(1.45).shift([0, -0.35, 0])
sphere_text = VGroup(Tex("\\textbf{Sphere at Origin}"), Tex("Radius is 2")).set_color(BLUE).arrange(DOWN).to_corner(UR, buff=1.5).scale(1.45).shift([0.25, 0.5, 0])
hit_point_normal = hit_points[0]
red_ray_equation = MathTex(red_ray.get_equation(), color=RED).scale(1.25)
equations = VGroup(red_ray_equation).arrange(DOWN, center=False, aligned_edge=LEFT).to_edge(LEFT).shift([0, -1.9, 0])
self.add(axes, camera, red_ray, sphere)
self.add_fixed_in_frame_mobjects(equations)
self.add_fixed_in_frame_mobjects(intersections_text)
self.add_fixed_in_frame_mobjects(sphere_text)
self.add_fixed_in_frame_mobjects(x_label)
self.add_fixed_in_frame_mobjects(z_label)
Phong Illumination Model
from manim import *
from manim_rt import *
class PhongIlluminationModel(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=90 * DEGREES, theta=-95 * DEGREES, frame_center=[0, 0, 0.65], zoom=5)
phong = MathTex("I(\\boldsymbol{p})=I_ak_a + I_dk_d(",
"\\boldsymbol{\hat{n}}",
"\cdot",
"\\boldsymbol{\hat{l}}",
") + I_sk_s(",
"\\boldsymbol{\hat{r}}",
"\cdot",
"\\boldsymbol{\hat{v}}",
")^a")
phong.set_color_by_tex("\\boldsymbol{\hat{n}}", BLUE)
phong.set_color_by_tex("\\boldsymbol{\hat{l}}", YELLOW)
phong.set_color_by_tex("\\boldsymbol{\hat{r}}", ORANGE)
phong.set_color_by_tex("\\boldsymbol{\hat{v}}", GREEN)
phong.scale(1.45)
phong.move_to([0.125, 0, 1.25])
# Axes and X + Z labels
axes = ThreeDAxes(x_length=8)
x_label = MathTex("x").next_to(axes.get_x_axis().get_end())
z_label = MathTex("z").next_to(axes.get_z_axis().get_end())
# Camera
camera = RTCamera([-3, 0, 3], focal_length=1, image_width=3, image_height=3, total_width=1, total_height=1)
camera.rotate(-45 * DEGREES, UP, camera.projection_point_coords)
# Ray
ray = Ray3D(start=[-3, 0, 3], direction=[1, 0, -1], length=4.5, thickness=0.01, color=RED)
ray_text = MathTex("R=(-3, 0, 3) + \\lambda (1, 0, -1)").next_to(ray.get_start(), OUT, buff=0.375).shift(0.5 * RIGHT)
# Sphere
sphere = RTSphere([0, 0, -1])
sphere.set_color(BLUE)
# Light Source
light = RTPointLightSource(center=[2.35, 0, 4], radius=0.1, color=YELLOW)
# Calculate hit points
hit_points = sphere.get_intersection(ray)
# First hit point
first_hit_point = hit_points[0]
first_hit_point_dot = Dot3D(first_hit_point, color=LIGHT_PINK)
# Second hit point
second_hit_point = hit_points[1]
second_hit_point_dot = Dot3D(second_hit_point, color=PURPLE)
# Unit normal
unit_normal = Ray3D(first_hit_point, ray.get_unit_normal(0), color=BLUE)
unit_normal_text = MathTex("\\boldsymbol{\\hat{n}}", color=BLUE).scale(2).next_to(unit_normal.get_end(), RIGHT, buff=-0.14)
# Light vector
light_vector = Ray3D(first_hit_point, ray.get_light_vector(0, light), color=YELLOW)
light_vector_text = MathTex("\\boldsymbol{\\hat{l}}", color=YELLOW).scale(2).next_to(light_vector.get_end(), RIGHT, buff=-0.025)
# Reflected light vector
reflected_light_vector = Ray3D(first_hit_point, ray.get_reflected_light_vector(0, light), color=ORANGE)
reflected_light_vector_text = MathTex("\\boldsymbol{\\hat{r}}", color=ORANGE).scale(2).next_to(reflected_light_vector.get_end(), RIGHT, buff=-0.075)
# Viewer vector (points towards the viewer of scene)
viewer_vector = Ray3D(first_hit_point, ray.get_viewer_vector(0, camera), color=GREEN)
viewer_vector_text = MathTex("\\boldsymbol{\\hat{v}}", color=GREEN).scale(2).next_to(viewer_vector.get_end(), IN)
angle_between_normal_and_light = Arc3D(unit_normal, light_vector)
angle_between_reflected_and_viewer = Arc3D(reflected_light_vector, viewer_vector)
# Add all relevant objects and text to the image
self.add(sphere)
self.add(light)
self.add(camera)
self.add(ray)
self.add(first_hit_point_dot)
self.add(second_hit_point_dot)
self.add(unit_normal)
self.add(light_vector)
self.add(reflected_light_vector)
self.add(viewer_vector)
self.add(angle_between_normal_and_light)
self.add(angle_between_reflected_and_viewer)
self.add_fixed_orientation_mobjects(x_label)
self.add_fixed_orientation_mobjects(z_label)
self.add_fixed_orientation_mobjects(ray_text)
self.add_fixed_orientation_mobjects(phong)
self.add_fixed_orientation_mobjects(unit_normal_text)
self.add_fixed_orientation_mobjects(light_vector_text)
self.add_fixed_orientation_mobjects(reflected_light_vector_text)
self.add_fixed_orientation_mobjects(viewer_vector_text)
Shadow Rays
from manim import *
from manim_rt import *
class ShadowRays(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=90 * DEGREES, theta=-90 * DEGREES, frame_center=[0, 0, 1.3], zoom=0.9)
# Axes and X + Z labels
axes = ThreeDAxes(x_length=8)
x_label = MathTex("x").next_to(axes.get_x_axis().get_end())
z_label = MathTex("z").next_to(axes.get_z_axis().get_end())
# Camera
camera = RTCamera([-3, 0, 3], focal_length=1, image_width=3, image_height=3, total_width=1, total_height=1)
camera.rotate(-45 * DEGREES, UP, camera.projection_point_coords)
# Ray
ray = Ray3D(start=[-3, 0, 3], direction=[1, 0, -1], length=4.5, thickness=0.01, color=RED)
ray_text = MathTex("R=(-3, 0, 3) + \\lambda (1, 0, -1)").next_to(ray.get_start(), OUT, buff=0.375).shift(0.5 * RIGHT)
# Sphere
sphere = RTSphere([0, 0, -1])
sphere.set_color(BLUE)
# Light Source 1
light1 = RTPointLightSource(center=[-3, 0, 3], radius=0.65, color=YELLOW)
light1_text = Tex("A").next_to(light1)
# Light Source 2
light2 = RTPointLightSource(center=[3, 0, 4], radius=0.75, color=YELLOW)
light2_text = Tex("B").next_to(light2)
# Calculate hit points
hit_points = sphere.get_intersection(ray)
# First hit point
first_hit_point = hit_points[0]
first_hit_point_dot = Dot3D(first_hit_point, radius=0.25, color=RED)
first_hit_point_text = Tex("Hit Point").next_to(first_hit_point, buff=0.65).shift([0, 0, 0.25])
# Shadow ray
shadow_ray1 = ray.get_shadow_ray(0, light1, color=LIGHT_BROWN)
shadow_ray2 = ray.get_shadow_ray(0, light2, color=LIGHT_BROWN)
# This sphere will intersect with the shadow ray above
blocking_sphere = RTSphere([1.5, 0, 2], x_scale=0.5, y_scale=0.5, z_scale=0.5)
blocking_sphere.set_color(GREEN)
# Add all relevant objects and text to the image
self.add(sphere, first_hit_point_dot, light1, light2, shadow_ray1, shadow_ray2, blocking_sphere)
self.add_fixed_orientation_mobjects(first_hit_point_text, light1_text, light2_text)
Mirror Ray
from manim import *
from manim_rt import *
class MirrorRay(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=90 * DEGREES, theta=-90 * DEGREES, frame_center=[0.25, 0, 0.5], zoom=1)
# Axes and X + Z labels
axes = ThreeDAxes(x_length=8)
# Camera
camera = RTCamera([-3, 0, 3], focal_length=1, image_width=3, image_height=3, total_width=1, total_height=1)
camera.rotate(-45 * DEGREES, UP, camera.projection_point_coords)
# Ray
ray = Ray3D(start=[-3, 0, 3], direction=[1, 0, -1], length=5.5, thickness=0.01, color=RED)
ray_text = MathTex("R=(-3, 0, 3) + \\lambda (1, 0, -1)").next_to(ray.get_start(), OUT, buff=0.375).shift(0.5 * RIGHT)
# Sphere
plane = RTPlane([1, 0, -1], x_scale=8, y_scale=2, opacity=0.5)
plane.set_color(BLUE)
# Calculate hit points
hit_points = plane.get_intersection(ray)
# First hit point
first_hit_point = hit_points[0]
first_hit_point_dot = Dot3D(first_hit_point, radius=0.25, color=RED)
first_hit_point_text = Tex("Hit Point").next_to(first_hit_point, direction=LEFT, buff=0.5).shift([0.25, 0, -0.55])
# Unit normal
normal = Ray3D(first_hit_point, ray.get_unit_normal(0), length=4, color=GREEN)
normal_text = Tex("Normal").next_to(normal.get_center(), buff=0.2).shift([0.1, 0, 1])
# Mirror ray
mirror_ray = ray.get_reflected_ray(0, camera, length=6, color=LIGHT_GREY)
# This sphere will intersect with the mirror ray
blocking_sphere = RTSphere([4, 0, 2], x_scale=0.5, y_scale=0.5, z_scale=0.5)
blocking_sphere.set_color(GREEN)
# Add all relevant objects and text to the image
self.add(camera, ray, plane, first_hit_point_dot, normal, mirror_ray, blocking_sphere)
self.add_fixed_orientation_mobjects(first_hit_point_text, normal_text)
Refracted Rays
from manim import *
from manim_rt import *
class RefractedRays(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=89 * DEGREES, theta=-180 * DEGREES, zoom=2, frame_center=[1, 0, -0.5])
# Axes for easier placement of objects
axes = ThreeDAxes()
labels = axes.get_axis_labels()
# Planes (maybe the air plane should be a different colour)
water_plane = RTPlane(refractive_index=1.33, color=BLUE)
air_plane = RTPlane([0, -1, -1], refractive_index=1, color=BLUE)
# Incident ray
ray_start = [-1, 1, 0.5]
ray = Ray3D(ray_start, ORIGIN - ray_start, 1, color=RED)
# Calculate intersection so we can actually get the refracted ray
hit_points = water_plane.get_intersection(ray)
# Unit normal for n1
unit_normal_n1 = Ray3D(hit_points[0], ray.get_unit_normal(0), color=GREEN)
# Angle between unit normal for n1 and incident ray
angle_n1 = Arc3D(ray, unit_normal_n1)
angle_n1_text = MathTex("\\theta_1").next_to(angle_n1.get_center() + 0.1 * UP, OUT)
# Unit normal for n2
unit_normal_n2 = Ray3D(hit_points[0], [0, 0, -1], color=ORANGE)
# Our first refracted ray travelling from air into water
first_refracted_ray = ray.get_refracted_ray(water_plane, color=BLUE, length=1.5)
# Angle between unit normal for n2 and the first refracted ray
angle_n2 = Arc3D(unit_normal_n2, first_refracted_ray)
angle_n2_text = MathTex("\\theta_2").next_to(angle_n2.get_center() + 0.2 * DOWN, IN)
# Show refractive indices
n1_text = MathTex("n = 1").next_to(unit_normal_n1.get_center(), DOWN, buff=0.35)
n2_text = MathTex("n = 1.33").next_to(first_refracted_ray.get_center(), DOWN, buff=0.75)
# Calculate intersection for refracted ray so we can show the second refracted ray
refracted_ray_hit_points = air_plane.get_intersection(first_refracted_ray)
# Our second refracted ray travelling from water to air
# The direction of this ray should be the same as the previous incident ray
second_refracted_ray = first_refracted_ray.get_refracted_ray(air_plane, refractive_index=1.33, length=2, color=RED)
# Show last refractive index
n3_text = MathTex("n = 1").next_to(second_refracted_ray.get_center(), IN, buff=0.5)
# Objects
self.add(water_plane, air_plane, ray, first_refracted_ray, unit_normal_n1, unit_normal_n2, angle_n1, angle_n2, second_refracted_ray)
# Text
self.add_fixed_orientation_mobjects(angle_n1_text, angle_n2_text, n1_text, n2_text, n3_text)
Total Internal Reflection
from manim import *
from manim_rt import *
class TotalInternalRefraction(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=85 * DEGREES, theta=-90 * DEGREES, zoom=1.75)
# Axes for easier placement of objects
axes = ThreeDAxes()
labels = axes.get_axis_labels()
# Planes
bottom_air_plane = RTPlane(x_scale=8, refractive_index=1, color=BLUE)
top_air_plane = RTPlane(translation=[0, 0, 0.5], x_scale=8, refractive_index=1, color=BLUE)
# Incident ray
ray_start = [-2, 0, 0.5]
ray = Ray3D(ray_start, np.subtract([-1, 0, 0], ray_start), 1, color=RED)
# Objects
self.add(bottom_air_plane, top_air_plane, ray)
# Text
n1_text = MathTex("n_1 = 1.33").next_to(ray.get_center(), LEFT)
n2_top_text = MathTex("n_2 = 1").next_to(ORIGIN, OUT, 1)
n2_bottom_text = MathTex("n_2 = 1").next_to(ORIGIN, IN, 0.5)
self.add_fixed_orientation_mobjects(n1_text, n2_top_text, n2_bottom_text)
for i in range(6):
if i % 2 == 0:
intersecting_plane = bottom_air_plane
ray_color = GREEN
else:
intersecting_plane = top_air_plane
ray_color = RED
# Calculate intersection so we can actually get the refracted ray
intersecting_plane.get_intersection(ray)
# First (of many) refracted rays that get reflected instead due to Total Internal Reflection
refracted_ray = ray.get_refracted_ray(bottom_air_plane, color=ray_color, length=1.125, refractive_index=1.33)
self.add(refracted_ray)
ray = refracted_ray
Animations
Basic Intersection
https://github.com/user-attachments/assets/8b971f01-36d9-4e0c-a136-2d750d31f42e
from manim import *
from manim_rt import *
class BasicIntersection(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=65*DEGREES, theta=-135*DEGREES, zoom=1.5)
sphere = RTSphere(color=BLUE)
ray = Ray3D([-5, 0, 0], length=10, color=RED)
self.begin_ambient_camera_rotation(0)
self.play(GrowFromCenter(sphere))
self.play(Create(ray, run_time=2))
self.wait(2)
Ray Tracing Algorithm
https://github.com/user-attachments/assets/d75863b4-b22d-4663-96b7-5bf504f541c0
from manim import *
from manim_rt import *
class BasicRayTracingAlgorithm(ThreeDScene):
def construct(self):
self.set_camera_orientation(phi=65*DEGREES, theta=0*DEGREES, zoom=1.5, frame_center=[0, 0, 1.5])
axes = ThreeDAxes()
labels = axes.get_axis_labels()
red_sphere_location = [-1, 2, 2]
# Camera
ray_start = [2, -2.5, 3]
camera = RTCamera(ray_start, image_width=3, image_height=3).rotate(90 * DEGREES, RIGHT).rotate(35 * DEGREES, OUT)
partial_ray = camera.draw_ray(2, 2, 2)
ray = camera.draw_ray(2, 2, 7.5)
pixel = camera.colour_pixel(2, 2, RED).rotate(90 * DEGREES, RIGHT).rotate(35 * DEGREES, OUT)
# Scene
plane = RTPlane(x_scale=3, y_scale=8, color=BLUE)
transparent_sphere = RTSphere(translation=[0, 0, 1], opacity=0.5)
red_sphere = RTSphere(translation=red_sphere_location, color=RED)
light_source = RTPointLightSource([0, -0.5, 3]).scale(0.25)
sphere = RTSphere.generate_sphere(ray, 2.5, color=RED)
# Animations
self.begin_ambient_camera_rotation(0)
self.play(GrowFromCenter(camera))
self.play(GrowFromCenter(plane))
self.play(GrowFromCenter(red_sphere))
self.play(GrowFromCenter(transparent_sphere))
self.play(GrowFromCenter(light_source))
self.play(Create(partial_ray))
self.play(FadeOut(partial_ray))
self.play(Create(ray))
self.play(FadeIn(pixel))