Mugichoko's blog

Mugichoko’s blog

しがない研究者のプログラミングを中心としたメモ書き.

ModernGL奮闘記 (5) - OrbitCamera -

マウスをグリグリするとカメラがある点を注視しながら移動するOrbitCameraを実装する.結論,ModernGLが用意しているクラスを使えばいいだけなので,とても簡単.

コード

ベースになっているコードは以下の回のもの.

mugichoko.hatenablog.com

今回はそこに,OrbitCameraとそれをマウス操作するためのコールバック関数を追加した.

尚,self.window.mouse_exclusivity = True(50行目)を指定しておくと,マウスポインタが見えなくなり,どこまでもスクロールし続けられるようになる.

# glfw_òrbitcamera.py
from pathlib import Path
import numpy as np
import moderngl as mgl
import moderngl_window as mglw
from moderngl_window.conf import settings
from moderngl_window import resources
from moderngl_window.resources import programs, scenes
from moderngl_window.meta import ProgramDescription, SceneDescription
from moderngl_window.scene.camera import OrbitCamera

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 = mglw.create_window_from_settings()
        self.window.print_context_info()

        # 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="test_vs.glsl", fragment_shader="test_fs.glsl",
            )
        )
        ## meshes
        resources.register_scene_dir((self.resource_dir / "models").resolve())
        self.scene = scenes.load(SceneDescription(path="bunny/bunny.obj"))
        for mesh in self.scene.meshes:
            print(">> mesh.attributes:", mesh.attributes)
        print(">> len(self.scene.meshes):", len(self.scene.meshes))
        
        # Camera
        self.camera = OrbitCamera(
            aspect_ratio=width / height,
            radius=0.5,
            near=0.01, far=100.0)
        self.camera.mouse_sensitivity = 0.75

        # Set key and mouse callback
        ## Ref: https://github.com/moderngl/moderngl-window/blob/master/examples/custom_config_class.py
        self.window.mouse_position_event_func = self.mouse_position_event
        self.window.mouse_scroll_event_func = self.mouse_scroll_event
        self.window.mouse_exclusivity = True

    def mouse_position_event(self, x, y, dx, dy) -> None:
        #print("Mouse position pos={} {} delta={} {}".format(x, y, dx, dy))
        self.camera.rot_state(dx, dy)

    def mouse_scroll_event(self, x_offset, y_offset) -> None:
        #print("mouse_scroll_event", x_offset, y_offset)
        self.camera.zoom_state(y_offset)

    def run(self) -> None:
        while not self.window.is_closing:
            self.window.ctx.enable_only(mgl.DEPTH_TEST | mgl.CULL_FACE)
            self.window.ctx.clear(1, 0, 0, 0)

            self.program["M"].write(np.identity(4, dtype="float32"))
            self.program["V"].write(self.camera.matrix)
            self.program["P"].write(self.camera.projection.matrix)
            self.scene.root_nodes[0].mesh.material.mat_texture.texture.use(0)
            self.scene.root_nodes[0].mesh.vao.render(self.program)

            self.window.swap_buffers()

if __name__ == "__main__":
    app = App()
    app.run()

結果

マウスをグリグリするとStanford Bunnyがグリグリ周る!