Welcome to ModernGL’s documentation!¶
Start here.
ModernGL¶
ModernGL on Github
If you have less time to read docs go to the TL;DR section.
ModernGL and OpenGL
OpenGL is a great environment for developing portable, platform independent, interactive 2D and 3D graphics applications. The API implementation in Python is cumbersome, resulting in applications with high latency. To solve this problem we have developed ModernGL, a wrapper over OpenGL that simplifies the creation of simple graphics applications like scientific simulations, small games or user interfaces. Usually, acquiring in-depth knowledge of OpenGL requires a steep learning curve. In contrast, ModernGL is easy to learn and use, moreover it is capable of rendering with the same performance and quality, with less code written.
How to install?
pip install ModernGL
How to create a window?
ModernGL encapsulates the use of the OpenGL API, a separate module must be used for creating a window. ModernGL can be integrated easily in GLWindow, PyQt5, pyglet, pygame, GLUT and many more.
How to create a context?
- Create a window
- Call
ModernGL.create_context()
ModernGL: PyOpenGL alternative
Context¶
-
create_context
(require=None) → Context¶ Create a ModernGL context by loading OpenGL functions from an existing OpenGL context. An OpenGL context must exists. If rendering is done without a window please use the
create_standalone_context()
instead.Keyword Arguments: require (Version) – OpenGL version. Returns: context Return type: Context
-
create_standalone_context
(size=(256, 256), require=None) → Context¶ Create a standalone ModernGL context. This method will create a hidden window with the initial size given in the parameters. This will set the initial viewport as well.
It is reccommanded to use a separate framebuffer when rendering.
The size is not really important for the default framebuffer. It is only useful to get a viewport with a visible size. Size
(1, 1)
is great to save memory, however makes harder to detect when the viewport was forgotten to set.Keyword Arguments: - size (tuple) – Initial framebuffer size.
- require (Version) – OpenGL version.
Returns: context
Return type:
-
class
Context
¶ Create a
Context
using:The
create_context()
must be used when rendering in a window. Thecreate_standalone_context()
must be used when rendering without a window.Members:
Context.program()
Context.vertex_shader()
Context.fragment_shader()
Context.geometry_shader()
Context.tess_evaluation_shader()
Context.tess_control_shader()
Context.buffer()
Context.simple_vertex_array()
Context.vertex_array()
Context.texture()
Context.depth_texture()
Context.renderbuffer()
Context.depth_renderbuffer()
Context.framebuffer()
-
clear
(red=0.0, green=0.0, blue=0.0, alpha=0.0, viewport=None)¶ Clear the framebuffer.
Values must be in
(0, 255)
range. If the viewport is notNone
then scrissor test will be used to clear the given viewport.If the viewport is a 2-tuple it will clear the
(0, 0, width, height)
where(width, height)
is the 2-tuple.If the viewport is a 4-tuple it will clear the given viewport.
Parameters: - red (float) – color component.
- green (float) – color component.
- blue (float) – color component.
- alpha (float) – alpha component.
Keyword Arguments: viewport (tuple) – The viewport.
-
enable
(flag)¶ Enable flags.
Valid flags are:
Parameters: flag (EnableFlag) – The flag to enable.
-
disable
(flag)¶ Disable flags.
Valid flags are:
Parameters: flag (EnableFlag) – The flag to disable.
-
finish
()¶ Wait for all drawing commands to finish.
-
copy_buffer
(dst, src, size=-1, read_offset=0, write_offset=0)¶ Copy buffer content.
Parameters: Keyword Arguments: - read_offset (int) – Read offset.
- write_offset (int) – Write offset.
-
copy_framebuffer
(dst, src)¶ Copy framebuffer content.
Use this method to:
- blit framebuffers.
- copy framebuffer content into a texture.
- downsample framebuffers. (it will allow to read the framebuffer’s content)
- downsample a framebuffer directly to a texture.
Parameters: - dst (Framebuffer or Texture) – Destination framebuffer or texture.
- src (Framebuffer) – Source framebuffer.
-
buffer
(data=None, reserve=0, dynamic=False) → Buffer¶ Create a
Buffer
.Parameters: data (bytes) – Content of the new buffer.
Keyword Arguments: - reserve (int) – The number of bytes to reserve.
- dynamic (bool) – Treat buffer as dynamic.
Returns: buffer
Return type:
-
texture
(size, components, data=None, samples=0, floats=False) → Texture¶ Create a
Texture
.Parameters: - size (tuple) – The width and height of the texture.
- components (int) – The number of components 1, 2, 3 or 4.
- data (bytes) – Content of the texture.
Keyword Arguments: - samples (int) – The number of samples. Value 0 means no multisample format.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
- floats (bool) – Use floating point precision.
Returns: texture
Return type:
-
texture3d
(size, components, data=None, floats=False) → Texture3D¶ Create a
Texture3D
.Parameters: - size (tuple) – The width, height and depth of the texture.
- components (int) – The number of components 1, 2, 3 or 4.
- data (bytes) – Content of the texture.
Keyword Arguments: - alignment (int) – The byte alignment 1, 2, 4 or 8.
- floats (bool) – Use floating point precision.
Returns: texture
Return type:
-
depth_texture
(size, data=None, samples=0) → Texture¶ Create a
Texture
.Parameters: - size (tuple) – The width and height of the texture.
- data (bytes) – Content of the texture.
Keyword Arguments: - samples (int) – The number of samples. Value 0 means no multisample format.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
Returns: depth texture
Return type:
-
vertex_array
(program, content, index_buffer=None) → VertexArray¶ Create a
VertexArray
.Parameters: - program (Program) – The program used by
render()
andtransform()
. - content (list) – A list of (buffer, format, attributes).
- index_buffer (Buffer) – An index buffer.
Returns: vertex array
Return type: - program (Program) – The program used by
-
simple_vertex_array
(program, buffer, attributes) → VertexArray¶ Create a
VertexArray
.This is an alias for:
format = detect_format(program, attributes) vertex_array(program, [(buffer, format, attributes)])
Parameters: - program (Program) – The program used by
render()
andtransform()
. - buffer (Buffer) – The buffer.
- attributes (list) – A list of attribute names.
Returns: vertex array
Return type: - program (Program) – The program used by
-
program
(shaders, varyings=()) → Program¶ Create a
Program
object.Only linked programs will be returned.
For more information please see:
Program
andShader
A single shader in the shaders parameter is also accepted. The varyings are only used when a transform program is created.
Parameters: - shaders (list) – A list of
Shader
objects. - varyings (list) – A list of varying names.
Returns: program
Return type: Examples
A simple program designed for rendering:
>>> my_render_program = ctx.program([ ... ctx.vertex_shader(''' ... #version 330 ... ... in vec2 vert; ... ... void main() { ... gl_Position = vec4(vert, 0.0, 1.0); ... } ... '''), ... ctx.fragment_shader(''' ... #version 330 ... ... out vec4 color; ... ... void main() { ... color = vec4(0.3, 0.5, 1.0, 1.0); ... } ... '''), ... ])
A simple program designed for transforming:
>>> my_vertex_shader = ctx.vertex_shader(''' ... #version 330 ... ... in vec4 vert; ... out float vert_length; ... ... void main() { ... vert_length = length(vert); ... } ... ''') >>> my_transform_program = ctx.program(my_vertex_shader, ['vert_length'])
- shaders (list) – A list of
-
vertex_shader
(source) → Shader¶ The Vertex Shader is a programmable Shader stage in the rendering pipeline that handles the processing of individual vertices.
Vertex shaders are fed Vertex Attribute data, as specified from a vertex array object by a drawing command. A vertex shader receives a single vertex from the vertex stream and generates a single vertex to the output vertex stream.
Parameters: source (str) – The source code in GLSL. Returns: vertex shader Return type: Shader Examples
Create a simple vertex shader:
>>> my_vertex_shader = ctx.vertex_shader(''' ... #version 330 ... ... in vec2 vert; ... ... void main() { ... gl_Position = vec4(vert, 0.0, 1.0); ... } ... ''')
-
fragment_shader
(source) → Shader¶ A Fragment Shader is the Shader stage that will process a Fragment generated by the Rasterization into a set of colors and a single depth value.
Parameters: source (str) – The source code in GLSL. Returns: fragment shader Return type: Shader Examples
Create a simple fragment shader:
>>> my_fragment_shader = ctx.fragment_shader(''' ... #version 330 ... ... out vec4 color; ... ... void main() { ... color = vec4(0.3, 0.5, 1.0, 1.0); ... } ... ''')
-
geometry_shader
(source) → Shader¶ A Geometry Shader is a Shader program written in GLSL that governs the processing of Primitives. Geometry shaders reside between the Vertex Shaders (or the optional Tessellation stage) and the fixed-function Vertex Post-Processing stage.
A geometry shader is optional and does not have to be used.
Parameters: source (str) – The source code in GLSL. Returns: geometry shader Return type: Shader
-
tess_evaluation_shader
(source) → Shader¶ Tessellation is the Vertex Processing stage in the OpenGL rendering pipeline where patches of vertex data are subdivided into smaller Primitives.
The Tessellation Evaluation Shader takes the tessellated patch and computes the vertex values for each generated vertex.
Parameters: source (str) – The source code in GLSL. Returns: tesselation evaluation shader Return type: Shader
-
tess_control_shader
(source) → Shader¶ The Tessellation Control Shader (TCS) determines how much tessellation to do. It can also adjust the actual patch data, as well as feed additional patch data to later stages. The Tessellation Control Shader is optional.
Parameters: source (str) – The source code in GLSL. Returns: tesselation control shader Return type: Shader
-
framebuffer
(color_attachments, depth_attachment=None) → Framebuffer¶ A
Framebuffer
is a collection of buffers that can be used as the destination for rendering. The buffers for Framebuffer objects reference images from either Textures or Renderbuffers.Parameters: - color_attachments (list) – A list of Texture or Renderbuffer objects.
- depth_attachment (Renderbuffer or Texture) – A Texture or Renderbuffer object.
Returns: framebuffer
Return type:
-
renderbuffer
(size, components=4, samples=0, floats=False) → Renderbuffer¶ Renderbuffer
objects are OpenGL objects that contain images. They are created and used specifically withFramebuffer
objects.Parameters: - size (tuple) – The width and height of the renderbuffer.
- components (int) – The number of components 1, 2, 3 or 4.
Keyword Arguments: - samples (int) – The number of samples. Value 0 means no multisample format.
- floats (bool) – Use floating point precision.
Returns: renderbuffer
Return type:
-
depth_renderbuffer
(size, samples=0) → Renderbuffer¶ Renderbuffer
objects are OpenGL objects that contain images. They are created and used specifically withFramebuffer
objects.Parameters: size (tuple) – The width and height of the renderbuffer. Keyword Arguments: samples (int) – The number of samples. Value 0 means no multisample format. Returns: depth renderbuffer Return type: Renderbuffer
-
compute_shader
(source) → ComputeShader¶ A
ComputeShader
is a Shader Stage that is used entirely for computing arbitrary information. While it can do rendering, it is generally used for tasks not directly related to drawing.Parameters: source (str) – The source of the compute shader. Returns: compute shader program Return type: ComputeShader
-
line_width
¶ float – Set the default line width.
-
point_size
¶ float – Set the default point size.
-
viewport
¶ tuple – The viewport.
Reading this property may force the GPU to sync. Use this property to set the viewport only.
-
max_samples
¶ int – The max samples.
-
max_integer_samples
¶ int – The max integer samples.
-
max_texture_units
¶ int – The max texture units.
-
default_texture_unit
¶ int – The default texture unit.
-
default_framebuffer
¶ Framebuffer – The default framebuffer.
-
wireframe
¶ bool – Wireframe settings for debugging.
-
error
¶ str – The result of glGetError() but human readable. This values is provided for debug purposes only.
-
vendor
¶ str – The vendor.
-
renderer
¶ str – The renderer.
-
version
¶ str – The OpenGL version.
-
version_code
¶ int – The OpenGL version.
-
info
¶ dict – The result of multiple glGet.
Shaders and Programs¶
-
Context.
vertex_shader
(source) → Shader The Vertex Shader is a programmable Shader stage in the rendering pipeline that handles the processing of individual vertices.
Vertex shaders are fed Vertex Attribute data, as specified from a vertex array object by a drawing command. A vertex shader receives a single vertex from the vertex stream and generates a single vertex to the output vertex stream.
Parameters: source (str) – The source code in GLSL. Returns: vertex shader Return type: Shader Examples
Create a simple vertex shader:
>>> my_vertex_shader = ctx.vertex_shader(''' ... #version 330 ... ... in vec2 vert; ... ... void main() { ... gl_Position = vec4(vert, 0.0, 1.0); ... } ... ''')
-
Context.
fragment_shader
(source) → Shader A Fragment Shader is the Shader stage that will process a Fragment generated by the Rasterization into a set of colors and a single depth value.
Parameters: source (str) – The source code in GLSL. Returns: fragment shader Return type: Shader Examples
Create a simple fragment shader:
>>> my_fragment_shader = ctx.fragment_shader(''' ... #version 330 ... ... out vec4 color; ... ... void main() { ... color = vec4(0.3, 0.5, 1.0, 1.0); ... } ... ''')
-
Context.
geometry_shader
(source) → Shader A Geometry Shader is a Shader program written in GLSL that governs the processing of Primitives. Geometry shaders reside between the Vertex Shaders (or the optional Tessellation stage) and the fixed-function Vertex Post-Processing stage.
A geometry shader is optional and does not have to be used.
Parameters: source (str) – The source code in GLSL. Returns: geometry shader Return type: Shader
-
Context.
tess_evaluation_shader
(source) → Shader Tessellation is the Vertex Processing stage in the OpenGL rendering pipeline where patches of vertex data are subdivided into smaller Primitives.
The Tessellation Evaluation Shader takes the tessellated patch and computes the vertex values for each generated vertex.
Parameters: source (str) – The source code in GLSL. Returns: tesselation evaluation shader Return type: Shader
-
Context.
tess_control_shader
(source) → Shader The Tessellation Control Shader (TCS) determines how much tessellation to do. It can also adjust the actual patch data, as well as feed additional patch data to later stages. The Tessellation Control Shader is optional.
Parameters: source (str) – The source code in GLSL. Returns: tesselation control shader Return type: Shader
-
Context.
program
(shaders, varyings=()) → Program Create a
Program
object.Only linked programs will be returned.
For more information please see:
Program
andShader
A single shader in the shaders parameter is also accepted. The varyings are only used when a transform program is created.
Parameters: - shaders (list) – A list of
Shader
objects. - varyings (list) – A list of varying names.
Returns: program
Return type: Examples
A simple program designed for rendering:
>>> my_render_program = ctx.program([ ... ctx.vertex_shader(''' ... #version 330 ... ... in vec2 vert; ... ... void main() { ... gl_Position = vec4(vert, 0.0, 1.0); ... } ... '''), ... ctx.fragment_shader(''' ... #version 330 ... ... out vec4 color; ... ... void main() { ... color = vec4(0.3, 0.5, 1.0, 1.0); ... } ... '''), ... ])
A simple program designed for transforming:
>>> my_vertex_shader = ctx.vertex_shader(''' ... #version 330 ... ... in vec4 vert; ... out float vert_length; ... ... void main() { ... vert_length = length(vert); ... } ... ''') >>> my_transform_program = ctx.program(my_vertex_shader, ['vert_length'])
- shaders (list) – A list of
-
class
Shader
¶ Shader objects represent compiled GLSL code for a single shader stage.
A Shader object cannot be instantiated directly, it requires a context. Use the following methods to create one:
-
source
¶ str – The source code of the shader.
-
-
class
Program
¶ A Program object represents fully processed executable code in the OpenGL Shading Language, for one or more Shader stages.
In ModernGL, a Program object can be assigned to
VertexArray
objects. The VertexArray object is capable of binding the Program object once theVertexArray.render()
orVertexArray.transform()
is called.Program objects has no method called
use()
, VertexArrays encapsulate this mechanism.A Program object cannot be instantiated directly, it requires a context. Use
Context.program()
to create one.-
uniforms
¶ UniformMap
– The uniforms of the program. The return value is a dictinary like object. It can be used to accessUniform
objects by name.Examples
Set the value of the uniforms:
# uniform vec3 eye_pos; >>> program.uniforms['eye_pos'].value = (10.0, 20.0, 0.0) # uniform sampler2D my_textures[3]; >>> program.uniforms['my_texture'].value = [0, 3, 2] # The values of `my_textures` will be: my_textures[0] = GL_TEXTURE0 # GL_TEXTURE0 my_textures[1] = GL_TEXTURE0 + 3 # GL_TEXTURE3 my_textures[2] = GL_TEXTURE0 + 2 # GL_TEXTURE2
Get information about the uniforms:
>>> program.uniforms['eye_pos'].location 0 >>> program.uniforms['eye_pos'].dimension 3 >>> program.uniforms['eye_pos'].value (10.0, 20.0, 0.0) >>> program.uniforms['my_textures'].dimension 1 >>> program.uniforms['my_textures'].array_length 3
-
uniform_blocks
¶ UniformBlockMap
– The uniform blocks of the program. The return value is a dictinary like object. It can be used to accessUniformBlock
objects by name.Examples
Get the location of the uniform block:
# uniform custom_material { # ... # }; >>> program.uniform_blocks['custom_material'].location 16
-
attributes
¶ AttributeMap
– The attributes of the program. The return value is a dictinary like object. It can be used to accessAttribute
objects by name.Examples
Set the default value for the attributes:
# in vec3 normal; >>> program.attributes['normal'].default = (0.0, 0.0, 1.0) # in vec2 texture_coordinates[3]; >>> program.attributes['texture_coordinates'].default = [ ... (0.0, 0.0), ... (0.0, 0.0), ... (0.0, 0.0), ... ]
Get information about the attributes:
>>> program.attributes['normal'].default (0.0, 0.0, 1.0) >>> program.attributes['normal'].dimension 3 >>> program.attributes['texture_coordinates'].default [(0.0, 0.0), (0.0, 0.0), (0.0, 0.0)] >>> program.attributes['texture_coordinates'].array_length 3 >>> program.attributes['texture_coordinates'].dimension 2
-
varyings
¶ VaryingMap
– The varyings of the program. The return value is a dictinary like object. It can be used to accessVarying
objects by name.The only reason varyings were added to allow verifying varyings programatically, they do not hold any other information.
Examples
Check varyings:
>>> 'vertex_out' in program.varyings True
-
geometry_input
¶ Primitive
– The geometry input primitive. The GeometryShader’s input primitive if the GeometryShader exists. The geometry input primitive will be used for validation.
-
geometry_output
¶ Primitive
– The geometry output primitive. The GeometryShader’s output primitive if the GeometryShader exists.
-
geometry_vertices
¶ int
– The maximum number of vertices that the geometry shader will output.
-
vertex_shader
¶ ProgramStage
– The vertex shader program stage.The return value is NOT a Shader.
-
fragment_shader
¶ ProgramStage
– The fragment shader program stage.The return value is NOT a Shader.
-
geometry_shader
¶ ProgramStage
– The geometry shader program stage.The return value is NOT a Shader.
-
tess_evaluation_shader
¶ ProgramStage
– The tesselation evaluation shader program stage.The return value is NOT a Shader.
-
tess_control_shader
¶ ProgramStage
– The tesselation control shader program stage.The return value is NOT a Shader.
-
Uniform¶
-
class
Uniform
¶ A uniform is a global GLSL variable declared with the “uniform” storage qualifier. These act as parameters that the user of a shader program can pass to that program.
In ModernGL, Uniforms can be accessed using
Program.uniforms
-
read
() → bytes¶ Read the value of the uniform.
-
write
(value)¶ Write the value of the uniform.
-
name
¶ str – The name of the uniform. The name does not contain leading [0]. The name may contain [ ] when the uniform is part of a struct.
-
location
¶ int – The location of the uniform. The location holds the value returned by the glGetUniformLocation. To set the value of the uniform use the
value
instead.
-
dimension
¶ int – The dimension of the uniform.
GLSL type dimension sampler2D 1 sampler2DCube 1 sampler2DShadow 1 bool 1 bvec2 2 bvec3 3 bvec4 4 int 1 ivec2 2 ivec3 3 ivec4 4 uint 1 uvec2 2 uvec3 3 uvec4 4 float 1 vec2 2 vec3 3 vec4 4 double 1 dvec2 2 dvec3 3 dvec4 4 mat2 4 mat2x3 6 mat2x4 8 mat3x2 6 mat3 9 mat3x4 12 mat4x2 8 mat4x3 12 mat4 16 dmat2 4 dmat2x3 6 dmat2x4 8 dmat3x2 6 dmat3 9 dmat3x4 12 dmat4x2 8 dmat4x3 12 dmat4 16
-
array_length
¶ int – The length of the array of the uniform. The array_length is 1 for non array uniforms.
-
value
¶ The value of the uniform. Reading the value of the uniform may force the GPU to sync.
The value must be a tuple for non array uniforms. The value must be a list of tuples for array uniforms.
-
Uniform Blocks¶
-
class
UniformBlock
¶ -
name
¶ str – name
-
index
¶ int – The index of the uniform block.
-
size
¶ int – The size of the uniform block.
-
binding
¶ int – The binding of the uniform block.
-
-
class
UniformBlockMap
¶ UniformBlockMap is a dictionary like object.
-
__getitem__
(key) → UniformBlock¶
-
Attributes¶
-
class
Attribute
¶ -
name
¶ str – The attribute name. The name will be filtered to have no array syntax on it’s end. Attribute name without
'[0]'
ending if any.
-
location
¶ int – The location of the attribute. The result of the glGetAttribLocation.
-
array_length
¶ int – If the attribute is an array the array_length is the length of the array otherwise 1.
-
dimension
¶ int – The attribute dimension.
GLSL type dimension int 1 ivec2 2 ivec3 3 ivec4 4 uint 1 uvec2 2 uvec3 3 uvec4 4 float 1 vec2 2 vec3 3 vec4 4 double 1 dvec2 2 dvec3 3 dvec4 4 mat2 4 mat2x3 6 mat2x4 8 mat3x2 6 mat3 9 mat3x4 12 mat4x2 8 mat4x3 12 mat4 16 dmat2 4 dmat2x3 6 dmat2x4 8 dmat3x2 6 dmat3 9 dmat3x4 12 dmat4x2 8 dmat4x3 12 dmat4 16
-
Varyings¶
Buffers¶
-
Context.
buffer
(data=None, reserve=0, dynamic=False) → Buffer Create a
Buffer
.Parameters: data (bytes) – Content of the new buffer.
Keyword Arguments: - reserve (int) – The number of bytes to reserve.
- dynamic (bool) – Treat buffer as dynamic.
Returns: buffer
Return type:
-
class
Buffer
¶ Buffer objects are OpenGL objects that store an array of unformatted memory allocated by the OpenGL context, (data allocated on the GPU). These can be used to store vertex data, pixel data retrieved from images or the framebuffer, and a variety of other things.
A Buffer object cannot be instantiated directly, it requires a context. Use
Context.buffer()
to create one.Copy buffer content using
Context.copy_buffer()
.-
access
(size=-1, offset=0, readonly=False) → BufferAccess¶ Create a
BufferAccess
object.Keyword Arguments: - size (int) – The size. Value -1 means all.
- offset (int) – The offset.
- readonly (bool) – The readonly.
Examples
Simple
with
statement:# The buffer will be mapped once and accessed multiple times. >>> with buffer.access() as access: ... access.read(...) ... access.write(...)
-
read
(size=-1, offset=0) → bytes¶ Read the content.
Parameters: size (int) – The size. Value -1
means all.Keyword Arguments: offset (int) – The offset. Returns: The content of the buffer. Return type: bytes
-
read_into
(buffer, size=-1, offset=0, write_offset=0)¶ Read the content into a buffer.
Parameters: - buffer (bytarray) – The buffer that will receive the content.
- size (int) – The size. Value
-1
means all.
Keyword Arguments: - offset (int) – The read offset.
- write_offset (int) – The write offset.
Returns: The content of the buffer.
Return type: bytes
-
write
(data, offset=0)¶ Write the content.
Parameters: data (bytes) – The data. Keyword Arguments: offset (int) – The offset.
-
orphan
()¶ Orphan the buffer.
It is also called buffer re-specification.
Reallocate the buffer object before you start modifying it.
Since allocating storage is likely faster than the implicit synchronization, you gain significant performance advantages over synchronization.
The old storage will still be used by the OpenGL commands that have been sent previously. It is likely that the GL driver will not be doing any allocation at all, but will just be pulling an old free block off the unused buffer queue and use it, so it is likely to be very efficient.
Examples
Simple orphaning example:
# For simplicity the VertexArray creation is omitted >>> vbo = ctx.buffer(reserve=1024) # Fill the buffer >>> vbo.write(some_temorary_data) # Issue a render call that uses the vbo >>> vao.render(...) # Orphan the buffer >>> vbo.orphan() # Issue another render call without waiting for the previous one >>> vbo.write(some_temorary_data) >>> vao.render(...)
-
bind_to_uniform_block
(binding=0)¶ Bind the buffer to a uniform block.
Parameters: binding (int) – The uniform block binding.
-
bind_to_storage_buffer
(binding=0)¶ Bind the buffer to a shader storage buffer.
Parameters: binding (int) – The shader storage binding.
-
-
class
BufferAccess
¶ BufferAccess objects are designed to access a
Buffer
object’s content inside awith
statement. The buffer is mapped and unmapped only once.Use
Buffer.access()
to get a BufferAccess object.-
open
()¶ Map the buffer. This method is called by
__enter__
.
-
close
()¶ Unmap the buffer. This method is called by
__exit__
.
-
read
(size=-1, offset=0) → bytes¶ Read the content.
Parameters: size (int) – The size. Value -1 means all. Keyword Arguments: offset (int) – The offset. Returns: binary data Return type: bytes
-
read_into
(buffer, size=-1, offset=0, write_offset=0)¶ Read the content.
Parameters: - buffer (bytarray) – The buffer that will receive the content.
- size (int) – The size. Value -1 means all.
Keyword Arguments: - offset (int) – The read offset.
- write_offset (int) – The write offset.
Returns: binary data
Return type: bytes
-
write
(data, offset=0)¶ Write the content.
Parameters: size (int) – The data. Keyword Arguments: offset (int) – The offset.
-
VertexArray¶
-
Context.
simple_vertex_array
(program, buffer, attributes) → VertexArray Create a
VertexArray
.This is an alias for:
format = detect_format(program, attributes) vertex_array(program, [(buffer, format, attributes)])
Parameters: - program (Program) – The program used by
render()
andtransform()
. - buffer (Buffer) – The buffer.
- attributes (list) – A list of attribute names.
Returns: vertex array
Return type: - program (Program) – The program used by
-
Context.
vertex_array
(program, content, index_buffer=None) → VertexArray Create a
VertexArray
.Parameters: - program (Program) – The program used by
render()
andtransform()
. - content (list) – A list of (buffer, format, attributes).
- index_buffer (Buffer) – An index buffer.
Returns: vertex array
Return type: - program (Program) – The program used by
-
class
VertexArray
¶ A VertexArray object is an OpenGL object that stores all of the state needed to supply vertex data. It stores the format of the vertex data as well as the Buffer objects providing the vertex data arrays.
In ModernGL, the VertexArray object also stores a reference for a
Program
object, and some Subroutine information.A VertexArray object cannot be instantiated directly, it requires a context. Use
Context.vertex_array()
orContext.simple_vertex_array()
to create one.-
render
(mode=TRIANGLES, vertices=-1, first=0, instances=1)¶ The render primitive (mode) must be the same as the input primitive of the GeometryShader.
Parameters: - mode (Primitive) – By default TRIANGLES will be used.
- vertices (int) – The number of vertices to transform.
Keyword Arguments: - first (int) – The index of the first vertex to start with.
- instances (int) – The number of instances.
-
transform
(buf, mode=POINTS, vertices=-1, *, first=0, instances=1)¶ Transform vertices. Stores the output in a single buffer. The transform primitive (mode) must be the same as the input primitive of the GeometryShader.
Parameters: Keyword Arguments: - first (int) – The index of the first vertex to start with.
- instances (int) – The number of instances.
-
program
¶ Program – The program assinged to the VertexArray. The program used when rendering or transforming primitives.
-
attributes
¶ VertexArrayAttributeMap – Individual vertex attributes. Use the
VertexArrayAttribute.bind()
method to assign vertex attributes to buffers.
-
index_buffer
¶ Buffer – The index buffer if the index_buffer is set, otherwise
None
.
-
vertices
¶ int – The number of vertices detected. This is the minimum of the number of vertices possible per Buffer. The size of the index_buffer determines the number of vertices. Per instance vertex attributes does not affect this number.
-
subroutines
¶ tuple – The subroutines assinged to the VertexArray. The subroutines used when rendering or transforming primitives.
-
Textures¶
-
Context.
texture
(size, components, data=None, samples=0, floats=False) → Texture Create a
Texture
.Parameters: - size (tuple) – The width and height of the texture.
- components (int) – The number of components 1, 2, 3 or 4.
- data (bytes) – Content of the texture.
Keyword Arguments: - samples (int) – The number of samples. Value 0 means no multisample format.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
- floats (bool) – Use floating point precision.
Returns: texture
Return type:
-
Context.
depth_texture
(size, data=None, samples=0) → Texture Create a
Texture
.Parameters: - size (tuple) – The width and height of the texture.
- data (bytes) – Content of the texture.
Keyword Arguments: - samples (int) – The number of samples. Value 0 means no multisample format.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
Returns: depth texture
Return type:
-
Context.
texture3d
(size, components, data=None, floats=False) → Texture3D Create a
Texture3D
.Parameters: - size (tuple) – The width, height and depth of the texture.
- components (int) – The number of components 1, 2, 3 or 4.
- data (bytes) – Content of the texture.
Keyword Arguments: - alignment (int) – The byte alignment 1, 2, 4 or 8.
- floats (bool) – Use floating point precision.
Returns: texture
Return type:
-
class
Texture
¶ A Texture is an OpenGL object that contains one or more images that all have the same image format. A texture can be used in two ways. It can be the source of a texture access from a Shader, or it can be used as a render target.
A Texture object cannot be instantiated directly, it requires a context. Use
Context.texture()
orContext.depth_texture()
to create one.-
read
(alignment=1) → bytes¶ Read the content of the texture into a buffer.
Keyword Arguments: alignment (int) – The byte alignment of the pixels. Returns: the pixels Return type: bytes
-
read_into
(buffer, alignment=1, write_offset=0)¶ Read the content of the texture into a buffer.
Parameters: buffer (bytearray) – The buffer that will receive the pixels.
Keyword Arguments: - alignment (int) – The byte alignment of the pixels.
- write_offset (int) – The write offset.
-
write
(data, viewport=None, alignment=1)¶ Update the content of the texture.
-
build_mipmaps
(base=0, max_level=1000)¶ Generate mipmaps.
-
use
(location=0)¶ Bind the texture.
Parameters: location (int) – The texture location. Same as the integer value that is used for sampler2D uniforms in the shaders. The value 0
will bind the texture to theGL_TEXTURE0
binding point.
-
repeat_x
¶ bool – The repeat_x of the texture.
-
repeat_y
¶ bool – The repeat_y of the texture.
-
filter
¶ TextureFilter – The filter of the texture.
-
swizzle
¶ str – The swizzle of the texture.
-
width
¶ int – The width of the texture.
-
height
¶ int – The height of the texture.
-
size
¶ tuple – The size of the texture.
-
components
¶ int – The number of components of the texture.
-
samples
¶ int – The number of samples of the texture.
-
floats
¶ bool – Is the texture using floats?
-
depth
¶ bool – Is the texture a depth texture?
-
-
class
Texture3D
¶ A Texture is an OpenGL object that contains one or more images that all have the same image format. A texture can be used in two ways. It can be the source of a texture access from a Shader, or it can be used as a render target.
A Texture3D object cannot be instantiated directly, it requires a context. Use
Context.texture3d()
to create one.-
read
(alignment=1) → bytes¶ Read the content of the texture into a buffer.
Parameters: - buffer (bytearray) – The buffer that will receive the pixels.
- viewport (tuple) – The viewport.
Keyword Arguments: alignment (int) – The byte alignment of the pixels.
Returns: the pixels
Return type: bytes
-
read_into
(buffer, alignment=1, write_offset=0)¶ Read the content of the texture into a buffer.
Parameters: - buffer (bytearray) – The buffer that will receive the pixels.
- viewport (tuple) – The viewport.
Keyword Arguments: - alignment (int) – The byte alignment of the pixels.
- write_offset (int) – The write offset.
-
write
(data, viewport=None, alignment=1)¶ Update the content of the texture.
-
build_mipmaps
(base=0, max_level=1000)¶ Generate mipmaps.
-
use
(location=0)¶ Bind the texture.
Parameters: location (int) – The texture location. Same as the integer value that is used for sampler3D uniforms in the shaders. The value 0
will bind the texture to theGL_TEXTURE0
binding point.
-
repeat_x
¶ bool – The repeat_x of the texture.
-
repeat_y
¶ bool – The repeat_y of the texture.
-
repeat_z
¶ bool – The repeat_z of the texture.
-
filter
¶ TextureFilter – The filter of the texture.
-
swizzle
¶ str – The swizzle of the texture.
-
width
¶ int – The width of the texture.
-
height
¶ int – The height of the texture.
-
depth
¶ int – The depth of the texture.
-
size
¶ tuple – The size of the texture.
-
components
¶ int – The number of components of the texture.
-
floats
¶ bool – Is the texture using floats?
-
Framebuffers¶
-
Context.
framebuffer
(color_attachments, depth_attachment=None) → Framebuffer A
Framebuffer
is a collection of buffers that can be used as the destination for rendering. The buffers for Framebuffer objects reference images from either Textures or Renderbuffers.Parameters: - color_attachments (list) – A list of Texture or Renderbuffer objects.
- depth_attachment (Renderbuffer or Texture) – A Texture or Renderbuffer object.
Returns: framebuffer
Return type:
-
class
Framebuffer
¶ A
Framebuffer
is a collection of buffers that can be used as the destination for rendering. The buffers for Framebuffer objects reference images from either Textures or Renderbuffers.Create a
Framebuffer
usingContext.framebuffer()
.-
clear
(red=0.0, green=0.0, blue=0.0, alpha=0.0, viewport=None)¶ Clear the framebuffer.
Values must be in
(0, 255)
range. If the viewport is notNone
then scrissor test will be used to clear the given viewport.If the viewport is a 2-tuple it will clear the
(0, 0, width, height)
where(width, height)
is the 2-tuple.If the viewport is a 4-tuple it will clear the given viewport.
Parameters: - red (float) – color component.
- green (float) – color component.
- blue (float) – color component.
- alpha (float) – alpha component.
Keyword Arguments: viewport (tuple) – The viewport.
-
use
()¶ Bind the framebuffer. Set the target for the VertexArray.render or VertexArray.transform methods.
-
read
(viewport=None, components=3, attachment=0, alignment=1, floats=False) → bytes¶ Read the content of the framebuffer.
Parameters: - viewport (tuple) – The viewport.
- components (int) – The number of components to read.
Keyword Arguments: - attachment (int) – The color attachment.
- alignment (int) – The byte alignment of the pixels.
- floats (bool) – The precision of the pixels.
Returns: the pixels
Return type: bytes
-
read_into
(buffer, viewport=None, components=3, attachment=0, alignment=1, floats=False, write_offset=0)¶ Read the content of the framebuffer into a buffer.
Parameters: - buffer (bytearray) – The buffer that will receive the pixels.
- viewport (tuple) – The viewport.
- components (int) – The number of components to read.
Keyword Arguments: - attachment (int) – The color attachment.
- alignment (int) – The byte alignment of the pixels.
- floats (bool) – The precision of the pixels.
- write_offset (int) – The write offset.
-
viewport
¶ tuple – The viewport of the framebuffer.
-
color_mask
¶ tuple – The color mask of the framebuffer.
-
depth_mask
¶ tuple – The depth mask of the framebuffer.
-
width
¶ int – The width of the framebuffer.
-
height
¶ int – The height of the framebuffer.
-
size
¶ tuple – The size of the framebuffer.
-
samples
¶ int – The samples of the framebuffer.
-
Renderbuffers¶
-
Context.
renderbuffer
(size, components=4, samples=0, floats=True) → Renderbuffer Renderbuffer
objects are OpenGL objects that contain images. They are created and used specifically withFramebuffer
objects.Parameters: - size (tuple) – The width and height of the renderbuffer.
- components (int) – The number of components 1, 2, 3 or 4.
Keyword Arguments: - samples (int) – The number of samples. Value 0 means no multisample format.
- floats (bool) – Use floating point precision.
Returns: renderbuffer
Return type:
-
Context.
depth_renderbuffer
(size, samples=0) → Renderbuffer Renderbuffer
objects are OpenGL objects that contain images. They are created and used specifically withFramebuffer
objects.Parameters: size (tuple) – The width and height of the renderbuffer. Keyword Arguments: samples (int) – The number of samples. Value 0 means no multisample format. Returns: depth renderbuffer Return type: Renderbuffer
-
class
Renderbuffer
¶ Renderbuffer objects are OpenGL objects that contain images. They are created and used specifically with
Framebuffer
objects. They are optimized for use as render targets, whileTexture
objects may not be, and are the logical choice when you do not need to sample from the produced image. If you need to resample, use Textures instead. Renderbuffer objects also natively accommodate multisampling.A Renderbuffer object cannot be instantiated directly, it requires a context. Use
Context.renderbuffer()
orContext.depth_renderbuffer()
to create one.-
width
¶ int – The width of the renderbuffer.
-
height
¶ int – The height of the renderbuffer.
-
size
¶ tuple – The size of the renderbuffer.
-
samples
¶ int – The samples of the renderbuffer.
-
components
¶ int – The components of the renderbuffer.
-
depth
¶ bool – Is the renderbuffer a depth renderbuffer?
-
ComputeShaders¶
-
Context.
compute_shader
(source) → ModernGL.programs.ComputeShader A
ComputeShader
is a Shader Stage that is used entirely for computing arbitrary information. While it can do rendering, it is generally used for tasks not directly related to drawing.Parameters: source (str) – The source of the compute shader. Returns: compute shader program Return type: ComputeShader
-
class
ComputeShader
¶ A Compute Shader is a Shader Stage that is used entirely for computing arbitrary information. While it can do rendering, it is generally used for tasks not directly related to drawing.
-
run
(group_x=1, group_y=1, group_z=1)¶ Run the compute shader.
Parameters: - group_x (int) – The number of work groups to be launched in the X dimension.
- group_y (int) – The number of work groups to be launched in the Y dimension.
- group_z (int) – The number of work groups to be launched in the Z dimension.
-
source
¶ str – The source code of the compute shader.
-
uniforms
¶ UniformMap
– The uniforms of the program. The return value is a dictinary like object. It can be used to accessUniform
objects by name.Examples
Set the value of the uniforms:
# uniform vec3 eye_pos; >>> program.uniforms['eye_pos'].value = (10.0, 20.0, 0.0) # uniform sampler2D my_textures[3]; >>> program.uniforms['my_texture'].value = [0, 3, 2] # The values of `my_textures` will be: my_textures[0] = GL_TEXTURE0 # GL_TEXTURE0 my_textures[1] = GL_TEXTURE0 + 3 # GL_TEXTURE3 my_textures[2] = GL_TEXTURE0 + 2 # GL_TEXTURE2
Get information about the uniforms:
>>> program.uniforms['eye_pos'].location 0 >>> program.uniforms['eye_pos'].dimension 3 >>> program.uniforms['eye_pos'].value (10.0, 20.0, 0.0) >>> program.uniforms['my_textures'].dimension 1 >>> program.uniforms['my_textures'].array_length 3
-
uniform_blocks
¶ UniformBlockMap
– The uniform blocks of the program. The return value is a dictinary like object. It can be used to accessUniformBlock
objects by name.Examples
Get the location of the uniform block:
# uniform custom_material { # ... # }; >>> program.uniform_blocks['custom_material'].location 16
-
InvalidObject¶
-
class
InvalidObject
¶ A ModernGL object turns into an InvalidObject once the
release()
method is successfully called.
Constants¶
Enable Flags¶
-
BLEND
= ModernGL.BLEND¶ GL_BLEND
-
DEPTH_TEST
= ModernGL.DEPTH_TEST¶ GL_DEPTH_TEST
-
CULL_FACE
= ModernGL.CULL_FACE¶ GL_CULL_FACE
-
MULTISAMPLE
= ModernGL.MULTISAMPLE¶ GL_MULTISAMPLE
Versions¶
-
class
Version
(major, minor)¶
-
CORE_330
= ModernGL.CORE_330¶ OpenGL 3.3
-
CORE_400
= ModernGL.CORE_400¶ OpenGL 4.0
-
CORE_410
= ModernGL.CORE_410¶ OpenGL 4.1
-
CORE_420
= ModernGL.CORE_420¶ OpenGL 4.2
-
CORE_430
= ModernGL.CORE_430¶ OpenGL 4.3
-
CORE_440
= ModernGL.CORE_440¶ OpenGL 4.4
-
CORE_450
= ModernGL.CORE_450¶ OpenGL 4.5
Primitives¶
-
class
Primitive
¶
-
TRIANGLES
= ModernGL.TRIANGLES¶ GL_TRIANGLES
-
TRIANGLE_STRIP
= ModernGL.TRIANGLE_STRIP¶ GL_TRIANGLE_STRIP
-
TRIANGLE_FAN
= ModernGL.TRIANGLE_FAN¶ GL_TRIANGLE_FAN
-
LINES
= ModernGL.LINES¶ GL_LINES
-
LINE_STRIP
= ModernGL.LINE_STRIP¶ GL_LINE_STRIP
-
LINE_LOOP
= ModernGL.LINE_LOOP¶ GL_LINE_LOOP
-
POINTS
= ModernGL.POINTS¶ GL_POINTS
-
LINE_STRIP_ADJACENCY
= ModernGL.LINE_STRIP_ADJACENCY¶ GL_LINE_STRIP_ADJACENCY
-
LINES_ADJACENCY
= ModernGL.LINES_ADJACENCY¶ GL_LINES_ADJACENCY
-
TRIANGLE_STRIP_ADJACENCY
= ModernGL.TRIANGLE_STRIP_ADJACENCY¶ GL_TRIANGLE_STRIP_ADJACENCY
-
TRIANGLES_ADJACENCY
= ModernGL.TRIANGLES_ADJACENCY¶ GL_TRIANGLES_ADJACENCY
Examples¶
01. Hello World!¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import struct
import GLWindow
import ModernGL
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
# Shaders & Program
prog = ctx.program([
ctx.vertex_shader('''
#version 330
in vec2 vert;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
}
'''),
ctx.fragment_shader('''
#version 330
out vec4 color;
void main() {
color = vec4(0.3, 0.5, 1.0, 1.0);
}
'''),
])
# Buffer
vbo = ctx.buffer(struct.pack(
'6f',
0.0, 0.8,
-0.6, -0.8,
0.6, -0.8,
))
# Put everything together
vao = ctx.simple_vertex_array(prog, vbo, ['vert'])
# Main loop
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
vao.render()
|
02. Uniforms and Attributes¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | import struct
import GLWindow
import ModernGL
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
# Shaders & Program
prog = ctx.program([
ctx.vertex_shader('''
#version 330
in vec2 vert;
in vec3 vert_color;
out vec3 frag_color;
uniform vec2 scale;
uniform float rotation;
void main() {
frag_color = vert_color;
mat2 rot = mat2(
cos(rotation), sin(rotation),
-sin(rotation), cos(rotation)
);
gl_Position = vec4((rot * vert) * scale, 0.0, 1.0);
}
'''),
ctx.fragment_shader('''
#version 330
in vec3 frag_color;
out vec4 color;
void main() {
color = vec4(frag_color, 1.0);
}
'''),
])
# Uniforms
scale = prog.uniforms['scale']
rotation = prog.uniforms['rotation']
width, height = wnd.size
scale.value = (height / width * 0.75, 0.75)
# Buffer
vbo = ctx.buffer(struct.pack(
'15f',
1.0, 0.0,
1.0, 0.0, 0.0,
-0.5, 0.86,
0.0, 1.0, 0.0,
-0.5, -0.86,
0.0, 0.0, 1.0,
))
# Put everything together
vao = ctx.simple_vertex_array(prog, vbo, ['vert', 'vert_color'])
# Main loop
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
rotation.value = wnd.time
vao.render()
|
03. Blending¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | import struct
import GLWindow
import ModernGL
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
# Shaders & Program
prog = ctx.program([
ctx.vertex_shader('''
#version 330
in vec2 vert;
in vec4 vert_color;
out vec4 frag_color;
uniform vec2 scale;
uniform float rotation;
void main() {
frag_color = vert_color;
float r = rotation * (0.5 + gl_InstanceID * 0.05);
mat2 rot = mat2(cos(r), sin(r), -sin(r), cos(r));
gl_Position = vec4((rot * vert) * scale, 0.0, 1.0);
}
'''),
ctx.fragment_shader('''
#version 330
in vec4 frag_color;
out vec4 color;
void main() {
color = vec4(frag_color);
}
'''),
])
# Uniforms
scale = prog.uniforms['scale']
rotation = prog.uniforms['rotation']
width, height = wnd.size
scale.value = (height / width * 0.75, 0.75)
# Buffer
vbo = ctx.buffer(struct.pack(
'18f',
1.0, 0.0,
1.0, 0.0, 0.0, 0.5,
-0.5, 0.86,
0.0, 1.0, 0.0, 0.5,
-0.5, -0.86,
0.0, 0.0, 1.0, 0.5,
))
# Put everything together
vao = ctx.simple_vertex_array(prog, vbo, ['vert', 'vert_color'])
# Main loop
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
ctx.enable(ModernGL.BLEND)
rotation.value = wnd.time
vao.render(instances=10)
|
04. Texture¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import os
import struct
import GLWindow
import ModernGL
from PIL import Image
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
# Shaders & Program
prog = ctx.program([
ctx.vertex_shader('''
#version 330
in vec2 vert;
in vec2 tex_coord;
out vec2 v_tex_coord;
uniform vec2 scale;
uniform float rotation;
void main() {
mat2 rot = mat2(
cos(rotation), sin(rotation),
-sin(rotation), cos(rotation)
);
gl_Position = vec4((rot * vert) * scale, 0.0, 1.0);
v_tex_coord = tex_coord;
}
'''),
ctx.fragment_shader('''
#version 330
uniform sampler2D texture;
in vec2 v_tex_coord;
out vec4 color;
void main() {
color = vec4(texture2D(texture, v_tex_coord).rgb, 1.0);
}
'''),
])
# Uniforms
scale = prog.uniforms['scale']
rotation = prog.uniforms['rotation']
width, height = wnd.size
scale.value = (height / width * 0.75, 0.75)
# Buffer
vbo = ctx.buffer(struct.pack(
'12f',
1.0, 0.0, 0.5, 1.0,
-0.5, 0.86, 1.0, 0.0,
-0.5, -0.86, 0.0, 0.0,
))
# Put everything together
vao = ctx.simple_vertex_array(prog, vbo, ['vert', 'tex_coord'])
# Texture
img = Image.open(os.path.join(os.path.dirname(__file__), '..', 'data', 'noise.jpg'))
texture = ctx.texture(img.size, 3, img.tobytes())
texture.use()
# Main loop
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
rotation.value = wnd.time
vao.render()
|
05. Perspective¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | import struct
import GLWindow
import ModernGL
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
vert = ctx.vertex_shader('''
#version 330
in vec3 vert;
uniform float znear;
uniform float zfar;
uniform float fovy;
uniform float ratio;
uniform vec3 center;
uniform vec3 eye;
uniform vec3 up;
mat4 perspective() {
float zmul = (-2.0 * znear * zfar) / (zfar - znear);
float ymul = 1.0 / tan(fovy * 3.14159265 / 360);
float xmul = ymul / ratio;
return mat4(
xmul, 0.0, 0.0, 0.0,
0.0, ymul, 0.0, 0.0,
0.0, 0.0, -1.0, -1.0,
0.0, 0.0, zmul, 0.0
);
}
mat4 lookat() {
vec3 forward = normalize(center - eye);
vec3 side = normalize(cross(forward, up));
vec3 upward = cross(side, forward);
return mat4(
side.x, upward.x, -forward.x, 0,
side.y, upward.y, -forward.y, 0,
side.z, upward.z, -forward.z, 0,
-dot(eye, side), -dot(eye, upward), dot(eye, forward), 1
);
}
void main() {
gl_Position = perspective() * lookat() * vec4(vert, 1.0);
}
''')
frag = ctx.fragment_shader('''
#version 330
out vec4 color;
void main() {
color = vec4(0.04, 0.04, 0.04, 1.0);
}
''')
width, height = wnd.size
prog = ctx.program([vert, frag])
prog.uniforms['znear'].value = 0.1
prog.uniforms['zfar'].value = 1000.0
prog.uniforms['ratio'].value = width / height
prog.uniforms['fovy'].value = 60
prog.uniforms['eye'].value = (3, 3, 3)
prog.uniforms['center'].value = (0, 0, 0)
prog.uniforms['up'].value = (0, 0, 1)
grid = bytes()
for i in range(0, 65):
grid += struct.pack('6f', i - 32, -32.0, 0.0, i - 32, 32.0, 0.0)
grid += struct.pack('6f', -32.0, i - 32, 0.0, 32.0, i - 32, 0.0)
vbo = ctx.buffer(grid)
vao = ctx.simple_vertex_array(prog, vbo, ['vert'])
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
vao.render(ModernGL.LINES, 65 * 4)
|
Julia Fractal¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | import struct
import GLWindow
import ModernGL
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
vert = ctx.vertex_shader('''
#version 330
in vec2 vert;
out vec2 tex;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
tex = vert / 2.0 + vec2(0.5, 0.5);
}
''')
frag = ctx.fragment_shader('''
#version 330
in vec2 tex;
out vec4 color;
uniform vec2 center;
uniform int iter;
void main() {
vec2 z = vec2(5.0 * (tex.x - 0.5), 3.0 * (tex.y - 0.5));
vec2 c = center;
int i;
for(i = 0; i < iter; i++) {
vec2 v = vec2(
(z.x * z.x - z.y * z.y) + c.x,
(z.y * z.x + z.x * z.y) + c.y
);
if (dot(v, v) > 4.0) break;
z = v;
}
float cm = fract((i == iter ? 0.0 : float(i)) * 10 / iter);
color = vec4(
fract(cm + 0.0 / 3.0),
fract(cm + 1.0 / 3.0),
fract(cm + 2.0 / 3.0),
1.0
);
}
''')
prog = ctx.program([vert, frag])
vbo = ctx.buffer(struct.pack('8f', -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0))
vao = ctx.simple_vertex_array(prog, vbo, ['vert'])
prog.uniforms['iter'].value = 100
x, y = (0.49, 0.32)
wnd.grab_mouse(True)
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
mx, my = wnd.mouse_delta
x -= mx / 100
y -= my / 100
prog.uniforms['center'].value = (y, x)
vao.render(ModernGL.TRIANGLE_STRIP)
|
Particle System¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | import math
import random
import struct
import GLWindow
import ModernGL
# Window & Context
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
tvert = ctx.vertex_shader('''
#version 330
uniform vec2 acc;
in vec2 in_pos;
in vec2 in_prev;
out vec2 out_pos;
out vec2 out_prev;
void main() {
out_pos = in_pos * 2.0 - in_prev + acc;
out_prev = in_pos;
}
''')
vert = ctx.vertex_shader('''
#version 330
in vec2 vert;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
}
''')
frag = ctx.fragment_shader('''
#version 330
out vec4 color;
void main() {
color = vec4(0.30, 0.50, 1.00, 1.0);
}
''')
prog = ctx.program([vert, frag])
transform = ctx.program(tvert, ['out_pos', 'out_prev'])
def particle():
a = random.uniform(0.0, math.pi * 2.0)
r = random.uniform(0.0, 0.001)
return struct.pack('2f2f', 0.0, 0.0, math.cos(a) * r - 0.003, math.sin(a) * r - 0.008)
vbo1 = ctx.buffer(b''.join(particle() for i in range(1024)))
vbo2 = ctx.buffer(reserve=vbo1.size)
vao1 = ctx.simple_vertex_array(transform, vbo1, ['in_pos', 'in_prev'])
vao2 = ctx.simple_vertex_array(transform, vbo2, ['in_pos', 'in_prev'])
render_vao = ctx.vertex_array(prog, [
(vbo1, '2f8x', ['vert']),
])
transform.uniforms['acc'].value = (0, -0.0001)
idx = 0
ctx.point_size = 5.0
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
for i in range(8):
vbo1.write(particle(), offset=idx * struct.calcsize('2f2f'))
idx = (idx + 1) % 1024
render_vao.render(ModernGL.POINTS, 1024)
vao1.transform(vbo2, ModernGL.POINTS, 1024)
ctx.copy_buffer(vbo1, vbo2)
|
Tutorials¶
TL;DR¶
For those who want to learn from examples.
Install¶
pip install ModernGL
pip install Pillow numpy
Choose a Window¶
pip install PyQt5
pip install GLWindow
pip install pygame
pip install pyglet
pip install PyOpenGL
Snippets¶
- Download the vscode snippets
- Open vscode
- Press
ctrl+shift+P
- Select
Open User Snippets
- Select
Python
- Paste some snippets from vscode snippets
Warning
Do not replace the python.json if you have python snippets already.
- Create a new python file
- Type
mgl_new_
(not working? -> see the note below)

