Working Shading in 3D many many tries

This commit is contained in:
Tristan Schulz 2023-09-12 18:25:34 +02:00
commit ab44633082
4 changed files with 77 additions and 39 deletions

View file

@ -1,13 +1,14 @@
import time
import numpy as np
import pyglet
from PIL import Image
from pyglet import shapes
from pyglet.gl import Config
from pyglet.window import Window
import numpy as np
import manim.utils.color.manim_colors as col
from manim._config import tempconfig
from manim._config import config, tempconfig
from manim.camera.camera import OpenGLCamera, OpenGLCameraFrame
from manim.constants import OUT, RIGHT, UP
from manim.mobject.geometry.arc import Circle
@ -15,7 +16,6 @@ from manim.mobject.geometry.polygram import Square
from manim.mobject.logo import ManimBanner
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
from manim.renderer.opengl_renderer import OpenGLRenderer
from manim._config import config
if __name__ == "__main__":
with tempconfig({"renderer": "opengl"}):
@ -24,7 +24,9 @@ if __name__ == "__main__":
vm = Circle(
radius=1, stroke_color=col.YELLOW, fill_opacity=1, fill_color=col.RED
).shift(RIGHT)
vm2 = Square(stroke_color=col.GREEN, fill_opacity=0, stroke_opacity=1).move_to((0,0,-0.5))
vm2 = Square(stroke_color=col.GREEN, fill_opacity=0, stroke_opacity=1).move_to(
(0, 0, -0.5)
)
vm3 = ManimBanner()
# vm.set_points_as_corners([[-1920/2, 0, 0], [1920/2, 0, 0], [0, 1080/2, 0]])
# print(vm.color)
@ -52,14 +54,20 @@ if __name__ == "__main__":
vm2.apply_depth_test()
vm3.apply_depth_test()
clock = pyglet.clock.get_default()
def update_circle(dt):
vm.move_to((np.sin(dt), np.cos(dt), -1))
clock.schedule(update_circle)
def p2m(x,y,z):
def p2m(x, y, z):
from manim._config import config
return (config.frame_width*(x/config.pixel_width-0.5), config.frame_height*(y/config.pixel_height-0.5),z)
return (
config.frame_width * (x / config.pixel_width - 0.5),
config.frame_height * (y / config.pixel_height - 0.5),
z,
)
@win.event
def on_close():
@ -68,9 +76,14 @@ if __name__ == "__main__":
@win.event
def on_mouse_motion(x, y, dx, dy):
# vm.move_to((14.2222 * (x / 1920 - 0.5), 8 * (y / 1080 - 0.5), 0))
#camera.move_to(p2m(x,y,camera.get_center()[2]))
# camera.move_to(p2m(x,y,camera.get_center()[2]))
from scipy.spatial.transform import Rotation
camera.set_orientation(Rotation.from_rotvec((-UP*(x/1920-0.5)+RIGHT*(y/1080-0.5))*2*3.1415))
camera.set_orientation(
Rotation.from_rotvec(
(-UP * (x / 1920 - 0.5) + RIGHT * (y / 1080 - 0.5)) * 2 * 3.1415
)
)
# vm.set_color(col.RED.interpolate(col.GREEN,x/1920))
# print(x,y)

View file

