mirror of
https://github.com/3b1b/manim.git
synced 2025-08-05 16:49:03 +00:00
bug fixes in light. Finally working again!
This commit is contained in:
parent
8e0c84946f
commit
2c4fa36073
1 changed files with 46 additions and 28 deletions
|
@ -21,7 +21,7 @@ from scipy.spatial import ConvexHull
|
||||||
|
|
||||||
|
|
||||||
LIGHT_COLOR = YELLOW
|
LIGHT_COLOR = YELLOW
|
||||||
SHADOW_COLOR = RED
|
SHADOW_COLOR = BLACK
|
||||||
SWITCH_ON_RUN_TIME = 1.5
|
SWITCH_ON_RUN_TIME = 1.5
|
||||||
FAST_SWITCH_ON_RUN_TIME = 0.1
|
FAST_SWITCH_ON_RUN_TIME = 0.1
|
||||||
NUM_LEVELS = 30
|
NUM_LEVELS = 30
|
||||||
|
@ -53,7 +53,7 @@ class LightSource(VMobject):
|
||||||
# a spotlight
|
# a spotlight
|
||||||
# and a shadow
|
# and a shadow
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"source_point": ORIGIN,
|
"source_point": VectorizedPoint(location = ORIGIN, stroke_width = 0, fill_opacity = 0),
|
||||||
"color": LIGHT_COLOR,
|
"color": LIGHT_COLOR,
|
||||||
"num_levels": 10,
|
"num_levels": 10,
|
||||||
"radius": 5,
|
"radius": 5,
|
||||||
|
@ -64,9 +64,12 @@ class LightSource(VMobject):
|
||||||
}
|
}
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
|
|
||||||
|
self.add(self.source_point)
|
||||||
|
|
||||||
self.lighthouse = Lighthouse()
|
self.lighthouse = Lighthouse()
|
||||||
self.ambient_light = AmbientLight(
|
self.ambient_light = AmbientLight(
|
||||||
source_point = self.source_point,
|
source_point = VectorizedPoint(location = self.get_source_point()),
|
||||||
color = self.color,
|
color = self.color,
|
||||||
num_levels = self.num_levels,
|
num_levels = self.num_levels,
|
||||||
radius = self.radius,
|
radius = self.radius,
|
||||||
|
@ -75,7 +78,7 @@ class LightSource(VMobject):
|
||||||
)
|
)
|
||||||
if self.has_screen():
|
if self.has_screen():
|
||||||
self.spotlight = Spotlight(
|
self.spotlight = Spotlight(
|
||||||
source_point = self.source_point,
|
source_point = VectorizedPoint(location = self.get_source_point()),
|
||||||
color = self.color,
|
color = self.color,
|
||||||
num_levels = self.num_levels,
|
num_levels = self.num_levels,
|
||||||
radius = self.radius,
|
radius = self.radius,
|
||||||
|
@ -87,11 +90,11 @@ class LightSource(VMobject):
|
||||||
self.spotlight = Spotlight()
|
self.spotlight = Spotlight()
|
||||||
|
|
||||||
self.shadow = VMobject(fill_color = SHADOW_COLOR, fill_opacity = 1.0, stroke_color = BLACK)
|
self.shadow = VMobject(fill_color = SHADOW_COLOR, fill_opacity = 1.0, stroke_color = BLACK)
|
||||||
self.lighthouse.next_to(self.source_point,DOWN,buff = 0)
|
self.lighthouse.next_to(self.get_source_point(),DOWN,buff = 0)
|
||||||
self.ambient_light.move_source_to(self.source_point)
|
self.ambient_light.move_source_to(self.get_source_point())
|
||||||
|
|
||||||
if self.has_screen():
|
if self.has_screen():
|
||||||
self.spotlight.move_source_to(self.source_point)
|
self.spotlight.move_source_to(self.get_source_point())
|
||||||
self.update_shadow()
|
self.update_shadow()
|
||||||
|
|
||||||
self.add(self.ambient_light,self.spotlight,self.lighthouse, self.shadow)
|
self.add(self.ambient_light,self.spotlight,self.lighthouse, self.shadow)
|
||||||
|
@ -118,24 +121,24 @@ class LightSource(VMobject):
|
||||||
self.spotlight.screen = new_screen
|
self.spotlight.screen = new_screen
|
||||||
else:
|
else:
|
||||||
# Note: See below
|
# Note: See below
|
||||||
# index = self.submobjects.index(self.spotlight)
|
index = self.submobjects.index(self.spotlight)
|
||||||
self.remove(self.spotlight)
|
self.remove(self.spotlight)
|
||||||
self.spotlight = Spotlight(
|
self.spotlight = Spotlight(
|
||||||
source_point = self.source_point,
|
source_point = VectorizedPoint(location = self.get_source_point()),
|
||||||
color = self.color,
|
color = self.color,
|
||||||
num_levels = self.num_levels,
|
num_levels = self.num_levels,
|
||||||
radius = self.radius,
|
radius = self.radius,
|
||||||
screen = new_screen
|
screen = new_screen
|
||||||
)
|
)
|
||||||
self.spotlight.move_source_to(self.source_point)
|
self.spotlight.move_source_to(self.get_source_point())
|
||||||
|
|
||||||
# Note: This line will make spotlight show up at the end
|
# Note: This line will make spotlight show up at the end
|
||||||
# of the submojects list, which can make it show up on
|
# of the submojects list, which can make it show up on
|
||||||
# top of the shadow. To make it show up in the
|
# top of the shadow. To make it show up in the
|
||||||
# same spot, you could try the following line,
|
# same spot, you could try the following line,
|
||||||
# where "index" is what I defined above:
|
# where "index" is what I defined above:
|
||||||
# self.submobjects.insert(index, self.spotlight)
|
self.submobjects.insert(index, self.spotlight)
|
||||||
self.add(self.spotlight)
|
#self.add(self.spotlight)
|
||||||
|
|
||||||
# in any case
|
# in any case
|
||||||
self.screen = new_screen
|
self.screen = new_screen
|
||||||
|
@ -145,12 +148,12 @@ class LightSource(VMobject):
|
||||||
|
|
||||||
def move_source_to(self,point):
|
def move_source_to(self,point):
|
||||||
apoint = np.array(point)
|
apoint = np.array(point)
|
||||||
v = apoint - self.source_point
|
v = apoint - self.get_source_point()
|
||||||
# Note: As discussed, things stand to behave better if source
|
# Note: As discussed, things stand to behave better if source
|
||||||
# point is a submobject, so that it automatically interpolates
|
# point is a submobject, so that it automatically interpolates
|
||||||
# during an animation, and other updates can be defined wrt
|
# during an animation, and other updates can be defined wrt
|
||||||
# that source point's location
|
# that source point's location
|
||||||
self.source_point = apoint
|
self.source_point.set_location(apoint)
|
||||||
self.lighthouse.next_to(apoint,DOWN,buff = 0)
|
self.lighthouse.next_to(apoint,DOWN,buff = 0)
|
||||||
self.ambient_light.move_source_to(apoint)
|
self.ambient_light.move_source_to(apoint)
|
||||||
if self.has_screen():
|
if self.has_screen():
|
||||||
|
@ -167,10 +170,12 @@ class LightSource(VMobject):
|
||||||
self.spotlight.update_sectors()
|
self.spotlight.update_sectors()
|
||||||
self.update_shadow()
|
self.update_shadow()
|
||||||
|
|
||||||
|
def get_source_point(self):
|
||||||
|
return self.source_point.get_location()
|
||||||
|
|
||||||
def update_shadow(self):
|
def update_shadow(self):
|
||||||
|
|
||||||
point = self.source_point
|
point = self.get_source_point()
|
||||||
projected_screen_points = []
|
projected_screen_points = []
|
||||||
if not self.has_screen():
|
if not self.has_screen():
|
||||||
return
|
return
|
||||||
|
@ -178,7 +183,7 @@ class LightSource(VMobject):
|
||||||
projected_screen_points.append(self.spotlight.project(point))
|
projected_screen_points.append(self.spotlight.project(point))
|
||||||
|
|
||||||
|
|
||||||
projected_source = project_along_vector(self.source_point,self.spotlight.projection_direction())
|
projected_source = project_along_vector(self.get_source_point(),self.spotlight.projection_direction())
|
||||||
|
|
||||||
projected_point_cloud_3d = np.append(
|
projected_point_cloud_3d = np.append(
|
||||||
projected_screen_points,
|
projected_screen_points,
|
||||||
|
@ -196,7 +201,7 @@ class LightSource(VMobject):
|
||||||
hull = []
|
hull = []
|
||||||
|
|
||||||
# we also need the projected source point
|
# we also need the projected source point
|
||||||
source_point_2d = np.dot(self.spotlight.project(self.source_point),back_rotation_matrix.T)[:2]
|
source_point_2d = np.dot(self.spotlight.project(self.get_source_point()),back_rotation_matrix.T)[:2]
|
||||||
|
|
||||||
index = 0
|
index = 0
|
||||||
for point in point_cloud_2d[hull_2d.vertices]:
|
for point in point_cloud_2d[hull_2d.vertices]:
|
||||||
|
@ -291,7 +296,7 @@ class AmbientLight(VMobject):
|
||||||
# * the number of subdivisions (levels, annuli)
|
# * the number of subdivisions (levels, annuli)
|
||||||
|
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"source_point" : ORIGIN,
|
"source_point": VectorizedPoint(location = ORIGIN, stroke_width = 0, fill_opacity = 0),
|
||||||
"opacity_function" : lambda r : 1.0/(r+1.0)**2,
|
"opacity_function" : lambda r : 1.0/(r+1.0)**2,
|
||||||
"color" : LIGHT_COLOR,
|
"color" : LIGHT_COLOR,
|
||||||
"max_opacity" : 1.0,
|
"max_opacity" : 1.0,
|
||||||
|
@ -300,8 +305,6 @@ class AmbientLight(VMobject):
|
||||||
}
|
}
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
self.source_point = np.array(self.source_point)
|
|
||||||
|
|
||||||
# in theory, this method is only called once, right?
|
# in theory, this method is only called once, right?
|
||||||
# so removing submobs shd not be necessary
|
# so removing submobs shd not be necessary
|
||||||
#
|
#
|
||||||
|
@ -311,6 +314,8 @@ class AmbientLight(VMobject):
|
||||||
for submob in self.submobjects:
|
for submob in self.submobjects:
|
||||||
self.remove(submob)
|
self.remove(submob)
|
||||||
|
|
||||||
|
self.add(self.source_point)
|
||||||
|
|
||||||
# create annuli
|
# create annuli
|
||||||
self.radius = float(self.radius)
|
self.radius = float(self.radius)
|
||||||
dr = self.radius / self.num_levels
|
dr = self.radius / self.num_levels
|
||||||
|
@ -322,22 +327,28 @@ class AmbientLight(VMobject):
|
||||||
color = self.color,
|
color = self.color,
|
||||||
fill_opacity = alpha
|
fill_opacity = alpha
|
||||||
)
|
)
|
||||||
annulus.move_arc_center_to(self.source_point)
|
annulus.move_arc_center_to(self.get_source_point())
|
||||||
self.add(annulus)
|
self.add(annulus)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def move_source_to(self,point):
|
def move_source_to(self,point):
|
||||||
# Note: Best to rewrite in terms of VectorizedPoint source_point
|
# Note: Best to rewrite in terms of VectorizedPoint source_point
|
||||||
v = np.array(point) - self.source_point
|
self.source_point.set_location(np.array(point))
|
||||||
self.source_point = np.array(point)
|
self.move_to(point)
|
||||||
self.shift(v)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_source_point(self):
|
||||||
|
return self.source_point.get_location()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def dimming(self,new_alpha):
|
def dimming(self,new_alpha):
|
||||||
|
@ -352,7 +363,7 @@ class AmbientLight(VMobject):
|
||||||
class Spotlight(VMobject):
|
class Spotlight(VMobject):
|
||||||
|
|
||||||
CONFIG = {
|
CONFIG = {
|
||||||
"source_point" : ORIGIN,
|
"source_point": VectorizedPoint(location = ORIGIN, stroke_width = 0, fill_opacity = 0),
|
||||||
"opacity_function" : lambda r : 1.0/(r/2+1.0)**2,
|
"opacity_function" : lambda r : 1.0/(r/2+1.0)**2,
|
||||||
"color" : LIGHT_COLOR,
|
"color" : LIGHT_COLOR,
|
||||||
"max_opacity" : 1.0,
|
"max_opacity" : 1.0,
|
||||||
|
@ -378,10 +389,17 @@ class Spotlight(VMobject):
|
||||||
w = project_along_vector(point,v)
|
w = project_along_vector(point,v)
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def get_source_point(self):
|
||||||
|
return self.source_point.get_location()
|
||||||
|
|
||||||
|
|
||||||
def generate_points(self):
|
def generate_points(self):
|
||||||
|
|
||||||
self.submobjects = []
|
self.submobjects = []
|
||||||
|
|
||||||
|
self.add(self.source_point)
|
||||||
|
|
||||||
if self.screen != None:
|
if self.screen != None:
|
||||||
# look for the screen and create annular sectors
|
# look for the screen and create annular sectors
|
||||||
lower_angle, upper_angle = self.viewing_angles(self.screen)
|
lower_angle, upper_angle = self.viewing_angles(self.screen)
|
||||||
|
@ -417,14 +435,14 @@ class Spotlight(VMobject):
|
||||||
projected_RIGHT = self.project(RIGHT)
|
projected_RIGHT = self.project(RIGHT)
|
||||||
omega = angle_between_vectors(rotated_RIGHT,projected_RIGHT)
|
omega = angle_between_vectors(rotated_RIGHT,projected_RIGHT)
|
||||||
annular_sector.rotate(omega, axis = self.projection_direction())
|
annular_sector.rotate(omega, axis = self.projection_direction())
|
||||||
annular_sector.move_arc_center_to(self.source_point)
|
annular_sector.move_arc_center_to(self.get_source_point())
|
||||||
|
|
||||||
return annular_sector
|
return annular_sector
|
||||||
|
|
||||||
def viewing_angle_of_point(self,point):
|
def viewing_angle_of_point(self,point):
|
||||||
# as measured from the positive x-axis
|
# as measured from the positive x-axis
|
||||||
v1 = self.project(RIGHT)
|
v1 = self.project(RIGHT)
|
||||||
v2 = self.project(np.array(point) - self.source_point)
|
v2 = self.project(np.array(point) - self.get_source_point())
|
||||||
absolute_angle = angle_between_vectors(v1, v2)
|
absolute_angle = angle_between_vectors(v1, v2)
|
||||||
# determine the angle's sign depending on their plane's
|
# determine the angle's sign depending on their plane's
|
||||||
# choice of orientation. That choice is set by the camera
|
# choice of orientation. That choice is set by the camera
|
||||||
|
@ -473,7 +491,7 @@ class Spotlight(VMobject):
|
||||||
return u
|
return u
|
||||||
|
|
||||||
def move_source_to(self,point):
|
def move_source_to(self,point):
|
||||||
self.source_point = np.array(point)
|
self.source_point.set_location(np.array(point))
|
||||||
self.update_sectors()
|
self.update_sectors()
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue