Something is rendering now but the relative manim units don't work Co-authored-by: Jason Villanueva <a@jsonvillanueva.com>

This commit is contained in:
MrDiver 2023-09-10 22:12:53 +02:00
commit 1e57feccdb
14 changed files with 836 additions and 243 deletions

View file

@ -1,14 +1,32 @@
import time
from pyglet.gl import Config
from pyglet.window import Window
import manim.utils.color.manim_colors as col
from manim._config import tempconfig
from manim.camera.camera import OpenGLCamera, OpenGLCameraFrame
from manim.constants import OUT
from manim.mobject.geometry.arc import Circle
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
from manim.renderer.opengl_renderer import OpenGLRenderer
renderer = OpenGLRenderer(1920, 1080)
vm = OpenGLVMobject([col.RED, col.GREEN])
vm.set_points_as_corners([[0, 0, 0], [1, 0, 0], [1, 1, 0]])
# print(vm.color)
# print(vm.fill_color)
# print(vm.stroke_color)
if __name__ == "__main__":
with tempconfig({"renderer": "opengl"}):
win = Window(width=1920, height=1080)
renderer = OpenGLRenderer(1920, 1080)
# vm = OpenGLVMobject([col.RED, col.GREEN])
vm = Circle(radius=100)
# vm.set_points_as_corners([[-1920/2, 0, 0], [1920/2, 0, 0], [0, 1080/2, 0]])
# print(vm.color)
# print(vm.fill_color)
# print(vm.stroke_color)
camera = OpenGLCameraFrame((1920, 1090))
renderer.render_vmobject(vm, camera)
camera = OpenGLCameraFrame((1920, 1080), center_point=OUT * 10)
renderer.set_camera(camera)
for _ in range(4):
renderer.render_vmobject(vm)
win.dispatch_events()
win.flip()
time.sleep(1)

View file

