bug fixes in light. Finally working again!

This commit is contained in:
Ben Hambrecht 2018-02-07 09:46:01 +01:00
parent 8e0c84946f
commit 2c4fa36073

View file

@ -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