@ -1,13 +1,13 @@
from __future__ import annotations
import copy
from dataclasses import dataclass
import itertools as it
import numbers
import os
import pickle
import random
import sys
from dataclasses import dataclass
from functools import partialmethod, wraps
from math import ceil
from typing import TYPE_CHECKING
@ -52,7 +52,9 @@ if TYPE_CHECKING:
from typing_extensions import Self, TypeAlias
TimeBasedUpdater: TypeAlias = Callable[["OpenGLMobject", float], "OpenGLMobject" | None]
TimeBasedUpdater: TypeAlias = Callable[
["OpenGLMobject", float], "OpenGLMobject" | None
]
NonTimeUpdater: TypeAlias = Callable[["OpenGLMobject"], "OpenGLMobject" | None]
Updater: TypeAlias = Union[TimeBasedUpdater, NonTimeUpdater]
PointUpdateFunction: TypeAlias = Callable[[np.ndarray], np.ndarray]
@ -91,6 +93,7 @@ def affects_shader_info_id(func):
return wrapper
@dataclass
class MobjectStatus:
color_changed: bool = False
@ -99,6 +102,7 @@ class MobjectStatus:
scale_changed: bool = False
points_changed: bool = False
class OpenGLMobject:
"""Mathematical Object: base class for objects that can be displayed on screen.

View file

@ -456,7 +456,7 @@ class OpenGLVMobject(OpenGLMobject):
def has_stroke(self) -> bool:
# TODO: This currently doesn't make sense needs fixing
return self.stroke_width>0 and any(self.get_stroke_opacities())
return self.stroke_width > 0 and any(self.get_stroke_opacities())
def has_fill(self) -> bool:
return any(self.get_fill_opacities())

View file

@ -224,23 +224,37 @@ class OpenGLRenderer(Renderer):
self.ctx = gl.create_context()
# Those are the actual buffers that are used for rendering
self.stencil_texture = self.ctx.texture((self.pixel_width, self.pixel_height), components=1, samples=0, dtype='f1')
self.stencil_buffer = self.ctx.renderbuffer((self.pixel_width, self.pixel_height), components=1, samples=0, dtype='f1')
self.color_buffer = self.ctx.renderbuffer((self.pixel_width, self.pixel_height), components=4,samples=0,dtype='f1')
self.stencil_texture = self.ctx.texture(
(self.pixel_width, self.pixel_height), components=1, samples=0, dtype="f1"
)
self.stencil_buffer = self.ctx.renderbuffer(
(self.pixel_width, self.pixel_height), components=1, samples=0, dtype="f1"
)
self.color_buffer = self.ctx.renderbuffer(
(self.pixel_width, self.pixel_height), components=4, samples=0, dtype="f1"
)
# Here we create different fbos that can be reused which are basically just targets to use for rendering and copy
# render_target_fbo is used for rendering it can write to color and stencil
self.render_target_fbo = self.ctx.framebuffer(
color_attachments=[ self.color_buffer,self.stencil_buffer]
,depth_attachment=self.ctx.depth_renderbuffer((self.pixel_width, self.pixel_height), samples=0)
color_attachments=[self.color_buffer, self.stencil_buffer],
depth_attachment=self.ctx.depth_renderbuffer(
(self.pixel_width, self.pixel_height), samples=0
),
)
# this is used as source for stencil copy
self.stencil_buffer_fbo = self.ctx.framebuffer(color_attachments=[self.stencil_buffer])
self.stencil_buffer_fbo = self.ctx.framebuffer(
color_attachments=[self.stencil_buffer]
)
# this is used as destination for stencil copy
self.stencil_texture_fbo = self.ctx.framebuffer(color_attachments=[self.stencil_texture])
self.stencil_texture_fbo = self.ctx.framebuffer(
color_attachments=[self.stencil_texture]
)
# this is used as source for copying color to the output
self.color_buffer_fbo = self.ctx.framebuffer(color_attachments=[self.color_buffer])
self.color_buffer_fbo = self.ctx.framebuffer(
color_attachments=[self.color_buffer]
)
self.output_fbo = self.ctx.framebuffer(
color_attachments=[
@ -266,7 +280,7 @@ class OpenGLRenderer(Renderer):
def init_camera(self, camera: OpenGLCameraFrame):
uniforms = dict()
uniforms["frame_shape"] = camera.frame_shape
uniforms['pixel_shape'] = (self.pixel_width,self.pixel_height)
uniforms["pixel_shape"] = (self.pixel_width, self.pixel_height)
uniforms["focal_distance"] = camera.get_focal_distance()
uniforms["camera_center"] = tuple(camera.get_center())
uniforms["camera_rotation"] = tuple(
@ -319,9 +333,13 @@ class OpenGLRenderer(Renderer):
def post_render(self):
self.ctx.copy_framebuffer(self.output_fbo, self.color_buffer_fbo)
def render_program(self, prog, data, indices = None):
def render_program(self, prog, data, indices=None):
vbo = self.ctx.buffer(data.tobytes())
ibo = self.ctx.buffer(np.asarray(indices).astype("i4").tobytes()) if indices is not None else None
ibo = (
self.ctx.buffer(np.asarray(indices).astype("i4").tobytes())
if indices is not None
else None
)
# print(prog,vbo,data)
vert_format = gl.detect_format(prog, data.dtype.names)
# print(vert_format)
@ -337,7 +355,7 @@ class OpenGLRenderer(Renderer):
ibo.release()
vao.release()
def render_vmobject(self, mob: OpenGLVMobject) -> None: #type: ignore
def render_vmobject(self, mob: OpenGLVMobject) -> None: # type: ignore
self.stencil_buffer_fbo.use()
self.stencil_buffer_fbo.clear()
self.render_target_fbo.use()
@ -360,7 +378,7 @@ class OpenGLRenderer(Renderer):
# mob.renderer_data.mesh = ... # Triangulation todo
# self.ctx.enable(gl.CULL_FACE)
self.ctx.enable(gl.BLEND) #type: ignore
self.ctx.enable(gl.BLEND) # type: ignore
# TODO: Because the Triangulation is messing up the normals this won't work
# self.ctx.blend_func = ( #type: ignore
# gl.SRC_ALPHA,
@ -369,40 +387,43 @@ class OpenGLRenderer(Renderer):
# gl.ONE,
# )
if sub.depth_test:
self.ctx.enable(gl.DEPTH_TEST) #type: ignore
self.ctx.enable(gl.DEPTH_TEST) # type: ignore
else:
self.ctx.disable(gl.DEPTH_TEST) #type: ignore
self.ctx.disable(gl.DEPTH_TEST) # type: ignore
num_mobs = len(mob.family_members_with_points())
for counter,sub in enumerate(mob.family_members_with_points()):
for counter, sub in enumerate(mob.family_members_with_points()):
if not isinstance(sub.renderer_data, GLRenderData):
return
uniforms = GLVMobjectManager.read_uniforms(sub)
# uniforms['z_shift'] = counter/9
uniforms['index'] = (counter + 1)/num_mobs
self.ctx.copy_framebuffer(self.stencil_texture_fbo,self.stencil_buffer_fbo)
uniforms["index"] = (counter + 1) / num_mobs
self.ctx.copy_framebuffer(self.stencil_texture_fbo, self.stencil_buffer_fbo)
self.stencil_texture.use(0)
self.vmobject_fill_program['stencil_texture'] = 0
self.vmobject_fill_program["stencil_texture"] = 0
if sub.has_fill():
ProgramManager.write_uniforms(self.vmobject_fill_program, uniforms)
self.render_program(
self.vmobject_fill_program, self.get_fill_shader_data(sub), sub.renderer_data.vert_indices
self.vmobject_fill_program,
self.get_fill_shader_data(sub),
sub.renderer_data.vert_indices,
)
for counter,sub in enumerate(mob.family_members_with_points()):
for counter, sub in enumerate(mob.family_members_with_points()):
if not isinstance(sub.renderer_data, GLRenderData):
return
uniforms = GLVMobjectManager.read_uniforms(sub)
uniforms['index'] = (counter + 1)/num_mobs
uniforms["index"] = (counter + 1) / num_mobs
# uniforms['z_shift'] = counter/9 + 1/20
self.ctx.copy_framebuffer(self.stencil_texture_fbo,self.stencil_buffer_fbo)
self.ctx.copy_framebuffer(self.stencil_texture_fbo, self.stencil_buffer_fbo)
self.stencil_texture.use(0)
self.vmobject_stroke_program['stencil_texture'] = 0
self.vmobject_stroke_program["stencil_texture"] = 0
if sub.has_stroke():
ProgramManager.write_uniforms(self.vmobject_stroke_program, uniforms)
self.render_program(
self.vmobject_stroke_program, self.get_stroke_shader_data(sub), np.array(range(len(sub.points)))[::-1]
self.vmobject_stroke_program,
self.get_stroke_shader_data(sub),
np.array(range(len(sub.points)))[::-1],
)
counter += 1
@ -415,7 +436,7 @@ class OpenGLRenderer(Renderer):
class GLVMobjectManager:
@staticmethod
def init_render_data(mob:OpenGLVMobject):
def init_render_data(mob: OpenGLVMobject):
logger.debug("Initializing GLRenderData")
mob.renderer_data = GLRenderData()
@ -440,7 +461,7 @@ class GLVMobjectManager:
@staticmethod
def read_uniforms(mob: OpenGLVMobject):
uniforms = {}
uniforms['reflectiveness'] = mob.reflectiveness
uniforms["reflectiveness"] = mob.reflectiveness
uniforms["is_fixed_in_frame"] = float(mob.is_fixed_in_frame)
uniforms["is_fixed_orientation"] = float(mob.is_fixed_orientation)
uniforms["gloss"] = mob.gloss