Add shadow, and pull out lighting information to Mobject

This commit is contained in:
Grant Sanderson 2020-06-06 16:55:56 -07:00
parent b32c2937ae
commit ba7a51931d
14 changed files with 94 additions and 44 deletions

View file

@ -382,5 +382,7 @@ class Camera(object):
class ThreeDCamera(Camera):
# Purely here to keep old scenes happy
pass
CONFIG = {
"apply_depth_test": True,
# TODO, default to do some multisampling?
}

View file

@ -39,6 +39,11 @@ class Mobject(Container):
"color": WHITE,
"name": None,
"dim": 3,
# Lighting parameters
# Positive gloss up to 1 makes it reflect the light.
"gloss": 0.0,
# Positive shadow up to 1 makes a side opposite the light darker
"shadow": 0.0,
# For shaders
"vert_shader_file": "",
"geom_shader_file": "",
@ -735,6 +740,26 @@ class Mobject(Container):
def get_color(self):
return self.color
def get_gloss(self):
return self.gloss
def set_gloss(self, gloss, family=True):
self.gloss = gloss
if family:
for submob in self.submobjects:
submob.set_gloss(gloss, family)
return self
def get_shadow(self):
return self.shadow
def set_shadow(self, shadow, family=True):
self.shadow = shadow
if family:
for submob in self.submobjects:
submob.set_shadow(shadow, family)
return self
##
def save_state(self, use_deepcopy=False):

View file

@ -14,12 +14,14 @@ class ParametricSurface(Mobject):
CONFIG = {
"u_range": (0, 1),
"v_range": (0, 1),
# Resolution counts number of points sampled, which is off by
# 1 from the number of actual approximating squares seen
# Resolution counts number of points sampled, which for
# each coordinate is one more than the the number of rows/columns
# of approximating squares
"resolution": (101, 101),
"color": GREY,
"opacity": 1.0,
"gloss": 0.3,
"shadow": 0.4,
# For du and dv steps. Much smaller and numerical error
# can crop up in the shaders.
"epsilon": 1e-5,
@ -32,6 +34,7 @@ class ParametricSurface(Mobject):
('dv_point', np.float32, (3,)),
('color', np.float32, (4,)),
('gloss', np.float32, (1,)),
('shadow', np.float32, (1,)),
]
}
@ -114,13 +117,6 @@ class ParametricSurface(Mobject):
sm.set_opacity(opacity, family)
return self
def set_gloss(self, gloss, family=True):
self.gloss = gloss
if family:
for sm in self.submobjects:
sm.set_gloss(gloss, family)
return self
def get_shader_data(self):
s_points, du_points, dv_points = [
self.get_triangle_ready_array(array)
@ -130,12 +126,13 @@ class ParametricSurface(Mobject):
data["point"] = s_points
data["du_point"] = du_points
data["dv_point"] = dv_points
data["gloss"] = self.gloss
data["shadow"] = self.shadow
self.fill_in_shader_color_info(data)
return data
def fill_in_shader_color_info(self, data):
data["color"] = self.rgbas
data["gloss"] = self.gloss
return data
@ -159,6 +156,7 @@ class TexturedSurface(ParametricSurface):
('im_coords', np.float32, (2,)),
('opacity', np.float32, (1,)),
('gloss', np.float32, (1,)),
('shadow', np.float32, (1,)),
]
}
@ -199,5 +197,4 @@ class TexturedSurface(ParametricSurface):
def fill_in_shader_color_info(self, data):
data["im_coords"] = self.get_triangle_ready_array(self.im_coords)
data["opacity"] = self.opacity
data["gloss"] = self.gloss
return data

View file