Note
- Press
ctrl+space
to trigger suggestions. - Try to save an empty file with
.py
ending. - Select the language in the right left corner of the window.
- Make sure you have pasted the snipptes correctly.
- Press
ctrl+shift+P
then selectInsert Snippet
then typemgl_new_
All the ModernGL snippets starts with mgl_
Hello World with PyQt5¶
import struct
import ModernGL
from PyQt5 import QtOpenGL, QtWidgets
class QGLControllerWidget(QtOpenGL.QGLWidget):
def __init__(self):
fmt = QtOpenGL.QGLFormat()
fmt.setVersion(3, 3)
fmt.setProfile(QtOpenGL.QGLFormat.CoreProfile)
fmt.setSampleBuffers(True)
super(QGLControllerWidget, self).__init__(fmt, None)
def initializeGL(self):
self.ctx = ModernGL.create_context()
prog = self.ctx.program([
self.ctx.vertex_shader('''
#version 330
in vec2 vert;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
}
'''),
self.ctx.fragment_shader('''
#version 330
out vec4 color;
void main() {
color = vec4(0.3, 0.5, 1.0, 1.0);
}
'''),
])
vbo = self.ctx.buffer(struct.pack('6f', 0.0, 0.8, -0.6, -0.8, 0.6, -0.8))
self.vao = self.ctx.simple_vertex_array(prog, vbo, ['vert'])
def paintGL(self):
self.ctx.viewport = (0, 0, self.width(), self.height())
self.ctx.clear(0.9, 0.9, 0.9)
self.vao.render()
self.ctx.finish()
app = QtWidgets.QApplication([])
window = QGLControllerWidget()
window.show()
app.exec_()
Hello World with GLWindow¶
import struct
import GLWindow
import ModernGL
wnd = GLWindow.create_window()
ctx = ModernGL.create_context()
prog = ctx.program([
ctx.vertex_shader('''
#version 330
in vec2 vert;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
}
'''),
ctx.fragment_shader('''
#version 330
out vec4 color;
void main() {
color = vec4(0.3, 0.5, 1.0, 1.0);
}
'''),
])
vbo = ctx.buffer(struct.pack('6f', 0.0, 0.8, -0.6, -0.8, 0.6, -0.8))
vao = ctx.simple_vertex_array(prog, vbo, ['vert'])
while wnd.update():
ctx.viewport = wnd.viewport
ctx.clear(0.9, 0.9, 0.9)
vao.render()
Help¶
- For rendering without a window please see: Rendering to a pillow image?
- If you are not familiar with modern OpenGL please see: How to render?
Rendering¶
To render we will need:
Context
— OpenGL supportProgram
— ShadersBuffer
filled with the vertex data.VertexArray
to connect the buffer and the program.
Note
The ModernGL implementation of the VertexArray
stores a reference to the program,
the original OpenGL implementation for Vertex Arrays does not provide this.
To see what other things are different please see: ModernGL vs OpenGL
Context¶
The context can be created once the window is ready.
ctx = ModernGL.create_context()
The ctx
provides functionality to create the Program
, Buffer
and VertexArray
Program¶
A Program Object represents fully processed executable code, in the OpenGL Shading Language.
We will create a simple program from a vertex and fragment shader.
Vertex Shader
Takes the vertices as the input.
#version 330
in vec2 vert;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
}
Fragment Shader
Writes the output to the screen.
#version 330
out vec4 color;
void main() {
color = vec4(0.3, 0.5, 1.0, 1.0);
}
The entire program can be created:
prog = ctx.program([
ctx.vertex_shader('''
#version 330
in vec2 vert;
void main() {
gl_Position = vec4(vert, 0.0, 1.0);
}
'''),
ctx.fragment_shader('''
#version 330
out vec4 color;
void main() {
color = vec4(0.3, 0.5, 1.0, 1.0);
}
'''),
])
Buffer¶
The buffer in the example is created with the following line of code:
vbo = ctx.buffer(struct.pack('6f', 0.0, 0.8, -0.6, -0.8, 0.6, -0.8))
The triangle is given as:
# x y
0.0, 0.8
-0.6, -0.8
0.6, -0.8

