Skip to content

Instantly share code, notes, and snippets.

@nitori
Last active January 11, 2026 16:42
Show Gist options
  • Select an option

  • Save nitori/df2913ffc24e05b65b9004d441912085 to your computer and use it in GitHub Desktop.

Select an option

Save nitori/df2913ffc24e05b65b9004d441912085 to your computer and use it in GitHub Desktop.
simple pygame + moderngl example
import pygame
import moderngl
from pyglm import glm
import numpy as np
VERTEX_SHADER = """
#version 330
uniform mat4 mvp;
in vec3 in_pos;
out vec3 pos;
void main() {
gl_Position = mvp * vec4(in_pos, 1.0);
pos = in_pos;
}
"""
FRAGMENT_SHADER = """
#version 330
out vec4 fragColor;
in vec3 pos;
void main() {
// make color position dependent
vec3 col = (pos + 1.0) / 2.0;
fragColor = vec4(col, 1.0);
}
"""
# fmt: off
CUBE_VERTICES = np.array([
[1, 1, -1],
[1, -1, -1],
[1, 1, 1],
[1, -1, 1],
[-1, 1, -1],
[-1, -1, -1],
[-1, 1, 1],
[-1, -1, 1],
], dtype=np.float32)
CUBE_FACE_INDICES = np.array([
[4, 2, 0],
[2, 7, 3],
[6, 5, 7],
[1, 7, 5],
[0, 3, 1],
[4, 1, 5],
[4, 6, 2],
[2, 6, 7],
[6, 4, 5],
[1, 3, 7],
[0, 2, 3],
[4, 0, 1],
], dtype=np.uint8)
# fmt: on
def main():
screen = pygame.display.set_mode(
(800, 600), pygame.OPENGL | pygame.DOUBLEBUF | pygame.RESIZABLE
)
clock = pygame.Clock()
# no argument: discovers the context created by pygame.
ctx = moderngl.create_context()
ctx.enable(moderngl.CULL_FACE)
ctx.enable(moderngl.DEPTH_TEST)
prog = ctx.program(
vertex_shader=VERTEX_SHADER,
fragment_shader=FRAGMENT_SHADER,
)
vertex_buffer = ctx.buffer(CUBE_VERTICES.tobytes())
index_buffer = ctx.buffer(CUBE_FACE_INDICES.tobytes())
vao = ctx.vertex_array(
prog,
[(vertex_buffer, "3f", "in_pos")],
index_buffer=index_buffer,
index_element_size=1,
)
camera_pos = glm.vec3(0, 0, 5)
camera_target = glm.vec3(0, 0, 0)
camera_up = glm.vec3(0, 1, 0)
angle = 0.0
width, height = screen.size
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.WINDOWRESIZED:
width, height = event.x, event.y
delta = clock.tick(60) / 1000
angle += 50 * delta
ctx.clear(0, 0, 0)
proj = glm.perspective(glm.radians(60), width / height, 0.1, 1000.0)
view = glm.lookAt(camera_pos, camera_target, camera_up)
model = glm.rotate(glm.radians(angle), glm.vec3(1.5, 1, 0.5))
mvp = proj * view * model
prog["mvp"].write(mvp.to_bytes())
vao.render(mode=moderngl.TRIANGLES)
pygame.display.flip()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment