Texture Arrayを実装する.上下キーを押すことでTexture Array内の2つのテクスチャを切り替える.
コード
# glfw_quad_tex_arr.py from pathlib import Path import moderngl as mgl import moderngl_window from moderngl_window.conf import settings from moderngl_window import resources from moderngl_window.resources import programs from moderngl_window.meta import ProgramDescription from moderngl_window.scene.camera import Camera from PIL import Image import numpy as np class Quad: def __init__(self, ctx: mgl.Context, prog: mgl.Program) -> None: self.prog = prog # Quad vertices = np.array([ # x, y, u, v -0.5, -0.5, 0.0, 0.0, # 0: Bottom left +0.5, -0.5, 1.0, 0.0, # 1: Bottom right +0.5, +0.5, 1.0, 1.0, # 2: Top right -0.5, +0.5, 0.0, 1.0, # 3: Top left ], dtype="f4") indices = np.array([0, 1, 2, 3], dtype="i4") self.vbo = ctx.buffer(vertices) self.ibo = ctx.buffer(indices) vao_content = [(self.vbo, "2f 2f", "in_vert", "in_uv")] self.vao = ctx.vertex_array(self.prog, vao_content, self.ibo) def render( self, camera: Camera, tex_arr: mgl.texture_array, tex_arr_idx: int ) -> None: self.prog["M"].write(np.identity(4, dtype="f4")) self.prog["V"].write(camera.matrix) self.prog["P"].write(camera.projection.matrix) # https://moderngl.readthedocs.io/en/latest/reference/texture.html#moderngl.Texture.use tex_arr.use(location=0) self.prog["tex_arr_idx"].write(np.array([tex_arr_idx], dtype="i4")) self.vao.render(mgl.TRIANGLE_FAN) class App: def __init__(self, width=512, height=512) -> None: # Window # create a gl window: https://moderngl-window.readthedocs.io/en/latest/reference/settings.conf.settings.html#moderngl_window.conf.Settings.WINDOW settings.WINDOW["class"] = "moderngl_window.context.glfw.Window" settings.WINDOW["gl_version"] = (4, 1) settings.WINDOW["size"] = (width, height) settings.WINDOW["aspect_ratio"] = width / height self.window = moderngl_window.create_window_from_settings() # Resources self.resource_dir = Path(__file__).parent.resolve() / "resources" # Shaders resources.register_program_dir((self.resource_dir / "shaders").resolve()) self.program = programs.load( ProgramDescription( vertex_shader="tex_arr_vs.glsl", fragment_shader="tex_arr_fs.glsl" ) ) # Textures # Note: In case you have a single vertically stacked image, you can use TextureDescription to load it # Ref: https://moderngl-window.readthedocs.io/en/latest/reference/meta/texture.html image_names = self.resource_dir / "textures" image_names = list(image_names.glob("**/*.png")) self.tex_arr = self.create_tex_arr(image_names, 512, 512) self.tex_arr_idx = 0 # Camera self.camera = Camera(aspect_ratio=width / height, near=0.01, far=100.0) self.camera.set_position(0, 0.0, 1.5) self.camera.look_at(pos=(0, 0, 0)) # Set key allback ## Ref: https://github.com/moderngl/moderngl-window/blob/master/examples/custom_config_class.py self.window.key_event_func = self.key_event # Quad mesh with a 2D texture array self.quad = Quad(self.window.ctx, self.program) def key_event(self, key, action, modifiers): keys = self.window.keys # Key pressed if action == keys.ACTION_PRESS: if key == keys.UP: self.tex_arr_idx = min(self.tex_arr_idx + 1, self.tex_arr.size[2] - 1) print("UP: ", self.tex_arr_idx) if key == keys.DOWN: self.tex_arr_idx = max(self.tex_arr_idx - 1, 0) print("Down: ", self.tex_arr_idx) # Ref: https://stackoverflow.com/questions/63711867/using-a-texturearray-in-moderngl def create_tex_arr( self, image_names: list[str], width: int, height: int ) -> mgl.texture_array: depth = len(image_names) image_data = [] for filename in image_names: image = Image.open(filename) if width != image.size[0] or height != image.size[1]: raise ValueError( f"Image size mismatch: {image.size[0]}x{image.size[1]}" ) image = image.transpose(method=Image.FLIP_TOP_BOTTOM) image_data.append(image.getdata()) image_data = np.array(image_data, np.uint8) tex_arr = self.window.ctx.texture_array( (width, height, depth), components=3, data=image_data ) return tex_arr def run(self) -> None: while not self.window.is_closing: self.window.clear(0.5, 1.0, 0.25, 0.0) self.window.ctx.enable(mgl.DEPTH_TEST | mgl.CULL_FACE) self.quad.render(self.camera, self.tex_arr, self.tex_arr_idx) self.window.swap_buffers() if __name__ == "__main__": app = App() app.run()
以下,シェーダ.
#version 330 uniform mat4 M; // model matrix uniform mat4 V; // view matrix uniform mat4 P; // projection matrix in vec2 in_vert; in vec2 in_uv; out vec2 vs_uv; void main() { vs_uv = in_uv; gl_Position = P * V * M * vec4(in_vert, 0.0, 1.0); }
#version 420 layout (binding = 0) uniform sampler2DArray tex_arr; uniform int tex_arr_idx; // set by a key binding (up / down) in vec2 vs_uv; out vec4 fs_color; void main() { vec4 color = texture(tex_arr, vec3(vs_uv, tex_arr_idx)); fs_color = color; }