The window coordinates

The triangle in window coordinates
VertexArray¶
We want the following to happen:
- Feed the vertex shader with the coordinates of the triangle.
- The vertex shader transforms the triangle to screen coordinates. (we gave the vertices in window coordinates so the vertex shader just passes the coordinates towards)
- The triangle will be rasterized.
- The triangle gets “painted” with the color given in the fragment shader.
In the example the VertexArray is created with the following line of code:
vao = ctx.simple_vertex_array(prog, vbo, ['vert'])
The simple_vertex_array()
creates a VertexArray
object.
The VertexArray will ensure that the prog
program object will be used when rendering.
Additionally detects the format of the in vec2 vert
and binds the attribute to the buffer.
Then finally the rendering is done by:
vao.render()
The expression above expands to:
vao.render(ModernGL.TRIANGLES, vertices=3)
Note
The render()
method’s first parameter is the rendering mode (by default ModernGL.TRIANGLES
are rendered).
The numer of vertices to render is detected form the size of the buffer assigned to the vert
vertex attribute.
The vbo
has 6f
(six floats), with the total of 24 bytes, The vert
vertex attribute is a vec2
with the size of 8 bytes.
The number of vertices detected is 24 / 8 = 3
. It can be read/changed programatically by using the VertexArray.vertices
attibute.
Note
To create a complex VertexArray use the Context.vertex_array()
method.
- Multiple buffers can be used to create VertexArrays.
- Padding, Per Vertex, Per Instance and Per Render attributes are also supported.
- Individual vertex attributes can be bound to different buffers with a custom offset, stride and divisor specified.