@ -57,8 +57,6 @@ class VMobject(Mobject):
"fill_frag_shader_file": "quadratic_bezier_fill_frag.glsl",
# Could also be Bevel, Miter, Round
"joint_type": "auto",
# Positive gloss up to 1 makes it reflect the light.
"gloss": 0.2,
"render_primative": moderngl.TRIANGLES,
"triangulation_locked": False,
"fill_dtype": [
@ -67,6 +65,7 @@ class VMobject(Mobject):
('color', np.float32, (4,)),
('fill_all', np.float32, (1,)),
('gloss', np.float32, (1,)),
('shadow', np.float32, (1,)),
],
"stroke_dtype": [
("point", np.float32, (3,)),
@ -77,6 +76,7 @@ class VMobject(Mobject):
("color", np.float32, (4,)),
("joint_type", np.float32, (1,)),
("gloss", np.float32, (1,)),
("shadow", np.float32, (1,)),
]
}
@ -155,6 +155,7 @@ class VMobject(Mobject):
stroke_width=None,
stroke_opacity=None,
gloss=None,
shadow=None,
background_image_file=None,
family=True):
self.set_fill(
@ -168,8 +169,10 @@ class VMobject(Mobject):
opacity=stroke_opacity,
family=family,
)
if gloss:
if gloss is not None:
self.set_gloss(gloss, family=family)
if shadow is not None:
self.set_shadow(shadow, family=family)
if background_image_file:
self.color_using_background_image(background_image_file)
return self
@ -223,17 +226,6 @@ class VMobject(Mobject):
super().fade(darkness, family)
return self
def set_gloss(self, gloss, family=True):
if family:
for sm in self.get_family():
sm.gloss = gloss
else:
self.gloss = gloss
return self
def get_gloss(self):
return self.gloss
def get_fill_rgbas(self):
try:
return self.fill_rgbas
@ -908,6 +900,7 @@ class VMobject(Mobject):
data["color"] = rgbas
data["joint_type"] = joint_type_to_code[self.joint_type]
data["gloss"] = self.gloss
data["shadow"] = self.shadow
return data
def lock_triangulation(self, family=True):
@ -994,6 +987,7 @@ class VMobject(Mobject):
data["fill_all"][:len(points)] = 0
data["fill_all"][len(points):] = 1
data["gloss"] = self.gloss
data["shadow"] = self.shadow
return data

View file

