One familiar triangle#
As with any graphics library guide, we also have a guide on how to draw a triangle. Below is a slightly modified line drawing code from the previous tutorial. The following code draws one triangle:
Entire source
1import moderngl
2import numpy as np
3
4from PIL import Image
5
6ctx = moderngl.create_context(standalone=True)
7
8prog = ctx.program(
9 vertex_shader="""
10 #version 330
11
12 in vec2 in_vert;
13 in vec3 in_color;
14
15 out vec3 v_color;
16
17 void main() {
18 v_color = in_color;
19 gl_Position = vec4(in_vert, 0.0, 1.0);
20 }
21 """,
22 fragment_shader="""
23 #version 330
24
25 in vec3 v_color;
26
27 out vec3 f_color;
28
29 void main() {
30 f_color = v_color;
31 }
32 """,
33)
34
35vertices = np.asarray([
36
37 -0.75, -0.75, 1, 0, 0,
38 0.75, -0.75, 0, 1, 0,
39 0.0, 0.649, 0, 0, 1
40
41], dtype='f4')
42
43vbo = ctx.buffer(vertices.tobytes())
44vao = ctx.vertex_array(prog, vbo, "in_vert", "in_color")
45
46fbo = ctx.framebuffer(
47 color_attachments=[ctx.texture((512, 512), 3)]
48)
49fbo.use()
50fbo.clear(0.0, 0.0, 0.0, 1.0)
51vao.render() # "mode" is moderngl.TRIANGLES by default
52
53Image.frombytes(
54 "RGB", fbo.size, fbo.color_attachments[0].read(),
55 "raw", "RGB", 0, -1
56).show()
When you run the code you will see this:

Triangle#
As you may have noticed, we only specified three colors for each vertex, but OpenGL interpolates our triangle and we see a soft transition of colors.
At this point you can try out the fragment shader, for example, let’s draw a lighting effect:
Fragment shader
#version 330
in vec3 v_color;
out vec3 f_color;
void main() {
vec2 pixel_coord = (gl_FragCoord.xy-256.0)/256.0;
f_color = v_color*(1.0-length(pixel_coord));
}

Lighted triangle#
Shaders are not very fond of branching algorithms and operations such as if (condition) {action} else {action}
. It is recommended to use formulas more often.