@ -0,0 +1,444 @@
from __future__ import annotations
import re
import textwrap
from pathlib import Path
import moderngl
import numpy as np
from .. import config
from ..utils import opengl
from ..utils.simple_functions import get_parameters
SHADER_FOLDER = Path(__file__).parent / "shaders"
shader_program_cache: dict = {}
file_path_to_code_map: dict = {}
__all__ = [
"Object3D",
"Mesh",
"Shader",
"FullScreenQuad",
]
def get_shader_code_from_file(file_path: Path) -> str:
if file_path in file_path_to_code_map:
return file_path_to_code_map[file_path]
source = file_path.read_text()
include_lines = re.finditer(
r"^#include (?P<include_path>.*\.glsl)$",
source,
flags=re.MULTILINE,
)
for match in include_lines:
include_path = match.group("include_path")
included_code = get_shader_code_from_file(
file_path.parent / include_path,
)
source = source.replace(match.group(0), included_code)
file_path_to_code_map[file_path] = source
return source
def filter_attributes(unfiltered_attributes, attributes):
# Construct attributes for only those needed by the shader.
filtered_attributes_dtype = []
for i, dtype_name in enumerate(unfiltered_attributes.dtype.names):
if dtype_name in attributes:
filtered_attributes_dtype.append(
(
dtype_name,
unfiltered_attributes.dtype[i].subdtype[0].str,
unfiltered_attributes.dtype[i].shape,
),
)
filtered_attributes = np.zeros(
unfiltered_attributes[unfiltered_attributes.dtype.names[0]].shape[0],
dtype=filtered_attributes_dtype,
)
for dtype_name in unfiltered_attributes.dtype.names:
if dtype_name in attributes:
filtered_attributes[dtype_name] = unfiltered_attributes[dtype_name]
return filtered_attributes
class Object3D:
def __init__(self, *children):
self.model_matrix = np.eye(4)
self.normal_matrix = np.eye(4)
self.children = []
self.parent = None
self.add(*children)
self.init_updaters()
# TODO: Use path_func.
def interpolate(self, start, end, alpha, _):
self.model_matrix = (1 - alpha) * start.model_matrix + alpha * end.model_matrix
self.normal_matrix = (
1 - alpha
) * start.normal_matrix + alpha * end.normal_matrix
def single_copy(self):
copy = Object3D()
copy.model_matrix = self.model_matrix.copy()
copy.normal_matrix = self.normal_matrix.copy()
return copy
def copy(self):
node_to_copy = {}
bfs = [self]
while bfs:
node = bfs.pop(0)
bfs.extend(node.children)
node_copy = node.single_copy()
node_to_copy[node] = node_copy
# Add the copy to the copy of the parent.
if node.parent is not None and node is not self:
node_to_copy[node.parent].add(node_copy)
return node_to_copy[self]
def add(self, *children):
for child in children:
if child.parent is not None:
raise Exception(
"Attempt to add child that's already added to another Object3D",
)
self.remove(*children, current_children_only=False)
self.children.extend(children)
for child in children:
child.parent = self
def remove(self, *children, current_children_only=True):
if current_children_only:
for child in children:
if child.parent != self:
raise Exception(
"Attempt to remove child that isn't added to this Object3D",
)
self.children = list(filter(lambda child: child not in children, self.children))
for child in children:
child.parent = None
def get_position(self):
return self.model_matrix[:, 3][:3]
def set_position(self, position):
self.model_matrix[:, 3][:3] = position
return self
def get_meshes(self):
dfs = [self]
while dfs:
parent = dfs.pop()
if isinstance(parent, Mesh):
yield parent
dfs.extend(parent.children)
def get_family(self):
dfs = [self]
while dfs:
parent = dfs.pop()
yield parent
dfs.extend(parent.children)
def align_data_and_family(self, _):
pass
def hierarchical_model_matrix(self):
if self.parent is None:
return self.model_matrix
model_matrices = [self.model_matrix]
current_object = self
while current_object.parent is not None:
model_matrices.append(current_object.parent.model_matrix)
current_object = current_object.parent
return np.linalg.multi_dot(list(reversed(model_matrices)))
def hierarchical_normal_matrix(self):
if self.parent is None:
return self.normal_matrix[:3, :3]
normal_matrices = [self.normal_matrix]
current_object = self
while current_object.parent is not None:
normal_matrices.append(current_object.parent.model_matrix)
current_object = current_object.parent
return np.linalg.multi_dot(list(reversed(normal_matrices)))[:3, :3]
def init_updaters(self):
self.time_based_updaters = []
self.non_time_updaters = []
self.has_updaters = False
self.updating_suspended = False
def update(self, dt=0):
if not self.has_updaters or self.updating_suspended:
return self
for updater in self.time_based_updaters:
updater(self, dt)
for updater in self.non_time_updaters:
updater(self)
return self
def get_time_based_updaters(self):
return self.time_based_updaters
def has_time_based_updater(self):
return len(self.time_based_updaters) > 0
def get_updaters(self):
return self.time_based_updaters + self.non_time_updaters
def add_updater(self, update_function, index=None, call_updater=True):
if "dt" in get_parameters(update_function):
updater_list = self.time_based_updaters
else:
updater_list = self.non_time_updaters
if index is None:
updater_list.append(update_function)
else:
updater_list.insert(index, update_function)
self.refresh_has_updater_status()
if call_updater:
self.update()
return self
def remove_updater(self, update_function):
for updater_list in [self.time_based_updaters, self.non_time_updaters]:
while update_function in updater_list:
updater_list.remove(update_function)
self.refresh_has_updater_status()
return self
def clear_updaters(self):
self.time_based_updaters = []
self.non_time_updaters = []
self.refresh_has_updater_status()
return self
def match_updaters(self, mobject):
self.clear_updaters()
for updater in mobject.get_updaters():
self.add_updater(updater)
return self
def suspend_updating(self):
self.updating_suspended = True
return self
def resume_updating(self, call_updater=True):
self.updating_suspended = False
if call_updater:
self.update(dt=0)
return self
def refresh_has_updater_status(self):
self.has_updaters = len(self.get_updaters()) > 0
return self
class Mesh(Object3D):
def __init__(
self,
shader=None,
attributes=None,
geometry=None,
material=None,
indices=None,
use_depth_test=True,
primitive=moderngl.TRIANGLES,
):
super().__init__()
if shader is not None and attributes is not None:
self.shader = shader
self.attributes = attributes
self.indices = indices
elif geometry is not None and material is not None:
self.shader = material
self.attributes = geometry.attributes
self.indices = geometry.index
else:
raise Exception(
"Mesh requires either attributes and a Shader or a Geometry and a "
"Material",
)
self.use_depth_test = use_depth_test
self.primitive = primitive
self.skip_render = False
self.init_updaters()
def single_copy(self):
copy = Mesh(
attributes=self.attributes.copy(),
shader=self.shader,
indices=self.indices.copy() if self.indices is not None else None,
use_depth_test=self.use_depth_test,
primitive=self.primitive,
)
copy.skip_render = self.skip_render
copy.model_matrix = self.model_matrix.copy()
copy.normal_matrix = self.normal_matrix.copy()
# TODO: Copy updaters?
return copy
def set_uniforms(self, renderer):
self.shader.set_uniform(
"u_model_matrix",
opengl.matrix_to_shader_input(self.model_matrix),
)
self.shader.set_uniform("u_view_matrix", renderer.camera.formatted_view_matrix)
self.shader.set_uniform(
"u_projection_matrix",
renderer.camera.projection_matrix,
)
def render(self):
if self.skip_render:
return
if self.use_depth_test:
self.shader.context.enable(moderngl.DEPTH_TEST)
else:
self.shader.context.disable(moderngl.DEPTH_TEST)
from moderngl import Attribute
shader_attributes = []
for k, v in self.shader.shader_program._members.items():
if isinstance(v, Attribute):
shader_attributes.append(k)
shader_attributes = filter_attributes(self.attributes, shader_attributes)
vertex_buffer_object = self.shader.context.buffer(shader_attributes.tobytes())
if self.indices is None:
index_buffer_object = None
else:
vert_index_data = self.indices.astype("i4").tobytes()
if vert_index_data:
index_buffer_object = self.shader.context.buffer(vert_index_data)
else:
index_buffer_object = None
vertex_array_object = self.shader.context.simple_vertex_array(
self.shader.shader_program,
vertex_buffer_object,
*shader_attributes.dtype.names,
index_buffer=index_buffer_object,
)
vertex_array_object.render(self.primitive)
vertex_buffer_object.release()
vertex_array_object.release()
if index_buffer_object is not None:
index_buffer_object.release()
class Shader:
def __init__(
self,
context,
name=None,
source=None,
):
global shader_program_cache
self.context = context
self.name = name
# See if the program is cached.
if (
self.name in shader_program_cache
and shader_program_cache[self.name].ctx == self.context
):
self.shader_program = shader_program_cache[self.name]
elif source is not None:
# Generate the shader from inline code if it was passed.
self.shader_program = context.program(**source)
else:
# Search for a file containing the shader.
source_dict = {}
source_dict_key = {
"vert": "vertex_shader",
"frag": "fragment_shader",
"geom": "geometry_shader",
}
shader_folder = SHADER_FOLDER / name
for shader_file in shader_folder.iterdir():
shader_file_path = shader_folder / shader_file
shader_source = get_shader_code_from_file(shader_file_path)
source_dict[source_dict_key[shader_file_path.stem]] = shader_source
self.shader_program = context.program(**source_dict)
# Cache the shader.
if name is not None and name not in shader_program_cache:
shader_program_cache[self.name] = self.shader_program
def set_uniform(self, name, value):
try:
self.shader_program[name] = value
except KeyError:
pass
class FullScreenQuad(Mesh):
def __init__(
self,
context,
fragment_shader_source=None,
fragment_shader_name=None,
):
if fragment_shader_source is None and fragment_shader_name is None:
raise Exception("Must either pass shader name or shader source.")
if fragment_shader_name is not None:
# Use the name.
shader_file_path = SHADER_FOLDER / f"{fragment_shader_name}.frag"
fragment_shader_source = get_shader_code_from_file(shader_file_path)
elif fragment_shader_source is not None:
fragment_shader_source = textwrap.dedent(fragment_shader_source.lstrip())
shader = Shader(
context,
source={
"vertex_shader": """
#version 330
in vec4 in_vert;
uniform mat4 u_model_view_matrix;
uniform mat4 u_projection_matrix;
void main() {{
vec4 camera_space_vertex = u_model_view_matrix * in_vert;
vec4 clip_space_vertex = u_projection_matrix * camera_space_vertex;
gl_Position = clip_space_vertex;
}}
""",
"fragment_shader": fragment_shader_source,
},
)
attributes = np.zeros(6, dtype=[("in_vert", np.float32, (4,))])
attributes["in_vert"] = np.array(
[
[-config["frame_x_radius"], -config["frame_y_radius"], 0, 1],
[-config["frame_x_radius"], config["frame_y_radius"], 0, 1],
[config["frame_x_radius"], config["frame_y_radius"], 0, 1],
[-config["frame_x_radius"], -config["frame_y_radius"], 0, 1],
[config["frame_x_radius"], -config["frame_y_radius"], 0, 1],
[config["frame_x_radius"], config["frame_y_radius"], 0, 1],
],
)
shader.set_uniform("u_model_view_matrix", opengl.view_matrix())
shader.set_uniform(
"u_projection_matrix",
opengl.orthographic_projection_matrix(),
)
super().__init__(shader, attributes)
def render(self):
super().render()

View file

@ -5,14 +5,18 @@ from typing import TYPE_CHECKING
import moderngl as gl
import numpy as np
from PIL import Image
from typing_extensions import override
import manim.constants as const
import manim.utils.color.manim_colors as color
from manim._config import config, logger
from manim.camera.camera import OpenGLCameraFrame
from manim.mobject.types.vectorized_mobject import VMobject
from manim.renderer.opengl_shader_program import load_shader_program_by_folder
from manim.renderer.renderer import Renderer, RendererData
from manim.renderer.renderer import ImageType, Renderer, RendererData
from manim.renderer.shader_wrapper import ShaderWrapper
from manim.utils.iterables import listify, resize_array, resize_with_interpolation
from manim.utils.space_ops import cross2d, earclip_triangulation, z_to_vector
if TYPE_CHECKING:
@ -21,15 +25,31 @@ if TYPE_CHECKING:
import manim.utils.color.core as c
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
fill_dtype = [
("point", np.float32, (3,)),
# ("orientation", np.float32, (3,)),
("unit_normal", np.float32, (3,)),
("color", np.float32, (4,)),
("vert_index", np.float32, (1,)),
]
stroke_dtype = [
("point", np.float32, (3,)),
("prev_point", np.float32, (3,)),
("next_point", np.float32, (3,)),
("stroke_width", np.float32, (1,)),
("color", np.float32, (4,)),
]
class GLRenderData(RendererData):
def __init__(self) -> None:
super().__init__()
self.fill_rgbas = np.zeros((1, 4))
self.stroke_rgbas = np.zeros((1, 4))
self.stroke_widths = np.zeros((1, 1))
self.normals = np.zeros((1, 4))
self.orientation = None
self.mesh = np.zeros((0, 3))
self.orientation = np.zeros((1, 1))
self.vert_indices = np.zeros((0, 3))
self.bounding_box = np.zeros((3, 3))
def __repr__(self) -> str:
@ -43,7 +63,7 @@ normals:
orientation:
{self.orientation}
mesh:
{self.mesh}
{self.vert_indices}
bounding_box:
{self.bounding_box}
"""
@ -165,22 +185,27 @@ class OpenGLRenderer(Renderer):
self.pixel_width = pixel_width
self.pixel_height = pixel_height
self.samples = samples
self.background_color = (color.BLACK,)
self.background_color = background_color.to_rgba()
self.background_image = background_image
self.rgb_max_val: float = np.iinfo(self.pixel_array_dtype).max
# Initializing Context
logger.debug("Initializing OpenGL context and framebuffers")
self.ctx = gl.create_context(standalone=True)
self.ctx = gl.create_context()
self.target_fbo = self.ctx.simple_framebuffer(
(self.pixel_width, self.pixel_height), samples=self.samples
)
self.output_fbo = self.ctx.framebuffer(
color_attachments=[
self.ctx.renderbuffer((self.pixel_width, self.pixel_height))
]
)
fbo = self.ctx.detect_framebuffer()
if not fbo:
self.output_fbo = self.ctx.framebuffer(
color_attachments=[
self.ctx.renderbuffer((self.pixel_width, self.pixel_height))
]
)
else:
self.output_fbo = fbo
# Preparing vmobject shader
logger.debug("Initializing Shader Programs")
@ -191,8 +216,70 @@ class OpenGLRenderer(Renderer):
self.ctx, "quadratic_bezier_stroke"
)
def set_camera(self, camera: OpenGLCameraFrame) -> ImageType:
self.vmobject_fill_program["is_fixed_in_frame"] = 0.0
self.vmobject_fill_program["frame_shape"] = camera.frame_shape
self.vmobject_fill_program["focal_distance"] = float(
camera.get_focal_distance()
)
self.vmobject_fill_program["camera_center"] = tuple(camera.get_center())
self.vmobject_fill_program["camera_rotation"] = tuple(
np.array(camera.get_inverse_camera_rotation_matrix()).T.flatten()
)
self.vmobject_fill_program["light_source_position"] = (-10, 10, 10)
# TODO: convert to singular 4x4 matrix after getting *something* to render
# self.vmobject_fill_program['view'].value = camera.get_view()?
self.vmobject_stroke_program["is_fixed_in_frame"].value = 0.0
self.vmobject_stroke_program["anti_alias_width"].value = 1.0
self.vmobject_stroke_program["frame_shape"].value = np.asarray(
camera.frame_shape
)
# self.vmobject_stroke_program['pixel_shape'].value = camera.frame_shape
self.vmobject_stroke_program["focal_distance"].value = np.asarray(
camera.get_focal_distance()
)
self.vmobject_stroke_program["camera_center"].value = np.asarray(
camera.get_center()
)
self.vmobject_stroke_program["camera_rotation"].value = np.array(
camera.get_inverse_camera_rotation_matrix()
).T.flatten()
self.vmobject_stroke_program["light_source_position"].value = np.array(
[-10, 10, 10]
)
def get_stroke_shader_data(self, mob: OpenGLVMobject) -> np.ndarray:
if not isinstance(mob.renderer_data, GLRenderData):
raise TypeError()
points = mob.points
stroke_data = np.zeros(len(points), dtype=stroke_dtype)
nppc = mob.n_points_per_curve
stroke_data["point"] = points
stroke_data["prev_point"][:nppc] = points[-nppc:]
stroke_data["prev_point"][nppc:] = points[:-nppc]
stroke_data["next_point"][:-nppc] = points[nppc:]
stroke_data["next_point"][-nppc:] = points[:nppc]
stroke_data["color"] = mob.renderer_data.stroke_rgbas
stroke_data["stroke_width"] = mob.renderer_data.stroke_widths
return stroke_data
def get_fill_shader_data(self, mob: OpenGLVMobject) -> np.ndarray:
if not isinstance(mob.renderer_data, GLRenderData):
raise TypeError()
fill_data = np.zeros(len(mob.points), dtype=fill_dtype)
fill_data["point"] = mob.points
fill_data["color"] = mob.renderer_data.fill_rgbas
# fill_data["orientation"] = mob.renderer_data.orientation
fill_data["unit_normal"] = mob.renderer_data.normals
fill_data["vert_index"] = np.reshape(range(len(mob.points)), (-1, 1))
return fill_data
@override
def render_vmobject(self, mob: OpenGLVMobject, camera: OpenGLCameraFrame) -> None:
def render_vmobject(self, mob: OpenGLVMobject) -> None:
# Setting camera uniforms
if mob.renderer_data is None:
@ -201,20 +288,25 @@ class OpenGLRenderer(Renderer):
logger.debug("Initializing GLRenderData")
mob.renderer_data = GLRenderData()
# Generate Mesh
mob.renderer_data.mesh, mob.renderer_data.orientation = get_triangulation(
mob
)
mesh_length = len(mob.renderer_data.mesh)
(
mob.renderer_data.vert_indices,
mob.renderer_data.orientation,
) = get_triangulation(mob)
points_length = len(mob.points)
# Generate Fill Color
fill_color = np.array([c._internal_value for c in mob.fill_color])
stroke_color = np.array([c._internal_value for c in mob.stroke_color])
mob.renderer_data.fill_rgbas = prepare_array(fill_color, mesh_length)
mob.renderer_data.stroke_rgbas = prepare_array(stroke_color, mesh_length)
mob.renderer_data.fill_rgbas = prepare_array(fill_color, points_length)
mob.renderer_data.stroke_rgbas = prepare_array(stroke_color, points_length)
mob.renderer_data.stroke_widths = prepare_array(
np.asarray(listify(mob.stroke_width)), points_length
)
mob.renderer_data.normals = np.repeat(
[mob.get_unit_normal()], mesh_length, axis=0
[mob.get_unit_normal()], points_length, axis=0
)
mob.renderer_data.bounding_box = compute_bounding_box(mob)
print(mob.renderer_data)
# print(mob.renderer_data.mesh)
# print(mob.renderer_data.orientation)
@ -227,6 +319,46 @@ class OpenGLRenderer(Renderer):
# if(mob.has_fill()):
# mob.renderer_data.mesh = ... # Triangulation todo
# self.vmobject_fill_program['reflectiveness'].value = mob.reflectiveness
self.vmobject_fill_program["gloss"].value = mob.gloss
self.vmobject_fill_program["shadow"].value = mob.shadow
# self.vmobject_stroke_program['reflectiveness'].value = mob.reflectiveness
self.vmobject_stroke_program["gloss"].value = mob.gloss
self.vmobject_stroke_program["shadow"].value = mob.shadow
self.vmobject_stroke_program["joint_type"].value = float(
mob.joint_type.value
) # TODO: This maybe breaks
self.vmobject_stroke_program["flat_stroke"].value = mob.flat_stroke
def render_shader(prog, mob, data):
vbo = self.ctx.buffer(data.tobytes())
ibo = self.ctx.buffer(mob.renderer_data.vert_indices)
# print(prog,vbo,data)
vert_format = gl.detect_format(prog, data.dtype.names)
# print(vert_format)
vao = self.ctx.vertex_array(
program=prog,
content=[(vbo, vert_format, *data.dtype.names)],
index_buffer=ibo,
)
self.target_fbo.use()
self.target_fbo.clear(*self.background_color)
vao.render(gl.TRIANGLES)
vbo.release()
ibo.release()
vao.release()
# print(self.get_fill_shader_data(mob))
self.ctx.enable(gl.BLEND)
self.ctx.enable(gl.DEPTH_TEST)
render_shader(self.vmobject_fill_program, mob, self.get_fill_shader_data(mob))
# render_shader(self.vmobject_stroke_program, mob, stroke_dtype, self.get_stroke_shader_data(mob))
# print(self.target_fbo.read())
self.ctx.copy_framebuffer(self.output_fbo, self.target_fbo)
# Image.frombytes('RGBA', self.output_fbo.size, self.output_fbo.read(components=4), 'raw', 'RGBA', 0, -1).show()
# set shader
# use vbo
# render fill

View file

@ -75,6 +75,9 @@ def load_shader_program_by_folder(ctx: gl.Context, folder_name: str):
vertex_code = get_shader_code_from_file(Path(folder_name + "/vert.glsl"))
geometry_code = get_shader_code_from_file(Path(folder_name + "/geom.glsl"))
fragment_code = get_shader_code_from_file(Path(folder_name + "/frag.glsl"))
# print(folder_name)
# for i,l in enumerate(geometry_code.splitlines()):
# print(str(i) + ":" + l )
if vertex_code is None or fragment_code is None:
logger.error(
f"Invalid program definition for {folder_name} vertex or fragment shader not present"

View file

@ -9,7 +9,7 @@ from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
from manim.mobject.types.image_mobject import ImageMobject
from manim.mobject.types.vectorized_mobject import VMobject
Image: TypeAlias = np.ndarray
ImageType: TypeAlias = np.ndarray
class RendererData:
@ -21,13 +21,12 @@ class Renderer(ABC):
self.fbo = np.zeros((config.height, config.width))
self.capabilities = {
VMobject: self.render_vmobject,
ImageMobject: self.render_imobject,
ImageMobject: self.render_image,
}
def render(self, camera, renderables: [VMobject]) -> Image: # Image
def render(self, camera, renderables: [VMobject]) -> ImageType: # Image
for mob in renderables:
if type(mob) in self.capabilities:
mob.points
self.capabilities[type(mob)](mob)
else:
print("WARNING: NOT SUPPORTED")

View file

@ -1,6 +1,7 @@
uniform vec2 frame_shape;
uniform vec2 pixel_shape;
uniform vec3 camera_offset;
uniform vec3 camera_center;
uniform mat3 camera_rotation;
uniform float is_fixed_in_frame;
uniform float is_fixed_orientation;
uniform vec3 fixed_orientation_center;
uniform float focal_distance;

View file

@ -1,53 +1,51 @@
vec3 float_to_color(float value, float min_val, float max_val, vec3[9] colormap_data)
{
vec3 float_to_color(float value, float min_val, float max_val, vec3[9] colormap_data){
float alpha = clamp((value - min_val) / (max_val - min_val), 0.0, 1.0);
int disc_alpha = min(int(alpha * 8), 7);
return mix(colormap_data[disc_alpha], colormap_data[disc_alpha + 1], 8.0 * alpha - disc_alpha);
return mix(
colormap_data[disc_alpha],
colormap_data[disc_alpha + 1],
8.0 * alpha - disc_alpha
);
}
vec4 add_light(vec4 color, vec3 point, vec3 unit_normal, vec3 light_coords, vec3 cam_coords, float reflectiveness,
float gloss, float shadow)
{
if (reflectiveness == 0.0 && gloss == 0.0 && shadow == 0.0)
return color;
vec4 result = color;
// Assume everything has already been rotated such that camera is in the z-direction
// cam_coords = vec3(0, 0, focal_distance);
vec3 to_camera = normalize(cam_coords - point);
vec3 to_light = normalize(light_coords - point);
vec4 add_light(vec4 color,
vec3 point,
vec3 unit_normal,
vec3 light_coords,
float gloss,
float shadow){
if(gloss == 0.0 && shadow == 0.0) return color;
// Note, this effectively treats surfaces as two-sided
// if(dot(to_camera, unit_normal) < 0) unit_normal *= -1;
float light_to_normal = dot(to_light, unit_normal);
// When unit normal points towards light, brighten
float bright_factor = max(light_to_normal, 0) * reflectiveness;
// For glossy surface, add extra shine if light beam go towards camera
vec3 light_reflection = -to_light + 2 * unit_normal * dot(to_light, unit_normal);
float light_to_cam = dot(light_reflection, to_camera);
float shine = gloss * exp(-3 * pow(1 - light_to_cam, 2));
bright_factor += shine;
result.rgb = mix(result.rgb, vec3(1.0), bright_factor);
if (light_to_normal < 0)
{
// Darken
result.rgb = mix(result.rgb, vec3(0.0), -light_to_normal * shadow);
// TODO, do we actually want this? It effectively treats surfaces as two-sided
if(unit_normal.z < 0){
unit_normal *= -1;
}
// float darkening = mix(1, max(light_to_normal, 0), shadow);
// return vec4(
// darkening * mix(color.rgb, vec3(1.0), shine),
// color.a
// );
return result;
// TODO, read this in as a uniform?
float camera_distance = 6;
// 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 dp2 = dot(normalize(to_light), unit_normal);
float darkening = mix(1, max(dp2, 0), shadow);
return vec4(
darkening * mix(color.rgb, vec3(1.0), shine),
color.a
);
}
vec4 finalize_color(vec4 color, vec3 point, vec3 unit_normal, vec3 light_coords, vec3 cam_coords, float reflectiveness,
float gloss, float shadow)
{
vec4 finalize_color(vec4 color,
vec3 point,
vec3 unit_normal,
vec3 light_coords,
float gloss,
float shadow){
///// INSERT COLOR FUNCTION HERE /////
// The line above may be replaced by arbitrary code snippets, as per
// the method Mobject.set_color_by_code
return add_light(color, point, unit_normal, light_coords, cam_coords, reflectiveness, gloss, shadow);
return add_light(color, point, unit_normal, light_coords, gloss, shadow);
}

View file

@ -1,22 +1,25 @@
// Assumes the following uniforms exist in the surrounding context:
// uniform float is_fixed_in_frame;
// uniform vec3 camera_offset;
// uniform float is_fixed_orientation;
// uniform vec3 fixed_orientation_center;
// uniform vec3 camera_center;
// uniform mat3 camera_rotation;
vec3 rotate_point_into_frame(vec3 point)
{
if (bool(is_fixed_in_frame))
{
vec3 rotate_point_into_frame(vec3 point){
if(bool(is_fixed_in_frame)){
return point;
}
return camera_rotation * point;
}
vec3 position_point_into_frame(vec3 point)
{
if (bool(is_fixed_in_frame))
{
vec3 position_point_into_frame(vec3 point){
if(bool(is_fixed_in_frame)){
return point;
}
return rotate_point_into_frame(point - camera_offset);
if(bool(is_fixed_orientation)){
vec3 new_center = rotate_point_into_frame(fixed_orientation_center);
return point + (new_center - fixed_orientation_center);
}
return rotate_point_into_frame(point - camera_center);
}

View file

@ -1,9 +1,9 @@
#version 330
#include "../include/camera_uniform_declarations.glsl"
#include ../include/camera_uniform_declarations.glsl
in vec4 color;
in float fill_all; // Either 0 or 1
in float fill_all; // Either 0 or 1e
in float uv_anti_alias_width;
in float orientation;
@ -14,10 +14,8 @@ out vec4 frag_color;
#define ANTI_ALIASING
float sdf()
{
if (bezier_degree < 2)
{
float sdf(){
if(bezier_degree < 2){
return abs(uv_coords[1]);
}
vec2 p = uv_coords;
@ -31,13 +29,11 @@ float sdf()
#endif
}
void main()
{
if (color.a == 0)
discard;
void main() {
if (color.a == 0) discard;
frag_color = color;
if (fill_all == 1.0)
return;
if (fill_all == 1.0) return;
#ifdef ANTI_ALIASING
frag_color.a *= 0.5 - sdf(); // Anti-aliasing
#endif

View file

@ -1,24 +1,23 @@
#version 330
layout(triangles) in;
layout(triangle_strip, max_vertices = 5) out;
layout (triangles) in;
layout (triangle_strip, max_vertices = 5) out;
uniform float anti_alias_width;
// Needed for get_gl_Position
uniform vec2 frame_shape;
uniform vec2 pixel_shape;
uniform float focal_distance;
uniform float is_fixed_in_frame;
uniform float is_fixed_orientation;
uniform vec3 fixed_orientation_center;
// Needed for finalize_color
uniform vec3 light_source_position;
uniform vec3 camera_position;
uniform float reflectiveness;
uniform float gloss;
uniform float shadow;
in vec3 bp[3];
in float v_orientation[3];
in vec3 v_global_unit_normal[3];
in vec4 v_color[3];
in float v_vert_index[3];
@ -30,14 +29,10 @@ out vec2 uv_coords;
out float bezier_degree;
// Analog of import for manim only
// Comment to prevent formatting
#include "../include/quadratic_bezier_geometry_functions.glsl"
//
#include "../include/get_gl_Position.glsl"
//
#include "../include/get_unit_normal.glsl"
//
#include "../include/finalize_color.glsl"
#include ../include/quadratic_bezier_geometry_functions.glsl
#include ../include/get_gl_Position.glsl
#include ../include/get_unit_normal.glsl
#include ../include/finalize_color.glsl
const vec2 uv_coords_arr[3] = vec2[3](vec2(0, 0), vec2(0.5, 0), vec2(1, 1));
@ -51,31 +46,31 @@ void emit_vertex_wrapper(vec3 point, int index)
void emit_simple_triangle()
{
for (int i = 0; i < 3; i++)
for(int i = 0; i < 3; i++)
{
emit_vertex_wrapper(bp[i], i);
}
EndPrimitive();
}
void main()
{
void main(){
// If vert indices are sequential, don't fill all
fill_all = float((v_vert_index[1] - v_vert_index[0]) != 1.0 || (v_vert_index[2] - v_vert_index[1]) != 1.0);
fill_all = float(
(v_vert_index[1] - v_vert_index[0]) != 1.0 ||
(v_vert_index[2] - v_vert_index[1]) != 1.0
);
if (fill_all == 1.0)
{
if(fill_all == 1.0){
emit_simple_triangle();
return;
}
vec3 new_bp[3];
bezier_degree = get_reduced_control_points(vec3[3](bp[0], bp[1], bp[2]), new_bp);
unit_normal = get_unit_normal(new_bp);
orientation = v_orientation[0];
vec3 local_unit_normal = get_unit_normal(new_bp);
orientation = sign(dot(v_global_unit_normal[0], local_unit_normal));
if (bezier_degree >= 1)
{
if(bezier_degree >= 1){
emit_simple_triangle();
}
// Don't emit any vertices for bezier_degree 0

View file

@ -1,24 +1,24 @@
#version 330
#include "../include/camera_uniform_declarations.glsl"
#include ../include/camera_uniform_declarations.glsl
in vec3 point;
in float orientation;
in vec3 unit_normal;
in vec4 color;
in float vert_index;
out vec3 bp; // Bezier control point
out float v_orientation;
out vec4 v_color;
out float v_vert_index;
out vec3 v_global_unit_normal;
// Analog of import for manim only
#include "../include/position_point_into_frame.glsl"
#include ../include/position_point_into_frame.glsl
void main()
{
bp = position_point_into_frame(point);
v_orientation = orientation;
void main(){
bp = position_point_into_frame(point.xyz);
v_global_unit_normal = rotate_point_into_frame(unit_normal);
v_color = color;
v_vert_index = vert_index;
}

View file

@ -1,6 +1,6 @@
#version 330
#include "../include/camera_uniform_declarations.glsl"
#include ../include/camera_uniform_declarations.glsl
in vec2 uv_coords;
in vec2 uv_b2;
@ -20,25 +20,25 @@ in float bezier_degree;
out vec4 frag_color;
float cross2d(vec2 v, vec2 w)
{
float cross2d(vec2 v, vec2 w){
return v.x * w.y - w.x * v.y;
}
float modify_distance_for_endpoints(vec2 p, float dist, float t)
{
float modify_distance_for_endpoints(vec2 p, float dist, float t){
float buff = 0.5 * uv_stroke_width - uv_anti_alias_width;
// Check the beginning of the curve
if (t == 0)
{
if(t == 0){
// Clip the start
if (has_prev == 0)
return max(dist, -p.x + buff);
if(has_prev == 0) return max(dist, -p.x + buff);
// Bevel start
if (bevel_start == 1)
{
if(bevel_start == 1){
float a = angle_from_prev;
mat2 rot = mat2(cos(a), sin(a), -sin(a), cos(a));
mat2 rot = mat2(
cos(a), sin(a),
-sin(a), cos(a)
);
// Dist for intersection of two lines
float bevel_d = max(abs(p.y), abs((rot * p).y));
// Dist for union of this intersection with the real curve
@ -47,29 +47,30 @@ float modify_distance_for_endpoints(vec2 p, float dist, float t)
return max(min(dist, bevel_d), dist / 2);
}
// Otherwise, start will be rounded off
}
else if (t == 1)
{
}else if(t == 1){
// Check the end of the curve
// TODO, too much code repetition
vec2 v21 = (bezier_degree == 2) ? vec2(1, 0) - uv_b2 : vec2(-1, 0);
float len_v21 = length(v21);
if (len_v21 == 0)
{
if(len_v21 == 0){
v21 = -uv_b2;
len_v21 = length(v21);
}
float perp_dist = dot(p - uv_b2, v21) / len_v21;
if (has_next == 0)
return max(dist, -perp_dist + buff);
if(has_next == 0) return max(dist, -perp_dist + buff);
// Bevel end
if (bevel_end == 1)
{
if(bevel_end == 1){
float a = -angle_to_next;
mat2 rot = mat2(cos(a), sin(a), -sin(a), cos(a));
mat2 rot = mat2(
cos(a), sin(a),
-sin(a), cos(a)
);
vec2 v21_unit = v21 / length(v21);
float bevel_d = max(abs(cross2d(p - uv_b2, v21_unit)), abs(cross2d((rot * (p - uv_b2)), v21_unit)));
float bevel_d = max(
abs(cross2d(p - uv_b2, v21_unit)),
abs(cross2d((rot * (p - uv_b2)), v21_unit))
);
return max(min(dist, bevel_d), dist / 2);
}
// Otherwise, end will be rounded off
@ -77,12 +78,12 @@ float modify_distance_for_endpoints(vec2 p, float dist, float t)
return dist;
}
#include "../include/quadratic_bezier_distance.glsl"
void main()
{
if (uv_stroke_width == 0)
discard;
#include ../include/quadratic_bezier_distance.glsl
void main() {
if (uv_stroke_width == 0) discard;
float dist_to_curve = min_dist_to_curve(uv_coords, uv_b2, bezier_degree);
// An sdf for the region around the curve we wish to color.
float signed_dist = abs(dist_to_curve) - 0.5 * uv_stroke_width;

View file

@ -1,28 +1,28 @@
#version 330
layout(triangles) in;
layout(triangle_strip, max_vertices = 5) out;
layout (triangles) in;
layout (triangle_strip, max_vertices = 5) out;
// Needed for get_gl_Position
uniform vec2 frame_shape;
uniform vec2 pixel_shape;
uniform float focal_distance;
uniform float is_fixed_in_frame;
uniform float is_fixed_orientation;
uniform vec3 fixed_orientation_center;
uniform float anti_alias_width;
uniform float flat_stroke;
// Needed for lighting
//Needed for lighting
uniform vec3 light_source_position;
uniform vec3 camera_position;
uniform float joint_type;
uniform float reflectiveness;
uniform float gloss;
uniform float shadow;
in vec3 bp[3];
in vec3 prev_bp[3];
in vec3 next_bp[3];
in vec3 v_global_unit_normal[3];
in vec4 v_color[3];
in float v_stroke_width[3];
@ -43,8 +43,6 @@ out float bezier_degree;
out vec2 uv_coords;
out vec2 uv_b2;
vec3 unit_normal;
// Codes for joint types
const float AUTO_JOINT = 0;
const float ROUND_JOINT = 1;
@ -52,61 +50,55 @@ const float BEVEL_JOINT = 2;
const float MITER_JOINT = 3;
const float PI = 3.141592653;
#include "../include/finalize_color.glsl"
#include "../include/get_gl_Position.glsl"
#include "../include/get_unit_normal.glsl"
#include "../include/quadratic_bezier_geometry_functions.glsl"
void flatten_points(in vec3[3] points, out vec2[3] flat_points)
{
for (int i = 0; i < 3; i++)
{
#include ../include/quadratic_bezier_geometry_functions.glsl
#include ../include/get_gl_Position.glsl
#include ../include/get_unit_normal.glsl
#include ../include/finalize_color.glsl
void flatten_points(in vec3[3] points, out vec2[3] flat_points){
for(int i = 0; i < 3; i++){
float sf = perspective_scale_factor(points[i].z, focal_distance);
flat_points[i] = sf * points[i].xy;
}
}
float angle_between_vectors(vec2 v1, vec2 v2)
{
float angle_between_vectors(vec2 v1, vec2 v2){
float v1_norm = length(v1);
float v2_norm = length(v2);
if (v1_norm == 0 || v2_norm == 0)
return 0.0;
if(v1_norm == 0 || v2_norm == 0) return 0.0;
float dp = dot(v1, v2) / (v1_norm * v2_norm);
float angle = acos(clamp(dp, -1.0, 1.0));
float sn = sign(cross2d(v1, v2));
return sn * angle;
}
bool find_intersection(vec2 p0, vec2 v0, vec2 p1, vec2 v1, out vec2 intersection)
{
bool find_intersection(vec2 p0, vec2 v0, vec2 p1, vec2 v1, out vec2 intersection){
// Find the intersection of a line passing through
// p0 in the direction v0 and one passing through p1 in
// the direction p1.
// That is, find a solutoin to p0 + v0 * t = p1 + v1 * s
float det = -v0.x * v1.y + v1.x * v0.y;
if (det == 0)
return false;
if(det == 0) return false;
float t = cross2d(p0 - p1, v1) / det;
intersection = p0 + v0 * t;
return true;
}
void create_joint(float angle, vec2 unit_tan, float buff, vec2 static_c0, out vec2 changing_c0, vec2 static_c1,
out vec2 changing_c1)
{
void create_joint(float angle, vec2 unit_tan, float buff,
vec2 static_c0, out vec2 changing_c0,
vec2 static_c1, out vec2 changing_c1){
float shift;
if (abs(angle) < 1e-3)
{
if(abs(angle) < 1e-3){
// No joint
shift = 0;
}
else if (joint_type == MITER_JOINT)
{
}else if(joint_type == MITER_JOINT){
shift = buff * (-1.0 - cos(angle)) / sin(angle);
}
else
{
}else{
// For a Bevel joint
shift = buff * (1.0 - cos(angle)) / sin(angle);
}
@ -114,11 +106,11 @@ void create_joint(float angle, vec2 unit_tan, float buff, vec2 static_c0, out ve
changing_c1 = static_c1 + shift * unit_tan;
}
// This function is responsible for finding the corners of
// a bounding region around the bezier curve, which can be
// emitted as a triangle fan
int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 corners[5])
{
int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 corners[5]){
vec2 p0 = controls[0];
vec2 p1 = controls[1];
vec2 p2 = controls[2];
@ -129,13 +121,13 @@ int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 c
vec2 v01 = -v10;
vec2 v21 = -v12;
vec2 p0_perp = vec2(-v01.y, v01.x); // Pointing to the left of the curve from p0
vec2 p2_perp = vec2(-v12.y, v12.x); // Pointing to the left of the curve from p2
vec2 p0_perp = vec2(-v01.y, v01.x); // Pointing to the left of the curve from p0
vec2 p2_perp = vec2(-v12.y, v12.x); // Pointing to the left of the curve from p2
// aaw is the added width given around the polygon for antialiasing.
// In case the normal is faced away from (0, 0, 1), the vector to the
// camera, this is scaled up.
float aaw = anti_alias_width * frame_shape.y / pixel_shape.y;
float aaw = anti_alias_width;
float buff0 = 0.5 * stroke_widths[0] + aaw;
float buff2 = 0.5 * stroke_widths[2] + aaw;
float aaw0 = (1 - has_prev) * aaw;
@ -147,92 +139,94 @@ int get_corners(vec2 controls[3], int degree, float stroke_widths[3], out vec2 c
vec2 c3 = p2 - buff2 * p2_perp + aaw2 * v12;
// Account for previous and next control points
if (has_prev > 0)
create_joint(angle_from_prev, v01, buff0, c0, c0, c1, c1);
if (has_next > 0)
create_joint(angle_to_next, v21, buff2, c3, c3, c2, c2);
if(has_prev > 0) create_joint(angle_from_prev, v01, buff0, c0, c0, c1, c1);
if(has_next > 0) create_joint(angle_to_next, v21, buff2, c3, c3, c2, c2);
// Linear case is the simplest
if (degree == 1)
{
// The order of corners should be for a triangle_strip. Last entry is a
// dummy
if(degree == 1){
// The order of corners should be for a triangle_strip. Last entry is a dummy
corners = vec2[5](c0, c1, c3, c2, vec2(0.0));
return 4;
}
// Otherwise, form a pentagon around the curve
float orientation = sign(cross2d(v01, v12)); // Positive for ccw curves
if (orientation > 0)
corners = vec2[5](c0, c1, p1, c2, c3);
else
corners = vec2[5](c1, c0, p1, c3, c2);
float orientation = sign(cross2d(v01, v12)); // Positive for ccw curves
if(orientation > 0) corners = vec2[5](c0, c1, p1, c2, c3);
else corners = vec2[5](c1, c0, p1, c3, c2);
// Replace corner[2] with convex hull point accounting for stroke width
find_intersection(corners[0], v01, corners[4], v21, corners[2]);
return 5;
}
void set_adjascent_info(vec2 c0, vec2 tangent, int degree, vec2 adj[3], out float bevel, out float angle)
{
void set_adjascent_info(vec2 c0, vec2 tangent,
int degree,
vec2 adj[3],
out float bevel,
out float angle
){
bool linear_adj = (angle_between_vectors(adj[1] - adj[0], adj[2] - adj[1]) < 1e-3);
angle = angle_between_vectors(c0 - adj[1], tangent);
// Decide on joint type
bool one_linear = (degree == 1 || linear_adj);
bool should_bevel = ((joint_type == AUTO_JOINT && one_linear) || joint_type == BEVEL_JOINT);
bool should_bevel = (
(joint_type == AUTO_JOINT && one_linear) ||
joint_type == BEVEL_JOINT
);
bevel = should_bevel ? 1.0 : 0.0;
}
void find_joint_info(vec2 controls[3], vec2 prev[3], vec2 next[3], int degree)
{
void find_joint_info(vec2 controls[3], vec2 prev[3], vec2 next[3], int degree){
float tol = 1e-6;
// Made as floats not bools so they can be passed to the frag shader
has_prev = float(distance(prev[2], controls[0]) < tol);
has_next = float(distance(next[0], controls[2]) < tol);
if (bool(has_prev))
{
if(bool(has_prev)){
vec2 tangent = controls[1] - controls[0];
set_adjascent_info(controls[0], tangent, degree, prev, bevel_start, angle_from_prev);
set_adjascent_info(
controls[0], tangent, degree, prev,
bevel_start, angle_from_prev
);
}
if (bool(has_next))
{
if(bool(has_next)){
vec2 tangent = controls[1] - controls[2];
set_adjascent_info(controls[2], tangent, degree, next, bevel_end, angle_to_next);
set_adjascent_info(
controls[2], tangent, degree, next,
bevel_end, angle_to_next
);
angle_to_next *= -1;
}
}
void main()
{
void main() {
// Convert control points to a standard form if they are linear or null
vec3 controls[3];
vec3 prev[3];
vec3 next[3];
unit_normal = get_unit_normal(controls);
bezier_degree = get_reduced_control_points(vec3[3](bp[0], bp[1], bp[2]), controls);
if (bezier_degree == 0.0)
return; // Null curve
if(bezier_degree == 0.0) return; // Null curve
int degree = int(bezier_degree);
get_reduced_control_points(vec3[3](prev_bp[0], prev_bp[1], prev_bp[2]), prev);
get_reduced_control_points(vec3[3](next_bp[0], next_bp[1], next_bp[2]), next);
// Adjust stroke width based on distance from the camera
float scaled_strokes[3];
for (int i = 0; i < 3; i++)
{
for(int i = 0; i < 3; i++){
float sf = perspective_scale_factor(controls[i].z, focal_distance);
if (bool(flat_stroke))
{
if(bool(flat_stroke)){
vec3 to_cam = normalize(vec3(0.0, 0.0, focal_distance) - controls[i]);
sf *= abs(dot(unit_normal, to_cam));
sf *= abs(dot(v_global_unit_normal[i], to_cam));
}
scaled_strokes[i] = v_stroke_width[i] * sf;
}
// Control points are projected to the xy plane before drawing, which in turn
// gets tranlated to a uv plane. The z-coordinate information will be
// remembered by what's sent out to gl_Position, and by how it affects the
// lighting and stroke width
// gets translated to a uv plane. The z-coordinate information will be remembered
// by what's sent out to gl_Position, and by how it affects the lighting and stroke width
vec2 flat_controls[3];
vec2 flat_prev[3];
vec2 flat_next[3];
@ -247,26 +241,33 @@ void main()
int n_corners = get_corners(flat_controls, degree, scaled_strokes, corners);
int index_map[5] = int[5](0, 0, 1, 2, 2);
if (n_corners == 4)
index_map[2] = 2;
if(n_corners == 4) index_map[2] = 2;
// Find uv conversion matrix
mat3 xy_to_uv = get_xy_to_uv(flat_controls[0], flat_controls[1]);
float scale_factor = length(flat_controls[1] - flat_controls[0]);
uv_anti_alias_width = anti_alias_width * frame_shape.y / pixel_shape.y / scale_factor;
uv_anti_alias_width = anti_alias_width / scale_factor;
uv_b2 = (xy_to_uv * vec3(flat_controls[2], 1.0)).xy;
// Emit each corner
for (int i = 0; i < n_corners; i++)
{
for(int i = 0; i < n_corners; i++){
uv_coords = (xy_to_uv * vec3(corners[i], 1.0)).xy;
uv_stroke_width = scaled_strokes[index_map[i]] / scale_factor;
// Apply some lighting to the color before sending out.
// vec3 xyz_coords = vec3(corners[i], controls[index_map[i]].z);
vec3 xyz_coords = vec3(corners[i], controls[index_map[i]].z);
color = finalize_color(v_color[index_map[i]], xyz_coords, unit_normal, light_source_position, camera_position,
reflectiveness, gloss, shadow);
gl_Position = vec4(get_gl_Position(vec3(corners[i], 0.0)).xy, get_gl_Position(controls[index_map[i]]).zw);
color = finalize_color(
v_color[index_map[i]],
xyz_coords,
v_global_unit_normal[index_map[i]],
light_source_position,
gloss,
shadow
);
gl_Position = vec4(
get_gl_Position(vec3(corners[i], 0.0)).xy,
get_gl_Position(controls[index_map[i]]).zw
);
EmitVertex();
}
EndPrimitive();

View file

@ -1,10 +1,11 @@
#version 330
#include "../include/camera_uniform_declarations.glsl"
#include ../include/camera_uniform_declarations.glsl
in vec3 point;
in vec3 prev_point;
in vec3 next_point;
in vec3 unit_normal;
in float stroke_width;
in vec4 color;
@ -13,20 +14,21 @@ in vec4 color;
out vec3 bp;
out vec3 prev_bp;
out vec3 next_bp;
out vec3 v_global_unit_normal;
out float v_stroke_width;
out vec4 v_color;
const float STROKE_WIDTH_CONVERSION = 0.01;
#include "../include/position_point_into_frame.glsl"
#include ../include/position_point_into_frame.glsl
void main()
{
void main(){
bp = position_point_into_frame(point);
prev_bp = position_point_into_frame(prev_point);
next_bp = position_point_into_frame(next_point);
v_global_unit_normal = rotate_point_into_frame(unit_normal);
v_stroke_width = STROKE_WIDTH_CONVERSION * stroke_width * frame_shape[1] / 8.0;
v_stroke_width = STROKE_WIDTH_CONVERSION * stroke_width;
v_color = color;
}