@ -1,5 +1,5 @@
vec4 add_light(vec4 raw_color, vec3 point, vec3 unit_normal, vec3 light_coords, float gloss){
if(gloss == 0.0) return raw_color;
vec4 add_light(vec4 raw_color, vec3 point, vec3 unit_normal, vec3 light_coords, float gloss, float shadow){
if(gloss == 0.0 && shadow == 0.0) return raw_color;
// TODO, do we actually want this? It effectively treats surfaces as two-sided
if(unit_normal.z < 0){
@ -14,9 +14,9 @@ vec4 add_light(vec4 raw_color, vec3 point, vec3 unit_normal, vec3 light_coords,
float dot_prod = dot(normalize(light_reflection), normalize(to_camera));
float shine = gloss * exp(-3 * pow(1 - dot_prod, 2));
float dp2 = dot(normalize(to_light), unit_normal);
float shadow = ((dp2 + 2.0) / 3.0); // TODO, this should come from the mobject in some way
float darkening = mix(1, max(dp2, 0), shadow);
return vec4(
shadow * mix(raw_color.rgb, vec3(1.0), shine),
darkening * mix(raw_color.rgb, vec3(1.0), shine),
raw_color.a
);
}

View file

@ -1,6 +1,5 @@
#version 330
uniform vec3 light_source_position;
uniform mat4 to_screen_space;
in vec4 color;
@ -8,12 +7,10 @@ in float fill_all; // Either 0 or 1e
in float uv_anti_alias_width;
in vec3 xyz_coords;
in vec3 global_unit_normal;
in float orientation;
in vec2 uv_coords;
in vec2 uv_b2;
in float bezier_degree;
in float gloss;
out vec4 frag_color;
@ -26,7 +23,6 @@ float modify_distance_for_endpoints(vec2 p, float dist, float t){
// so to share functionality between this and others, the caller
// replaces this line with the contents of quadratic_bezier_sdf.glsl
#INSERT quadratic_bezier_distance.glsl
#INSERT add_light.glsl
float sdf(){
@ -67,7 +63,7 @@ float sdf(){
void main() {
if (color.a == 0) discard;
frag_color = add_light(color, xyz_coords, global_unit_normal, light_source_position, gloss);
frag_color = color;
if (fill_all == 1.0) return;
frag_color.a *= smoothstep(1, 0, sdf() / uv_anti_alias_width);
}

View file

@ -7,20 +7,20 @@ uniform float anti_alias_width;
// Needed for get_gl_Position
uniform float aspect_ratio;
uniform float focal_distance;
uniform vec3 light_source_position;
in vec3 bp[3];
in vec3 v_global_unit_normal[3];
in vec4 v_color[3];
in float v_fill_all[3];
in float v_gloss[3];
in float v_shadow[3];
out vec4 color;
out float gloss;
out float fill_all;
out float uv_anti_alias_width;
out vec3 xyz_coords;
out vec3 global_unit_normal;
out float orientation;
// uv space is where b0 = (0, 0), b1 = (1, 0), and transform is orthogonal
out vec2 uv_coords;
@ -33,12 +33,18 @@ out float bezier_degree;
#INSERT quadratic_bezier_geometry_functions.glsl
#INSERT get_gl_Position.glsl
#INSERT get_unit_normal.glsl
#INSERT add_light.glsl
void emit_vertex_wrapper(vec3 point, int index){
color = v_color[index];
gloss = v_gloss[index];
global_unit_normal = v_global_unit_normal[index];
color = add_light(
v_color[index],
point,
v_global_unit_normal[index],
light_source_position,
v_gloss[index],
v_shadow[index]
);
xyz_coords = point;
gl_Position = get_gl_Position(xyz_coords);
EmitVertex();

View file

@ -7,12 +7,14 @@ in vec3 unit_normal;
in vec4 color;
in float fill_all; // Either 0 or 1
in float gloss;
in float shadow;
out vec3 bp; // Bezier control point
out vec3 v_global_unit_normal;
out vec4 v_color;
out float v_fill_all;
out float v_gloss;
out float v_shadow;
// To my knowledge, there is no notion of #include for shaders,
// so to share functionality between this and others, the caller
@ -25,4 +27,5 @@ void main(){
v_color = color;
v_fill_all = fill_all;
v_gloss = gloss;
v_shadow = shadow;
}

View file

@ -18,6 +18,7 @@ in vec4 v_color[3];
in float v_stroke_width[3];
in float v_joint_type[3];
in float v_gloss[3];
in float v_shadow[3];
out vec4 color;
out float uv_stroke_width;
@ -256,7 +257,8 @@ void main() {
xyz_coords,
v_global_unit_normal[index_map[i]],
light_source_position,
v_gloss[index_map[i]]
v_gloss[index_map[i]],
v_shadow[index_map[i]]
);
gl_Position = get_gl_Position(xyz_coords);
EmitVertex();

View file

@ -12,6 +12,7 @@ in float stroke_width;
in vec4 color;
in float joint_type;
in float gloss;
in float shadow;
// Bezier control point
out vec3 bp;
@ -23,6 +24,7 @@ out float v_stroke_width;
out vec4 v_color;
out float v_joint_type;
out float v_gloss;
out float v_shadow;
const float STROKE_WIDTH_CONVERSION = 0.0025;
@ -41,4 +43,5 @@ void main(){
v_color = color;
v_joint_type = joint_type;
v_gloss = gloss;
v_shadow = shadow;
}

View file

@ -9,11 +9,19 @@ in vec3 xyz_coords;
in vec3 v_normal;
in vec4 v_color;
in float v_gloss;
in float v_shadow;
out vec4 frag_color;
#INSERT add_light.glsl
void main() {
frag_color = add_light(v_color, xyz_coords, normalize(v_normal), light_source_position, v_gloss);
frag_color = add_light(
v_color,
xyz_coords,
normalize(v_normal),
light_source_position,
v_gloss,
v_shadow
);
}

View file

@ -11,11 +11,13 @@ in vec3 du_point;
in vec3 dv_point;
in vec4 color;
in float gloss;
in float shadow;
out vec3 xyz_coords;
out vec3 v_normal;
out vec4 v_color;
out float v_gloss;
out float v_shadow;
// These lines will get replaced
#INSERT position_point_into_frame.glsl
@ -27,5 +29,6 @@ void main(){
v_normal = get_rotated_surface_unit_normal_vector(point, du_point, dv_point);
v_color = color;
v_gloss = gloss;
v_shadow = shadow;
gl_Position = get_gl_Position(xyz_coords);
}

View file

@ -8,6 +8,7 @@ in vec3 v_normal;
in vec2 v_im_coords;
in float v_opacity;
in float v_gloss;
in float v_shadow;
out vec4 frag_color;
@ -15,6 +16,13 @@ out vec4 frag_color;
void main() {
vec4 im_color = texture(Texture, v_im_coords);
frag_color = add_light(im_color, xyz_coords, normalize(v_normal), light_source_position, v_gloss);
frag_color = add_light(
im_color,
xyz_coords,
normalize(v_normal),
light_source_position,
v_gloss,
v_shadow
);
frag_color.a = v_opacity;
}

View file

@ -14,12 +14,14 @@ in vec3 dv_point;
in vec2 im_coords;
in float opacity;
in float gloss;
in float shadow;
out vec3 xyz_coords;
out vec3 v_normal;
out vec2 v_im_coords;
out float v_opacity;
out float v_gloss;
out float v_shadow;
// These lines will get replaced
#INSERT position_point_into_frame.glsl
@ -32,5 +34,6 @@ void main(){
v_im_coords = im_coords;
v_opacity = opacity;
v_gloss = gloss;
v_shadow = shadow;
gl_Position = get_gl_Position(xyz_coords);
}