Source code for moderngl_window.scene.programs

from __future__ import annotations

import os
from typing import Any, Optional

import glm
import moderngl

import moderngl_window
from moderngl_window.conf import settings
from moderngl_window.meta import ProgramDescription
from moderngl_window.resources.programs import programs

from .mesh import Mesh

settings.PROGRAM_DIRS.append(os.path.join(os.path.dirname(__file__), "programs"))


[docs] class MeshProgram: """ Describes how a mesh is rendered using a specific shader program """ def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: """Initialize. Args: program: The moderngl program """ self.program = program @property def ctx(self) -> moderngl.Context: """moderngl.Context: The current context""" return moderngl_window.ctx()
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: """Draw code for the mesh Args: mesh (Mesh): The mesh to render Keyword Args: projection_matrix (numpy.ndarray): projection_matrix (bytes) model_matrix (numpy.ndarray): view_matrix (bytes) camera_matrix (numpy.ndarray): camera_matrix (bytes) time (float): The current time """ assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" self.program["m_proj"].write(projection_matrix) self.program["m_mv"].write(model_matrix) self.program["m_cam"].write(camera_matrix) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> MeshProgram | None: """ Determine if this ``MeshProgram`` should be applied to the mesh. Can return self or some ``MeshProgram`` instance to support dynamic ``MeshProgram`` creation Args: mesh: The mesh to inspect """ raise NotImplementedError( "apply is not implemented. Please override the MeshProgram method" )
[docs] class VertexColorProgram(MeshProgram): """Vertex color program""" def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: super().__init__(program=None) self.program = programs.load(ProgramDescription(path="scene_default/vertex_color.glsl"))
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" self.program["m_proj"].write(projection_matrix) self.program["m_model"].write(model_matrix) self.program["m_cam"].write(camera_matrix) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> Optional[MeshProgram]: if not mesh.material: return None if mesh.attributes.get("TEXCOORD_0"): return None if mesh.attributes.get("COLOR_0"): return self return None
[docs] class ColorLightProgram(MeshProgram): """Simple color program with light""" def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: super().__init__(program=None) self.program = programs.load(ProgramDescription(path="scene_default/color_light.glsl"))
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" if mesh.material is not None: # if mesh.material.double_sided: # self.ctx.disable(moderngl.CULL_FACE) # else: # self.ctx.enable(moderngl.CULL_FACE) if mesh.material.color: self.program["color"].value = tuple(mesh.material.color) else: self.program["color"].value = (1.0, 1.0, 1.0, 1.0) self.program["m_proj"].write(projection_matrix) self.program["m_model"].write(model_matrix) self.program["m_cam"].write(camera_matrix) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> MeshProgram | None: if not mesh.material: return None if not mesh.attributes.get("NORMAL"): return None return self
[docs] class TextureProgram(MeshProgram): """Plan textured""" def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: super().__init__(program=None) self.program = programs.load(ProgramDescription(path="scene_default/texture.glsl"))
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" assert mesh.material is not None, "There is no material to render" assert ( mesh.material.mat_texture is not None ), "The material does not have a texture to render" assert ( mesh.material.mat_texture.texture is not None ), "The material texture is not linked to a texture, so it can not be rendered" mesh.material.mat_texture.texture.use() self.program["m_proj"].write(projection_matrix) self.program["m_model"].write(model_matrix) self.program["m_cam"].write(camera_matrix) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> Optional[MeshProgram]: if not mesh.material: return None if mesh.attributes.get("NORMAL"): return None if not mesh.attributes.get("TEXCOORD_0"): return None if mesh.attributes.get("COLOR_0"): return None if mesh.material.mat_texture is not None: return self return None
[docs] class TextureVertexColorProgram(MeshProgram): """textured object with vertex color""" def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: super().__init__(program=None) self.program = programs.load( ProgramDescription(path="scene_default/vertex_color_texture.glsl") )
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" assert mesh.material is not None, "There is no material to render" assert ( mesh.material.mat_texture is not None ), "The material does not have a texture to render" assert ( mesh.material.mat_texture.texture is not None ), "The material texture is not linked to a texture, so it can not be rendered" mesh.material.mat_texture.texture.use() self.program["m_proj"].write(projection_matrix) self.program["m_model"].write(model_matrix) self.program["m_cam"].write(camera_matrix) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> MeshProgram | None: if not mesh.material: return None if mesh.attributes.get("NORMAL"): return None if not mesh.attributes.get("TEXCOORD_0"): return None if not mesh.attributes.get("COLOR_0"): return None if mesh.material.mat_texture is not None: return self return None
[docs] class TextureLightProgram(MeshProgram): """ Simple texture program """ def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: super().__init__(program=None) self.program = programs.load(ProgramDescription(path="scene_default/texture_light.glsl"))
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" assert mesh.material is not None, "There is no material to render" assert ( mesh.material.mat_texture is not None ), "The material does not have a texture to render" assert ( mesh.material.mat_texture.texture is not None ), "The material texture is not linked to a texture, so it can not be rendered" # if mesh.material.double_sided: # self.ctx.disable(moderngl.CULL_FACE) # else: # self.ctx.enable(moderngl.CULL_FACE) mesh.material.mat_texture.texture.use() self.program["texture0"].value = 0 self.program["m_proj"].write(projection_matrix) self.program["m_model"].write(model_matrix) self.program["m_cam"].write(camera_matrix) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> MeshProgram | None: if not mesh.material: return None if not mesh.attributes.get("NORMAL"): return None if not mesh.attributes.get("TEXCOORD_0"): return None if mesh.material.mat_texture is not None: return self return None
[docs] class TextureLightColorProgram: pass
[docs] class FallbackProgram(MeshProgram): """ Fallback program only rendering positions in white """ def __init__(self, program: Optional[moderngl.Program] = None, **kwargs: Any) -> None: super().__init__(program=None) self.program = programs.load(ProgramDescription(path="scene_default/fallback.glsl"))
[docs] def draw( self, mesh: Mesh, projection_matrix: glm.mat4, model_matrix: glm.mat4, camera_matrix: glm.mat4, time: float = 0.0, ) -> None: assert self.program is not None, "There is no program to draw" assert mesh.vao is not None, "There is no vao to render" self.program["m_proj"].write(projection_matrix) self.program["m_model"].write(model_matrix) self.program["m_cam"].write(camera_matrix) if mesh.material: self.program["color"].value = tuple(mesh.material.color[0:3]) else: self.program["color"].value = (1.0, 1.0, 1.0) mesh.vao.render(self.program)
[docs] def apply(self, mesh: Mesh) -> MeshProgram | None: return self