Semester 1, Week 10 Development - 62firelight/manimRT-490 GitHub Wiki

What's New

Finished Features

  • As a user, I want to...
    • add an arc representing an angle between two vectors so I can demonstrate that lighting is dependent on angles between certain vectors
    • create a Manim mobject representing a human eye so I can introduce ray-tracing by comparing it with how humans perceive light (need permission to complete)

Some progress has also been done on computing a refracted ray, but it's not in a state that I'm satisfied with yet.

Resolved Issue - Strange Layering Issue with Animations

Original: https://github.com/62firelight/manimRT-490/wiki/Semester-1,-Week-08-Development#strange-layering-issue-with-animations

I found this Reddit thread that ran into a similar issue. Apparently inserting an animation to make the camera move over time will cause intersecting objects to display correctly. The rate at which the camera moves can be set to 0 so the camera doesn't move, but any intersecting objects will have their intersections shown properly. Here is a revised animation with that fix in place:

IntersectionAnimationTest.mp4

In the thread I linked, one of the commenters said that they still have no idea why this fix works after trudging through the source code for hours, which is a bit concerning... but at least it works.

Feature Showcase

Angle Between Vectors

Below is a zoomed in version of the image from last week, but with angles between some of the vectors (n and l, r and v). I considered adding a theta symbol but it's already pretty cluttered as it is.

RTPointLightSourceTest_ManimCE_v0 18 0

Code (click to reveal)
from manim import *

from manim_rt.Arc3D import Arc3D
from manim_rt.RTPointLightSource import RTPointLightSource
from manim_rt.RTSphere import RTSphere
from manim_rt.Ray3D import Ray3D
from manim_rt.RTCamera import RTCamera

class RTPointLightSourceTest(ThreeDScene):
  def construct(self):
      self.set_camera_orientation(phi=90 * DEGREES, theta=-90 * DEGREES, frame_center=[0, 0, 1], zoom=1.5])
      
      # 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, plane_width=3, plane_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], distance=4.5, 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=[3, 0, 4], 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=PURPLE)
      
      # 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("\\hat{n}").next_to(unit_normal.get_end(), RIGHT + OUT, buff=0.1)
      
      # Light vector
      light_vector = Ray3D(first_hit_point, ray.get_light_vector(0, light), color=YELLOW)
      light_vector_text = MathTex("\\hat{l}").next_to(light_vector.get_end(), 0.1 * RIGHT + OUT, buff=0.45)
      
      # Reflected light vector
      reflected_light_vector = Ray3D(first_hit_point, ray.get_reflected_light_vector(0, light), color=ORANGE)
      reflected_light_vector_text = MathTex("\\hat{r}").next_to(reflected_light_vector.get_end(), RIGHT + OUT, buff=0.1)
      
      # 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("\\hat{v}").next_to(viewer_vector.get_end(), IN)
      
      # Shadow ray
      shadow_ray = ray.get_shadow_ray(0, light, color=LIGHT_BROWN)
      shadow_ray_text = VGroup(Tex("\\textbf{Shadow Ray}"), Tex("(no intersections)")).arrange(DOWN, aligned_edge=LEFT).next_to(shadow_ray.get_center(), RIGHT, buff=0.001)
      
      # This sphere will intersect with the shadow ray above
      blocking_sphere = RTSphere([2, 0, 2])
      blocking_sphere.set_color(LIGHT_GRAY)
      
      # Reflected ray (assuming the sphere is reflective)
      reflected_ray = ray.get_reflected_ray(0, camera, color=GRAY)
      reflected_ray_text = MathTex("\\hat{m}").next_to(reflected_ray.get_end(), RIGHT, buff=0.1)
      
      angle_between_normal_and_light = Arc3D(unit_normal, light_vector)
      angle_between_reflected_and_viewer = Arc3D(reflected_light_vector, viewer_vector)
      
      # Add all relevants objects and text to the image
      self.add(axes, sphere, light, camera, ray, first_hit_point_dot, second_hit_point_dot, unit_normal, light_vector, reflected_light_vector, viewer_vector, shadow_ray, reflected_ray, angle_between_normal_and_light, angle_between_reflected_and_viewer)
      self.add_fixed_orientation_mobjects(x_label, z_label, ray_text, unit_normal_text, light_vector_text, reflected_light_vector_text, viewer_vector_text, shadow_ray_text, reflected_ray_text)

Eye Image Test

I used an image mobject of an eyeball for this implementation, but I still have not gotten permission to use this.

Eye3DTest.mp4
Code (click to reveal)
from manim import *

from manim_rt.Ray3D import Ray3D

class Eye3DTest(ThreeDScene):
  def construct(self):
      self.set_camera_orientation(phi=45 * DEGREES, theta=45 * DEGREES)
      
      axes = ThreeDAxes()
      labels = axes.get_axis_labels()
      
      eye = ImageMobject("Eye.png")
      
      ray = Ray3D([5, 0, 0], LEFT, distance=4.1, color=YELLOW)
      
      # self.add(axes, labels, eye, ray)
      
      self.play(GrowFromCenter(eye))
      self.play(Create(ray))

Refracted Rays (WIP)

Refraction is still a big WIP, but here is where I am at so far. The main problem that I'm having is coming up with a good example for refraction that can easily demonstrate that it is working correctly.

RefractedRayTest_ManimCE_v0 18 0

Code (click to reveal)
from manim import *

from manim_rt.RTSphere import RTSphere
from manim_rt.Ray3D import Ray3D

class RefractedRayTest(ThreeDScene):
  def construct(self):
      self.set_camera_orientation(phi=45 * DEGREES, theta=-135 * DEGREES, zoom=1.5)
      
      axes = ThreeDAxes()
      labels = axes.get_axis_labels()
      
      sphere = RTSphere(refractive_index=1.7)
      sphere.set_color(WHITE)
      sphere.set_opacity(0.25)
      
      ray = Ray3D([-3, 3, 1], [1, -1, -0.25], 2.45, color=RED)
      
      hit_points = sphere.get_intersection(ray)
      
      refracted_ray = ray.get_refracted_ray(sphere, color=BLUE)
      print(refracted_ray.get_equation())
      
      unit_normal = Ray3D(hit_points[0], ray.get_unit_normal(0), color=GREEN)
      
      self.add(axes, labels, sphere, ray, refracted_ray, unit_normal)

Questions

  1. Do I have permission to use the eyeball image in ManimRT?
  2. Is there any feedback that can be given on the Ray-Object Intersection script that I've made at this link? (this can also be found in the Animation Planning section)
  3. Should the videos be commentated using voice or text? The answer is probably obvious here -- I've looked at a dozen SoME3 videos and all of them are voiced.
  4. Any potential issues with following the COSC342/450 lecture material too closely?

What's Next

To-Do List

From highest to lowest priority:

  • Develop full animation video for illustrating ray-object intersections
  • Check TODO comments in code and potentially make changes based on those
  • Start on interim report/presentation
  • Elicit more requirements for either lighting and/or reflections and refractions
  • Feature - As a developer I want to add a new object (other than spheres) that rays can intersect so that I can teach ray-tracing for different objects in my scene
  • Add docstrings to created classes and their methods
  • Add option to initialize camera grid with x value and aspect ratio
  • Generate spheres that intersect the ray at different points (2 intersection points + 1 intersection + no intersection)
⚠️ **GitHub.com Fallback** ⚠️