diff --git a/manimlib/camera/camera.py b/manimlib/camera/camera.py index e2b80274..9676b67f 100644 --- a/manimlib/camera/camera.py +++ b/manimlib/camera/camera.py @@ -166,14 +166,14 @@ class Camera(object): self.fbo = self.get_fbo() self.fbo.use() + flag = moderngl.BLEND if self.apply_depth_test: - self.ctx.enable(moderngl.DEPTH_TEST | moderngl.BLEND) - else: - self.ctx.enable(moderngl.BLEND) - self.ctx.blend_func = ( - moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA, - moderngl.ONE, moderngl.ONE - ) + flag |= moderngl.DEPTH_TEST + self.ctx.enable(flag) + self.ctx.blend_func = ( # Needed? + moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA, + moderngl.ONE, moderngl.ONE + ) self.background_fbo = None def init_light_source(self): @@ -379,3 +379,8 @@ class Camera(object): texture.use(location=tid) self.path_to_texture_id[path] = tid return self.path_to_texture_id[path] + + +class ThreeDCamera(Camera): + # Purely here to keep old scenes happy + pass diff --git a/manimlib/camera/three_d_camera.py b/manimlib/camera/three_d_camera.py deleted file mode 100644 index 7cb3b954..00000000 --- a/manimlib/camera/three_d_camera.py +++ /dev/null @@ -1,232 +0,0 @@ -import numpy as np - -from manimlib.camera.camera import Camera -from manimlib.constants import * -from manimlib.mobject.three_d_utils import get_3d_vmob_end_corner -from manimlib.mobject.three_d_utils import get_3d_vmob_end_corner_unit_normal -from manimlib.mobject.three_d_utils import get_3d_vmob_start_corner -from manimlib.mobject.three_d_utils import get_3d_vmob_start_corner_unit_normal -from manimlib.mobject.types.point_cloud_mobject import Point -from manimlib.mobject.value_tracker import ValueTracker -from manimlib.utils.color import get_shaded_rgb -from manimlib.utils.simple_functions import clip_in_place -from manimlib.utils.space_ops import rotation_about_z -from manimlib.utils.space_ops import rotation_matrix - - -class ThreeDCamera(Camera): - CONFIG = { - "shading_factor": 0.2, - "distance": 20.0, - "default_distance": 5.0, - "phi": 0, # Angle off z axis - "theta": -90 * DEGREES, # Rotation about z axis - "gamma": 0, # Rotation about normal vector to camera - "light_source_start_point": 9 * DOWN + 7 * LEFT + 10 * OUT, - "frame_center": ORIGIN, - "should_apply_shading": True, - "exponential_projection": False, - "max_allowable_norm": 3 * FRAME_WIDTH, - } - - def __init__(self, *args, **kwargs): - Camera.__init__(self, *args, **kwargs) - self.phi_tracker = ValueTracker(self.phi) - self.theta_tracker = ValueTracker(self.theta) - self.distance_tracker = ValueTracker(self.distance) - self.gamma_tracker = ValueTracker(self.gamma) - self.light_source = Point(self.light_source_start_point) - self.frame_center = Point(self.frame_center) - self.fixed_orientation_mobjects = dict() - self.fixed_in_frame_mobjects = set() - self.reset_rotation_matrix() - - def capture(self, *mobjects, **kwargs): - self.reset_rotation_matrix() - Camera.capture(self, *mobjects, **kwargs) - - def get_value_trackers(self): - return [ - self.phi_tracker, - self.theta_tracker, - self.distance_tracker, - self.gamma_tracker, - ] - - def modified_rgbas(self, vmobject, rgbas): - if not self.should_apply_shading: - return rgbas - if vmobject.shade_in_3d and (vmobject.get_num_points() > 0): - light_source_point = self.light_source.points[0] - if len(rgbas) < 2: - shaded_rgbas = rgbas.repeat(2, axis=0) - else: - shaded_rgbas = np.array(rgbas[:2]) - shaded_rgbas[0, :3] = get_shaded_rgb( - shaded_rgbas[0, :3], - get_3d_vmob_start_corner(vmobject), - get_3d_vmob_start_corner_unit_normal(vmobject), - light_source_point, - ) - shaded_rgbas[1, :3] = get_shaded_rgb( - shaded_rgbas[1, :3], - get_3d_vmob_end_corner(vmobject), - get_3d_vmob_end_corner_unit_normal(vmobject), - light_source_point, - ) - return shaded_rgbas - return rgbas - - def get_stroke_rgbas(self, vmobject, background=False): - return self.modified_rgbas( - vmobject, vmobject.get_stroke_rgbas(background) - ) - - def get_fill_rgbas(self, vmobject): - return self.modified_rgbas( - vmobject, vmobject.get_fill_rgbas() - ) - - def get_mobjects_to_display(self, *args, **kwargs): - mobjects = Camera.get_mobjects_to_display( - self, *args, **kwargs - ) - rot_matrix = self.get_rotation_matrix() - - def z_key(mob): - if not (hasattr(mob, "shade_in_3d") and mob.shade_in_3d): - return np.inf - # Assign a number to a three dimensional mobjects - # based on how close it is to the camera - return np.dot( - mob.get_z_index_reference_point(), - rot_matrix.T - )[2] - return sorted(mobjects, key=z_key) - - def get_phi(self): - return self.phi_tracker.get_value() - - def get_theta(self): - return self.theta_tracker.get_value() - - def get_distance(self): - return self.distance_tracker.get_value() - - def get_gamma(self): - return self.gamma_tracker.get_value() - - def get_frame_center(self): - return self.frame_center.points[0] - - def set_phi(self, value): - self.phi_tracker.set_value(value) - - def set_theta(self, value): - self.theta_tracker.set_value(value) - - def set_distance(self, value): - self.distance_tracker.set_value(value) - - def set_gamma(self, value): - self.gamma_tracker.set_value(value) - - def set_frame_center(self, point): - self.frame_center.move_to(point) - - def reset_rotation_matrix(self): - self.rotation_matrix = self.generate_rotation_matrix() - - def get_rotation_matrix(self): - return self.rotation_matrix - - def generate_rotation_matrix(self): - phi = self.get_phi() - theta = self.get_theta() - gamma = self.get_gamma() - matrices = [ - rotation_about_z(-theta - 90 * DEGREES), - rotation_matrix(-phi, RIGHT), - rotation_about_z(gamma), - ] - result = np.identity(3) - for matrix in matrices: - result = np.dot(matrix, result) - return result - - def project_points(self, points): - frame_center = self.get_frame_center() - distance = self.get_distance() - rot_matrix = self.get_rotation_matrix() - - points = points - frame_center - points = np.dot(points, rot_matrix.T) - zs = points[:, 2] - for i in 0, 1: - if self.exponential_projection: - # Proper projedtion would involve multiplying - # x and y by d / (d-z). But for points with high - # z value that causes weird artifacts, and applying - # the exponential helps smooth it out. - factor = np.exp(zs / distance) - lt0 = zs < 0 - factor[lt0] = (distance / (distance - zs[lt0])) - else: - factor = (distance / (distance - zs)) - factor[(distance - zs) < 0] = 10**6 - # clip_in_place(factor, 0, 10**6) - points[:, i] *= factor - points = points + frame_center - return points - - def project_point(self, point): - return self.project_points(point.reshape((1, 3)))[0, :] - - def transform_points_pre_display(self, mobject, points): - points = super().transform_points_pre_display(mobject, points) - fixed_orientation = mobject in self.fixed_orientation_mobjects - fixed_in_frame = mobject in self.fixed_in_frame_mobjects - - if fixed_in_frame: - return points - if fixed_orientation: - center_func = self.fixed_orientation_mobjects[mobject] - center = center_func() - new_center = self.project_point(center) - return points + (new_center - center) - else: - return self.project_points(points) - - def add_fixed_orientation_mobjects( - self, *mobjects, - use_static_center_func=False, - center_func=None): - # This prevents the computation of mobject.get_center - # every single time a projetion happens - def get_static_center_func(mobject): - point = mobject.get_center() - return (lambda: point) - - for mobject in mobjects: - if center_func: - func = center_func - elif use_static_center_func: - func = get_static_center_func(mobject) - else: - func = mobject.get_center - for submob in mobject.get_family(): - self.fixed_orientation_mobjects[submob] = func - - def add_fixed_in_frame_mobjects(self, *mobjects): - for mobject in self.extract_mobject_family_members(mobjects): - self.fixed_in_frame_mobjects.add(mobject) - - def remove_fixed_orientation_mobjects(self, *mobjects): - for mobject in self.extract_mobject_family_members(mobjects): - if mobject in self.fixed_orientation_mobjects: - self.fixed_orientation_mobjects.remove(mobject) - - def remove_fixed_in_frame_mobjects(self, *mobjects): - for mobject in self.extract_mobject_family_members(mobjects): - if mobject in self.fixed_in_frame_mobjects: - self.fixed_in_frame_mobjects.remove(mobject) diff --git a/manimlib/imports.py b/manimlib/imports.py index 23c1498e..ae5a3e7a 100644 --- a/manimlib/imports.py +++ b/manimlib/imports.py @@ -30,9 +30,6 @@ from manimlib.animation.transform import * from manimlib.animation.update import * from manimlib.camera.camera import * -from manimlib.camera.mapping_camera import * -from manimlib.camera.moving_camera import * -from manimlib.camera.three_d_camera import * from manimlib.mobject.coordinate_systems import * from manimlib.mobject.changing import * @@ -50,10 +47,10 @@ from manimlib.mobject.svg.drawings import * from manimlib.mobject.svg.svg_mobject import * from manimlib.mobject.svg.tex_mobject import * from manimlib.mobject.svg.text_mobject import * -from manimlib.mobject.three_d_utils import * from manimlib.mobject.three_dimensions import * from manimlib.mobject.types.image_mobject import * from manimlib.mobject.types.point_cloud_mobject import * +from manimlib.mobject.types.surface_mobject import * from manimlib.mobject.types.vectorized_mobject import * from manimlib.mobject.mobject_update_utils import * from manimlib.mobject.value_tracker import * diff --git a/manimlib/mobject/three_d_shading_utils.py b/manimlib/mobject/three_d_shading_utils.py deleted file mode 100644 index 4d8d7190..00000000 --- a/manimlib/mobject/three_d_shading_utils.py +++ /dev/null @@ -1,58 +0,0 @@ -import numpy as np - -from manimlib.constants import ORIGIN -from manimlib.utils.space_ops import get_unit_normal - - -# TODO, these ideas should be deprecated - -def get_3d_vmob_gradient_start_and_end_points(vmob): - return ( - get_3d_vmob_start_corner(vmob), - get_3d_vmob_end_corner(vmob), - ) - - -def get_3d_vmob_start_corner_index(vmob): - return 0 - - -def get_3d_vmob_end_corner_index(vmob): - return ((len(vmob.points) - 1) // 6) * 3 - - -def get_3d_vmob_start_corner(vmob): - if vmob.get_num_points() == 0: - return np.array(ORIGIN) - return vmob.points[get_3d_vmob_start_corner_index(vmob)] - - -def get_3d_vmob_end_corner(vmob): - if vmob.get_num_points() == 0: - return np.array(ORIGIN) - return vmob.points[get_3d_vmob_end_corner_index(vmob)] - - -def get_3d_vmob_unit_normal(vmob, point_index): - n_points = vmob.get_num_points() - if vmob.get_num_points() == 0: - return np.array(ORIGIN) - i = point_index - im1 = i - 1 if i > 0 else (n_points - 2) - ip1 = i + 1 if i < (n_points - 1) else 1 - return get_unit_normal( - vmob.points[ip1] - vmob.points[i], - vmob.points[im1] - vmob.points[i], - ) - - -def get_3d_vmob_start_corner_unit_normal(vmob): - return get_3d_vmob_unit_normal( - vmob, get_3d_vmob_start_corner_index(vmob) - ) - - -def get_3d_vmob_end_corner_unit_normal(vmob): - return get_3d_vmob_unit_normal( - vmob, get_3d_vmob_end_corner_index(vmob) - ) diff --git a/manimlib/mobject/three_d_utils.py b/manimlib/mobject/three_d_utils.py deleted file mode 100644 index 46e83165..00000000 --- a/manimlib/mobject/three_d_utils.py +++ /dev/null @@ -1,64 +0,0 @@ -import numpy as np - -from manimlib.constants import ORIGIN -from manimlib.constants import UP -from manimlib.utils.space_ops import get_norm -from manimlib.utils.space_ops import get_unit_normal - - -# TODO, these ideas should be deprecated - - -def get_3d_vmob_gradient_start_and_end_points(vmob): - return ( - get_3d_vmob_start_corner(vmob), - get_3d_vmob_end_corner(vmob), - ) - - -def get_3d_vmob_start_corner_index(vmob): - return 0 - - -def get_3d_vmob_end_corner_index(vmob): - return ((len(vmob.points) - 1) // 6) * 3 - - -def get_3d_vmob_start_corner(vmob): - if vmob.get_num_points() == 0: - return np.array(ORIGIN) - return vmob.points[get_3d_vmob_start_corner_index(vmob)] - - -def get_3d_vmob_end_corner(vmob): - if vmob.get_num_points() == 0: - return np.array(ORIGIN) - return vmob.points[get_3d_vmob_end_corner_index(vmob)] - - -def get_3d_vmob_unit_normal(vmob, point_index): - n_points = vmob.get_num_points() - if len(vmob.get_anchors()) <= 2: - return np.array(UP) - i = point_index - im3 = i - 3 if i > 2 else (n_points - 4) - ip3 = i + 3 if i < (n_points - 3) else 3 - unit_normal = get_unit_normal( - vmob.points[ip3] - vmob.points[i], - vmob.points[im3] - vmob.points[i], - ) - if get_norm(unit_normal) == 0: - return np.array(UP) - return unit_normal - - -def get_3d_vmob_start_corner_unit_normal(vmob): - return get_3d_vmob_unit_normal( - vmob, get_3d_vmob_start_corner_index(vmob) - ) - - -def get_3d_vmob_end_corner_unit_normal(vmob): - return get_3d_vmob_unit_normal( - vmob, get_3d_vmob_end_corner_index(vmob) - ) diff --git a/manimlib/mobject/three_dimensions.py b/manimlib/mobject/three_dimensions.py index 7cf11163..8e44d7c9 100644 --- a/manimlib/mobject/three_dimensions.py +++ b/manimlib/mobject/three_dimensions.py @@ -1,29 +1,14 @@ from manimlib.constants import * from manimlib.mobject.geometry import Square +from manimlib.mobject.types.surface_mobject import SurfaceMobject from manimlib.mobject.types.vectorized_mobject import VGroup -from manimlib.mobject.types.vectorized_mobject import VMobject -from manimlib.utils.iterables import listify -from manimlib.utils.space_ops import z_to_vector - -############## -# TODO, replace these with a special 3d type, not VMobject - - -class ThreeDVMobject(VMobject): +class ParametricSurface(SurfaceMobject): CONFIG = { - "shade_in_3d": True, - } - - -class ParametricSurface(VGroup): - CONFIG = { - "u_min": 0, - "u_max": 1, - "v_min": 0, - "v_max": 1, - "resolution": 32, + "u_range": (0, 1), + "v_range": (0, 1), + "resolution": (32, 32), "surface_piece_config": {}, "fill_color": BLUE_D, "fill_opacity": 1.0, @@ -34,93 +19,72 @@ class ParametricSurface(VGroup): "pre_function_handle_to_anchor_scale_factor": 0.00001, } - def __init__(self, func, **kwargs): - VGroup.__init__(self, **kwargs) - self.func = func - self.setup_in_uv_space() - self.apply_function(lambda p: func(p[0], p[1])) - if self.should_make_jagged: - self.make_jagged() - - def get_u_values_and_v_values(self): - res = listify(self.resolution) - if len(res) == 1: - u_res = v_res = res[0] + def __init__(self, function=None, **kwargs): + if function is None: + self.uv_func = self.func else: - u_res, v_res = res - u_min = self.u_min - u_max = self.u_max - v_min = self.v_min - v_max = self.v_max + self.uv_func = function + super().__init__(**kwargs) - u_values = np.linspace(u_min, u_max, u_res + 1) - v_values = np.linspace(v_min, v_max, v_res + 1) - - return u_values, v_values - - def setup_in_uv_space(self): - u_values, v_values = self.get_u_values_and_v_values() - faces = VGroup() - for i in range(len(u_values) - 1): - for j in range(len(v_values) - 1): - u1, u2 = u_values[i:i + 2] - v1, v2 = v_values[j:j + 2] - face = ThreeDVMobject() - face.set_points_as_corners([ - [u1, v1, 0], - [u2, v1, 0], - [u2, v2, 0], - [u1, v2, 0], - [u1, v1, 0], - ]) - faces.add(face) - face.u_index = i - face.v_index = j - face.u1 = u1 - face.u2 = u2 - face.v1 = v1 - face.v2 = v2 - faces.set_fill( - color=self.fill_color, - opacity=self.fill_opacity + def init_points(self): + epsilon = 1e-6 # For differentials + nu, nv = self.resolution + u_range = np.linspace(*self.u_range, nu + 1) + v_range = np.linspace(*self.v_range, nv + 1) + # List of three grids, [Pure uv values, those nudged by du, those nudged by dv] + uv_grids = [ + np.array([[[u, v] for v in v_range] for u in u_range]) + for (du, dv) in [(0, 0), (epsilon, 0), (0, epsilon)] + ] + point_grid, points_nudged_du, points_nudged_dv = [ + np.apply_along_axis(lambda p: self.uv_func(*p), 2, uv_grid) + for uv_grid in uv_grids + ] + normal_grid = np.cross( + (points_nudged_du - point_grid) / epsilon, + (points_nudged_dv - point_grid) / epsilon, ) - faces.set_stroke( - color=self.stroke_color, - width=self.stroke_width, - opacity=self.stroke_opacity, + + self.set_points( + self.get_triangle_ready_array_from_grid(point_grid), + self.get_triangle_ready_array_from_grid(normal_grid), ) - self.add(*faces) - if self.checkerboard_colors: - self.set_fill_by_checkerboard(*self.checkerboard_colors) - def set_fill_by_checkerboard(self, *colors, opacity=None): - n_colors = len(colors) - for face in self: - c_index = (face.u_index + face.v_index) % n_colors - face.set_fill(colors[c_index], opacity=opacity) + # self.points = point_grid[indices] + + def get_triangle_ready_array_from_grid(self, grid): + # Given a grid, say of points or normals, this returns an Nx3 array + # whose rows are elements from this grid in such such a way that successive + # triplets of points form triangles covering the grid. + nu = grid.shape[0] - 1 + nv = grid.shape[1] - 1 + dim = grid.shape[2] + arr = np.zeros((nu * nv * 6, dim)) + # To match the triangles covering this surface + arr[0::6] = grid[:-1, :-1].reshape((nu * nv, 3)) # Top left + arr[1::6] = grid[+1:, :-1].reshape((nu * nv, 3)) # Bottom left + arr[2::6] = grid[:-1, +1:].reshape((nu * nv, 3)) # Top right + arr[3::6] = grid[:-1, +1:].reshape((nu * nv, 3)) # Top right + arr[4::6] = grid[+1:, :-1].reshape((nu * nv, 3)) # Bottom left + arr[5::6] = grid[+1:, +1:].reshape((nu * nv, 3)) # Bottom right + return arr + + def func(self, u, v): + pass -# Specific shapes - +# Sphere, cylinder, cube, prism class Sphere(ParametricSurface): CONFIG = { "resolution": (12, 24), "radius": 1, - "u_min": 0.001, - "u_max": PI - 0.001, - "v_min": 0, - "v_max": TAU, + "u_range": (0, PI), + "v_range": (0, TAU), } - def __init__(self, **kwargs): - ParametricSurface.__init__( - self, self.func, **kwargs - ) - self.scale(self.radius) - def func(self, u, v): - return np.array([ + return self.radius * np.array([ np.cos(v) * np.sin(u), np.sin(v) * np.sin(u), np.cos(u) diff --git a/manimlib/mobject/types/surface_mobject.py b/manimlib/mobject/types/surface_mobject.py new file mode 100644 index 00000000..b1774fef --- /dev/null +++ b/manimlib/mobject/types/surface_mobject.py @@ -0,0 +1,76 @@ +import numpy as np +import moderngl + +# from PIL import Image + +from manimlib.constants import * +from manimlib.mobject.mobject import Mobject +from manimlib.utils.color import color_to_rgba + + +class SurfaceMobject(Mobject): + CONFIG = { + "color": GREY, + "opacity": 1, + "gloss": 1.0, + "render_primative": moderngl.TRIANGLES, + # "render_primative": moderngl.TRIANGLE_STRIP, + "vert_shader_file": "surface_vert.glsl", + "frag_shader_file": "surface_frag.glsl", + "shader_dtype": [ + ('point', np.float32, (3,)), + ('normal', np.float32, (3,)), + ('color', np.float32, (4,)), + ('gloss', np.float32, (1,)), + # ('im_coords', np.float32, (2,)), + ] + } + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def init_points(self): + self.points = np.zeros((0, self.dim)) + self.normals = np.zeros((0, self.dim)) + + def init_colors(self): + self.set_color(self.color, self.opacity) + + def set_points(self, points, normals=None): + self.points = np.array(points) + if normals is None: + v01 = points[1:-1] - points[:-2] + v02 = points[2:] - points[:-2] + crosses = np.cross(v01, v02) + crosses[1::2] *= -1 # Because of reversed orientation of every other triangle in the strip + self.normals = np.vstack([ + crosses, + crosses[-1:].repeat(2, 0) # Repeat last entry twice + ]) + else: + self.normals = np.array(normals) + + def set_color(self, color, opacity): + # TODO, allow for multiple colors + rgba = color_to_rgba(color, opacity) + self.rgbas = np.array([rgba]) + + def apply_function(self, function, **kwargs): + # Apply it to infinitesimal neighbors to preserve normals + pass + + def rotate(self, axis, angle, **kwargs): + # Account for normals + pass + + def stretch(self, factor, dim, **kwargs): + # Account for normals + pass + + def get_shader_data(self): + data = self.get_blank_shader_data_array(len(self.points)) + data["point"] = self.points + data["normal"] = self.normals + data["color"] = self.rgbas + data["gloss"] = self.gloss + return data diff --git a/manimlib/mobject/types/vectorized_mobject.py b/manimlib/mobject/types/vectorized_mobject.py index 5362036c..d4631deb 100644 --- a/manimlib/mobject/types/vectorized_mobject.py +++ b/manimlib/mobject/types/vectorized_mobject.py @@ -8,7 +8,6 @@ from functools import reduce from manimlib.constants import * from manimlib.mobject.mobject import Mobject from manimlib.mobject.mobject import Point -from manimlib.mobject.three_d_utils import get_3d_vmob_gradient_start_and_end_points from manimlib.utils.bezier import bezier from manimlib.utils.bezier import get_smooth_handle_points from manimlib.utils.bezier import get_quadratic_approximation_of_cubic @@ -63,7 +62,7 @@ class VMobject(Mobject): # Could also be Bevel, Miter, Round "joint_type": "auto", # Positive gloss up to 1 makes it reflect the light. - "gloss": 0.0, + "gloss": 0.2, "render_primative": moderngl.TRIANGLES, "triangulation_locked": False, "fill_dtype": [ diff --git a/manimlib/scene/three_d_scene.py b/manimlib/scene/three_d_scene.py index 1d4979ea..5cb847b8 100644 --- a/manimlib/scene/three_d_scene.py +++ b/manimlib/scene/three_d_scene.py @@ -1,5 +1,4 @@ from manimlib.animation.transform import ApplyMethod -from manimlib.camera.three_d_camera import ThreeDCamera from manimlib.constants import DEGREES from manimlib.constants import PRODUCTION_QUALITY_CAMERA_CONFIG from manimlib.mobject.coordinate_systems import ThreeDAxes @@ -12,9 +11,10 @@ from manimlib.utils.config_ops import digest_config from manimlib.utils.config_ops import merge_dicts_recursively +# TODO, these seem deprecated. + class ThreeDScene(Scene): CONFIG = { - "camera_class": ThreeDCamera, "ambient_camera_rotation": None, "default_angled_camera_orientation_kwargs": { "phi": 70 * DEGREES, diff --git a/manimlib/shaders/add_light.glsl b/manimlib/shaders/add_light.glsl index ffb16037..1c1b61cb 100644 --- a/manimlib/shaders/add_light.glsl +++ b/manimlib/shaders/add_light.glsl @@ -7,15 +7,17 @@ vec4 add_light(vec4 raw_color, vec3 point, vec3 unit_normal, vec3 light_coords, unit_normal *= -1; } - float camera_distance = 6; + float camera_distance = 6; // TODO, read this in as a uniform? // Assume everything has already been rotated such that camera is in the z-direction vec3 to_camera = vec3(0, 0, camera_distance) - point; vec3 to_light = light_coords - point; vec3 light_reflection = -to_light + 2 * unit_normal * dot(to_light, unit_normal); float dot_prod = dot(normalize(light_reflection), normalize(to_camera)); - float shine = gloss * exp(-3 * pow(1 - dot_prod, 2)); + // float shine = gloss * exp(-3 * pow(1 - dot_prod, 2)); + float shine = 2 * gloss * exp(-1 * pow(1 - dot_prod, 2)); + float dp2 = dot(normalize(to_light), unit_normal); return vec4( - mix(raw_color.rgb, vec3(1.0), shine), + mix(0.5, 1.0, max(dp2, 0)) * mix(raw_color.rgb, vec3(1.0), shine), raw_color.a ); } \ No newline at end of file diff --git a/manimlib/shaders/surface_frag.glsl b/manimlib/shaders/surface_frag.glsl new file mode 100644 index 00000000..3f0eb69c --- /dev/null +++ b/manimlib/shaders/surface_frag.glsl @@ -0,0 +1,12 @@ +#version 330 + +// uniform sampler2D Texture; + +// in vec2 v_im_coords; +in vec4 v_color; + +out vec4 frag_color; + +void main() { + frag_color = v_color; +} \ No newline at end of file diff --git a/manimlib/shaders/surface_vert.glsl b/manimlib/shaders/surface_vert.glsl new file mode 100644 index 00000000..2a8284de --- /dev/null +++ b/manimlib/shaders/surface_vert.glsl @@ -0,0 +1,31 @@ +#version 330 + +uniform float aspect_ratio; +uniform float anti_alias_width; +uniform mat4 to_screen_space; +uniform float focal_distance; +uniform vec3 light_source_position; + +// uniform sampler2D Texture; + +in vec3 point; +in vec3 normal; +// in vec2 im_coords; +in vec4 color; +in float gloss; + +// out vec2 v_im_coords; +out vec4 v_color; + +// Analog of import for manim only +#INSERT position_point_into_frame.glsl +#INSERT get_gl_Position.glsl +#INSERT add_light.glsl + +void main(){ + vec3 xyz_coords = position_point_into_frame(point); + vec3 unit_normal = normalize(position_point_into_frame(normal)); + // v_im_coords = im_coords; + v_color = add_light(color, xyz_coords, unit_normal, light_source_position, gloss); + gl_Position = get_gl_Position(xyz_coords); +} \ No newline at end of file