def __init__(self, name, **kwargs): """Create a scene with a name. Args: name (str): Unique name or path for the scene """ self.name = name self.root_nodes = [] # References resources in the scene self.nodes = [] self.materials = [] self.meshes = [] self.cameras = [] self.bbox_min = None # Type: numpy.ndarray self.bbox_max = None # Type: numpy.ndarray self.diagonal_size = 1.0 self.bbox_vao = geometry.bbox() global DEFAULT_BBOX_PROGRAM if DEFAULT_BBOX_PROGRAM is None: DEFAULT_BBOX_PROGRAM = programs.load( ProgramDescription(path='scene_default/bbox.glsl'), ) self.bbox_program = DEFAULT_BBOX_PROGRAM global DEFAULT_WIREFRAME_PROGRAM if DEFAULT_WIREFRAME_PROGRAM is None: DEFAULT_WIREFRAME_PROGRAM = programs.load( ProgramDescription(path='scene_default/wireframe.glsl'), ) self.wireframe_program = DEFAULT_WIREFRAME_PROGRAM self._matrix = matrix44.create_identity(dtype='f4')
def test_compute_shader(self): """Attempt loading a compute shader""" path = 'programs/compute.glsl' descr = ProgramDescription(compute_shader=path) self.assertEqual(descr.compute_shader, path) program = resources.programs.load(descr) self.assertIsInstance(program, moderngl.ComputeShader)
def __init__(self): super().__init__() meta = FontMeta( resources.data.load( DataDescription(path="bitmapped/text/meta.json"))) self._texture = resources.textures.load( TextureDescription( path="bitmapped/textures/VeraMono.png", kind="array", mipmap=True, layers=meta.characters, )) self._program = resources.programs.load( ProgramDescription(path="bitmapped/programs/text_2d.glsl")) self._init(meta) self._string_buffer = self.ctx.buffer(reserve=1024 * 4) self._string_buffer.clear(chunk=b'\32') pos = self.ctx.buffer(data=bytes([0] * 4 * 3)) self._vao = VAO("textwriter", mode=moderngl.POINTS) self._vao.buffer(pos, '3f', 'in_position') self._vao.buffer(self._string_buffer, '1u/i', 'in_char_id') self._text: str = None
def load_program(self, path=None, vertex_shader=None, geometry_shader=None, fragment_shader=None, tess_control_shader=None, tess_evaluation_shader=None) -> moderngl.Program: """Loads a shader program. Note that `path` should only be used if all shaders are defined in the same glsl file separated by defines. Keyword Args: path (str): Path to a single glsl file vertex_shader (str): Path to vertex shader geometry_shader (str): Path to geometry shader fragment_shader (str): Path to fragment shader tess_control_shader (str): Path to tessellation control shader tess_evaluation_shader (str): Path to tessellation eval shader Returns: moderngl.Program: The program instance """ return resources.programs.load( ProgramDescription( path=path, vertex_shader=vertex_shader, geometry_shader=geometry_shader, fragment_shader=fragment_shader, tess_control_shader=tess_control_shader, tess_evaluation_shader=tess_evaluation_shader, ))
def load_program(self, path=None, vertex_shader=None, geometry_shader=None, fragment_shader=None, tess_control_shader=None, tess_evaluation_shader=None, defines: dict = None) -> moderngl.Program: """Loads a shader program. Note that `path` should only be used if all shaders are defined in the same glsl file separated by defines. Keyword Args: path (str): Path to a single glsl file vertex_shader (str): Path to vertex shader geometry_shader (str): Path to geometry shader fragment_shader (str): Path to fragment shader tess_control_shader (str): Path to tessellation control shader tess_evaluation_shader (str): Path to tessellation eval shader defines (dict): ``#define`` values to replace in the shader source. Example: ``{'VALUE1': 10, 'VALUE2': '3.1415'}``. Returns: moderngl.Program: The program instance """ return resources.programs.load( ProgramDescription( path=path, vertex_shader=vertex_shader, geometry_shader=geometry_shader, fragment_shader=fragment_shader, tess_control_shader=tess_control_shader, tess_evaluation_shader=tess_evaluation_shader, defines=defines, ))
def test_separate_geometry(self): program = resources.programs.load( ProgramDescription( vertex_shader="programs/billboards/billboards_vs.glsl", geometry_shader="programs/billboards/billboards_gs.glsl", fragment_shader="programs/billboards/billboards_fs.glsl", )) self.assertIsInstance(program, moderngl.Program)
def test_single(self): """Load a single file glsl program""" program = resources.programs.load( ProgramDescription(path='programs/white.glsl')) self.assertIsInstance(program, moderngl.Program) # Ensure attribute is present program['in_position'] self.assertIsInstance(program.extra.get('meta'), ProgramDescription)
def test_separate_tesselation(self): """Load a more complex tesselation program from separate files""" program = resources.programs.load( ProgramDescription( vertex_shader="programs/terrain/terrain_vs.glsl", tess_control_shader="programs/terrain/terrain_tc.glsl", tess_evaluation_shader="programs/terrain/terrain_te.glsl", fragment_shader="programs/terrain/terrain_fs.glsl", )) self.assertIsInstance(program, moderngl.Program)
def test_separate_not_found(self): """Ensure ImproperlyConfigured is raised when shaders are not found""" with self.assertRaises(ImproperlyConfigured): resources.programs.load( ProgramDescription( vertex_shader="programs/notfound_vs.glsl", geometry_shader="programs/notfound_geo.glsl", tess_control_shader="programs/notfound_tc.glsl", tess_evaluation_shader="programs/notfound_te.glsl", fragment_shader="programs/notfound_fs.glsl", ))
def __init__(self, name, **kwargs): """Create a scene with a name. Args: name (str): Unique name or path for the scene """ self.name = name self.root_nodes = [] # References resources in the scene self.nodes = [] self.materials = [] self.meshes = [] self.cameras = [] self.bbox_min = None # Type: numpy.ndarray self.bbox_max = None # Type: numpy.ndarray self.diagonal_size = 1.0 self.bbox_vao = geometry.bbox() if self.ctx.extra is None: self.ctx.extra = {} # Load bbox program and cache in the context self.bbox_program = self.ctx.extra.get("DEFAULT_BBOX_PROGRAM") if not self.bbox_program: self.bbox_program = programs.load( ProgramDescription(path="scene_default/bbox.glsl"), ) self.ctx.extra["DEFAULT_BBOX_PROGRAM"] = self.bbox_program # Load wireframe program and cache in the context self.wireframe_program = self.ctx.extra.get( "DEFAULT_WIREFRAME_PROGRAM") if not self.wireframe_program: self.wireframe_program = programs.load( ProgramDescription(path="scene_default/wireframe.glsl"), ) self.ctx.extra[ "DEFAULT_WIREFRAME_PROGRAM"] = self.wireframe_program self._matrix = matrix44.create_identity(dtype="f4")
def test_render(self): """Render something simple to the framebuffer""" self.window.use() self.window.clear() prog = resources.programs.load( ProgramDescription(path="programs/white.glsl")) quad = geometry.quad_fs() quad.render(prog) # Ensure all fragments (rgba) values are white data = self.window.fbo.read(components=4) self.assertEqual( data, b'\xff' * (self.window_size[0] * self.window_size[1] * 4))
def resolve_loader(self, meta: ProgramDescription) -> None: """Resolve program loader. Determines if the references resource is a single or multiple glsl files unless ``kind`` is specified. Args: meta (ProgramDescription): The resource description """ if not meta.kind: meta.kind = 'single' if meta.path else 'separate' super().resolve_loader(meta)
def load_compute_shader(self, path, defines: dict = None, **kwargs) -> moderngl.ComputeShader: """Loads a compute shader. Args: path (str): Path to a single glsl file defines (dict): ``#define`` values to replace in the shader source Returns: moderngl.ComputeShader: The compute shader """ return resources.programs.load( ProgramDescription(compute_shader=path, defines=defines, **kwargs))
def load_shadertoy_program(source): if '\n' not in source: path = find_path(source) source = path.open().read() path = find_path('shaders/shadertoy-wrapper.glsl') single = path.open().read() single = re.sub(r'void mainImage.* {}', source, single) pd = ProgramDescription(path='shadertoy.glsl') sd = program.ProgramShaders.from_single(pd, single) pg = sd.create() return pg
def load_program( self, path=None, vertex_shader=None, geometry_shader=None, fragment_shader=None, tess_control_shader=None, tess_evaluation_shader=None, defines: dict = None, varyings: List[str] = None, ) -> moderngl.Program: """Loads a shader program. Note that `path` should only be used if all shaders are defined in the same glsl file separated by defines. If the path is relative the resource system is used expecting one or more resource directories to be registered first. Absolute paths will attempt to load the file directly. Keyword Args: path (str): Path to a single glsl file vertex_shader (str): Path to vertex shader geometry_shader (str): Path to geometry shader fragment_shader (str): Path to fragment shader tess_control_shader (str): Path to tessellation control shader tess_evaluation_shader (str): Path to tessellation eval shader defines (dict): ``#define`` values to replace in the shader source. Example: ``{'VALUE1': 10, 'VALUE2': '3.1415'}``. varyings (List[str]): Out attribute names for transform shaders Returns: moderngl.Program: The program instance """ return resources.programs.load( ProgramDescription( path=path, vertex_shader=vertex_shader, geometry_shader=geometry_shader, fragment_shader=fragment_shader, tess_control_shader=tess_control_shader, tess_evaluation_shader=tess_evaluation_shader, defines=defines, varyings=varyings, ))
def test_single_reloadable(self): """Load a single file glsl program as reloadable""" program = resources.programs.load( ProgramDescription(path='programs/white.glsl', reloadable=True)) self.assertIsInstance(program, ReloadableProgram) # Ensure attribute is present program['in_position'] self.assertIsInstance(program.extra.get('meta'), ProgramDescription) self.assertEqual(program.name, 'programs/white.glsl') self.assertIsInstance(program.ctx, moderngl.Context) self.assertIsNotNone(program.get('in_position', None)) self.assertIsNotNone(program.mglo) self.assertGreater(program.glo, 0) program.subroutines program.geometry_input program.geometry_output program.geometry_vertices program._members repr(program)
def initGL(self): self.vertexShaderFile = 'dbray/shaders/vertex.glsl' self.fragmentShaderFile = 'dbray/shaders/fragment.glsl' self.FSProgram = resources.programs.load( ProgramDescription( vertex_shader=self.vertexShaderFile, fragment_shader=self.fragmentShaderFile, )) self.cameraPositionUniform = self.FSProgram['cameraPosition'] self.cameraOrthoForwardUniform = self.FSProgram['cameraForward'] self.cameraOrthoRightUniform = self.FSProgram['cameraRight'] self.cameraOrthoUpUniform = self.FSProgram['cameraUp'] self.cameraPositionUniform.value = tuple(self.camera.location) self.cameraOrthoForwardUniform.value = tuple(self.camera.orthoForward) self.cameraOrthoRightUniform.value = tuple(self.camera.orthoRight) self.cameraOrthoUpUniform.value = tuple(self.camera.orthoUp) self.FSProgram['numObjects'] = self.scene.getNumObjects() self.FSProgram['lightPosition'].value = (0.0, 120.0, 200.0) self.FSProgram['projScale'].value = 1.5 self.FSProgram['aspectRatio'] = self.width / self.height ysampInc = 1.0 / self.height xsampInc = 1.0 / self.width samples = [] numSamples = 4 numSample1 = int(math.sqrt(numSamples) + 0.1) for x in range(numSample1): for y in range(numSample1): samples.append( ((x / numSample1) * xsampInc, (y / numSample1) * ysampInc)) self.FSProgram['samples'].value = samples self.texture = self.ctx.texture( [self.sceneArray.shape[1], self.sceneArray.shape[0]], 3, self.sceneArray.tobytes(), dtype='f4') self.texture.filter = (mgl.NEAREST, mgl.NEAREST) self.quad_fs = geometry.quad_fs()
def test_program(self): """Create ProgramDescription""" instance = ProgramDescription( path=self.path, kind=self.kind, label=self.label, vertex_shader='vertex_shader', geometry_shader='geometry_shader', fragment_shader='fragment_shader', tess_control_shader='tess_control_shader', tess_evaluation_shader='tess_evaluation_shader', ) self.inspect_base_properties(instance) self.assertEqual(instance.reloadable, False) self.assertEqual(instance.vertex_shader, 'vertex_shader') self.assertEqual(instance.geometry_shader, 'geometry_shader') self.assertEqual(instance.fragment_shader, 'fragment_shader') self.assertEqual(instance.tess_control_shader, 'tess_control_shader') self.assertEqual(instance.tess_evaluation_shader, 'tess_evaluation_shader')
def __init__(self, name, **kwargs): """Create a scene with a name. Args: name (str): Unique name or path for the scene """ self.name = name self.root_nodes = [] # References resources in the scene self.nodes = [] self.materials = [] self.meshes = [] self.cameras = [] self.bbox_min = None # Type: numpy.ndarray self.bbox_max = None # Type: numpy.ndarray self.diagonal_size = 1.0 self.bbox_vao = geometry.bbox() self.bbox_program = programs.load( ProgramDescription(path='scene_default/bbox.glsl'), ) self._model_matrix = matrix44.create_identity()
def __init__(self, lines=None, line_colors=None, lw=1, points=None, point_colors=None, point_r=1): self.point_r = point_r # Configure to use pyglet window window_str = 'moderngl_window.context.pyglet.Window' window_cls = moderngl_window.get_window_cls(window_str) window = window_cls( title="My Window", gl_version=(3, 3), # aspect_ratio=1.0, # resizable=False, # size=(1600, 800), ) self.wnd = window moderngl_window.activate_context(ctx=window.ctx) # self.wnd.gl_version = (3, 3) resources.register_dir(Path(__file__).parent.absolute()) self.ctx = self.wnd.ctx # register event methods self.wnd.resize_func = self.resize # self.wnd.iconify_func = self.iconify # self.wnd.key_event_func = self.key_event # self.wnd.mouse_position_event_func = self.mouse_position_event # self.wnd.mouse_drag_event_func = self.mouse_drag_event # self.wnd.mouse_scroll_event_func = self.mouse_scroll_event # self.wnd.mouse_press_event_func = self.mouse_press_event # self.wnd.mouse_release_event_func = self.mouse_release_event # self.wnd.unicode_char_entered_func = self.unicode_char_entered self.line_prog = programs.load( ProgramDescription(path="rich_lines.glsl")) self.point_prog = programs.load(ProgramDescription(path="points.glsl")) bbox = drawing_bbox(lines + points) bbox = drawing_bbox(lines + points, padding=0.05 * bbox[2]) self.bbox = bbox self.drawing_W = bbox[2] self.drawing_H = bbox[3] if len(lines) > 0: vertex, index, colors = build_buffers(lines, line_colors) vbo = self.ctx.buffer(vertex) ibo = self.ctx.buffer(index) cbo = self.ctx.buffer(colors) self.line_vao = self.ctx.vertex_array(self.line_prog, [ (vbo, "2f", "in_position"), (cbo, "4f", "in_color"), ], index_buffer=ibo) else: self.line_vao = None if len(points) > 0: point_vertex, point_color = build_point_buffers( points, point_colors) vbo = self.ctx.buffer(point_vertex) cbo = self.ctx.buffer(point_color) self.point_vao = self.ctx.vertex_array(self.point_prog, [ (vbo, "2f", "in_position"), (cbo, "4f", "in_color"), ]) else: self.point_vao = None # Set the desired properties for the lines. # Note: # - round cap/ends are used if miter_limit < 0 # - antialias value is in model space and should probably be scaled to be ~1.5px in # screen space self.line_prog["linewidth"].value = lw self.line_prog["antialias"].value = 1.5 self.line_prog["miter_limit"].value = -1 # self.line_prog["color"].value = 0, 0, 0, 1 self.update_projection()
def test_single_feedback(self): """Load transform feedback shader""" program = resources.programs.load( ProgramDescription(path='programs/feedback.glsl')) self.assertIsInstance(program, moderngl.Program)
def test_single_geometry(self): """Load single glsl file with gemotry shader""" program = resources.programs.load( ProgramDescription(path='programs/billboards/billboards.glsl')) self.assertIsInstance(program, moderngl.Program)
def __init__(self, program=None, **kwargs): super().__init__(program=None) self.program = programs.load( ProgramDescription(path="scene_default/color.glsl"))
def test_single_tesselation(self): """Load single glsl file with tessellation""" program = resources.programs.load( ProgramDescription(path='programs/terrain/terrain.glsl')) self.assertIsInstance(program, moderngl.Program)
def test_varyings_override(self): """Specify varyings during program creation""" path = 'programs/varyings.glsl' descr = ProgramDescription(vertex_shader=path, varyings=["value_1", "value_2"]) program = resources.programs.load(descr)
def __init__(self, scene, camera, track): self.scene = scene self.track = track self.camera = camera static_color = 0.01, 0.01, 0.01, 1.0 # light/laser shaders self.light_static_prog = resources.programs.load( ProgramDescription(path='programs/light_static.glsl')) self.laser_prog = resources.programs.load( ProgramDescription(path='programs/laser.glsl')) self.highway = self.scene.find_node('Highway') self.highway.mesh.material.color = static_color # Inner rings self.inner_ring_prog = resources.programs.load( ProgramDescription(path='programs/inner_rings.glsl')) self.inner_ring_prog['color'] = static_color self.inner_ring_prog['ring_spacing'] = -5.0 self.inner_ring_vao = self.scene.find_node('Ring.001').mesh.vao # Outer rings self.outer_ring_prog = resources.programs.load( ProgramDescription(path='programs/outer_rings.glsl')) self.outer_ring_prog['color'] = static_color self.outer_ring_vao = self.scene.find_node( 'Ring.021').children[1].mesh.vao # Ring neons self.ring_neon_prog = resources.programs.load( ProgramDescription(path='programs/outer_rings_neons.glsl')) self.ring_neon_1 = self.scene.find_node( 'Ring.021').children[0].mesh.vao self.ring_neon_2 = self.scene.find_node( 'Ring.021').children[2].mesh.vao self.ring_neon_3 = self.scene.find_node( 'Ring.021').children[3].mesh.vao self.ring_neon_4 = self.scene.find_node( 'Ring.021').children[4].mesh.vao # Lights self.light_left_static_vao = self.scene.find_node( 'Left Static').mesh.vao self.light_right_static_vao = self.scene.find_node( 'Right Static').mesh.vao self.light_center_static_vao = self.scene.find_node( 'Center Lights').mesh.vao self.light_back_static_vao = self.scene.find_node( 'Back Lights').mesh.vao # Lasers self.laser_left_1 = self.scene.find_node('Left 1').mesh.vao self.laser_right_1 = self.scene.find_node('Right 1').mesh.vao # Color variables for each light self.light_center_color = 0, 0, 0, 0 self.light_back_color = 0, 0, 0, 0 self.laser_left_color = 0, 0, 0, 0 self.laser_right_color = 0, 0, 0, 0 self.light_ring_color = 0, 0, 0, 0 # Ring values self.inner_rings_timestamp = 0 self.inner_rings_rotation = 0 self.inner_rings_velocity = 0 self.inner_ring_spacing = -5 # Moving lasers self.left_laser_rot = 0 self.right_laser_rot = 0 self.resize()
def test_include(self): program = resources.programs.load( ProgramDescription(path='programs/include_test.glsl')) self.assertIsInstance(program, moderngl.Program)
def test_single_not_found(self): """Ensure ImproperlyConfigured is raised when shaders are not found""" with self.assertRaises(ImproperlyConfigured): resources.programs.load( ProgramDescription(path='programs/nonexist.glsl'))