Welcome to ModernGL’s documentation!¶
Start here.
ModernGL¶
ModernGL on Github
If you have less time to read this then 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
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, green=0, blue=0, alpha=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 (int) – color component.
- green (int) – color component.
- blue (int) – color component.
- alpha (int) – alpha component.
Keyword Arguments: viewport (tuple) – The viewport.
-
enable
(flag)¶ Enable flags.
Valid flags are:
Parameters: flag – The flag to enable.
-
disable
(flag)¶ Disable flags.
Valid flags are:
Parameters: flag – 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. Use this method to copy framebuffer content into a texture. Use this method to downsample framebuffers, it will allow to read the framebuffer’s content. Use this method to 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) – Width, height.
- components (int) – The number of components 1, 2, 3 or 4.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
- data (bytes) – Content of the image.
Keyword Arguments: floats (bool) – Use floating point precision.
Returns: texture
Return type:
-
depth_texture
(size, data=None, samples=0) → Texture¶ Create a
Texture
.Parameters: - size (tuple) – Width, height.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
- data (bytes) – Content of the image.
Returns: depth texture
Return type:
-
vertex_array
(program, content, index_buffer=None) → VertexArray¶ Create a
VertexArray
.Parameters: Returns: vertex array
Return type:
-
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: Returns: vertex array
Return type:
-
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'])
-
vertex_shader
(source) → Shader¶ The Vertex Shader is the 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¶ Create a
Shader
.Parameters: source (str) – The source code in GLSL. Returns: geometry shader Return type: Shader
-
tess_evaluation_shader
(source) → Shader¶ Create a
Shader
.Parameters: source (str) – The source code in GLSL. Returns: tesselation evaluation shader Return type: Shader
-
tess_control_shader
(source) → Shader¶ Create a
Shader
.Parameters: source (str) – The source code in GLSL. Returns: tesselation control shader Return type: Shader
-
framebuffer
(color_attachments, depth_attachment) → Framebuffer¶ Create a
Framebuffer
.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=True) → Renderbuffer¶ Create a
Renderbuffer
.Parameters: - size (tuple) – The width and height.
- components (int) – The number of components 1, 2, 3 or 4.
Keyword Arguments: - samples – The number of samples. Value 0 means no multisample format.
- floats – Use floating point precision.
Returns: renderbuffer
Return type:
-
depth_renderbuffer
(size, samples=0) → Renderbuffer¶ Create a
Renderbuffer
.Parameters: size (tuple) – The width and height. Keyword Arguments: samples – The number of samples. Value 0 means no multisample format. Returns: depth renderbuffer Return type: Renderbuffer
-
compute_shader
(source) → ComputeShader¶ Create a
ComputeShader
.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.
-
default_texture_unit
¶ int – The default texture unit.
-
max_texture_units
¶ int – The max texture units.
-
default_framebuffer
¶ Framebuffer – The default framebuffer.
-
vendor
¶ str – The vendor.
-
renderer
¶ str – The renderer.
-
version
¶ str – The OpenGL version.
Shaders and Programs¶
-
Context.
vertex_shader
(source) → Shader The Vertex Shader is the 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 Create a
Shader
.Parameters: source (str) – The source code in GLSL. Returns: geometry shader Return type: Shader
-
Context.
tess_evaluation_shader
(source) → Shader Create a
Shader
.Parameters: source (str) – The source code in GLSL. Returns: tesselation evaluation shader Return type: Shader
-
Context.
tess_control_shader
(source) → Shader Create a
Shader
.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'])
-
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
-
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.
-
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¶
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
-
write
(data, offset=0)¶ Write the content.
Parameters: data – The data. Keyword Arguments: offset – 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
(location=0)¶ Bind the buffer to a uniform block.
Parameters: location – The uniform block location.
-
bind_to_storage_buffer
(location=0)¶ Bind the buffer to a shader storage buffer.
Parameters: location – The shader storage location.
-
-
class
BufferAccess
¶ BufferAccess
objects are designed to access aBuffer
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 – The size. Value -1 means all. Keyword Arguments: offset – The offset. Returns: binary data Return type: bytes
-
write
(data, offset=0)¶ Write the content.
Parameters: size – The data. Keyword Arguments: offset – The offset.
-
VertexArray¶
-
Context.
simple_vertex_array
(program, buffer, attributes) → ModernGL.vertex_arrays.VertexArray Create a
VertexArray
.This is an alias for:
format = detect_format(program, attributes) vertex_array(program, [(buffer, format, attributes)])Parameters: Returns: vertex array
Return type:
-
Context.
vertex_array
(program, content, index_buffer=None) → ModernGL.vertex_arrays.VertexArray Create a
VertexArray
.Parameters: Returns: vertex array
Return type:
-
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 – By default TRIANGLES will be used.
- vertices – The number of vertices to transform.
Keyword Arguments: - first – The index of the first vertex to start with.
- instances – 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: - buffer – The buffer to store the output.
- mode – By default TRIANGLES will be used.
- vertices – The number of vertices to transform.
Keyword Arguments: - first – The index of the first vertex to start with.
- instances – 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.
-
Textures¶
-
Context.
texture
(size, components, data=None, samples=0, floats=False) → Texture Create a
Texture
.Parameters: - size (tuple) – Width, height.
- components (int) – The number of components 1, 2, 3 or 4.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
- data (bytes) – Content of the image.
Keyword Arguments: 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) – Width, height.
- alignment (int) – The byte alignment 1, 2, 4 or 8.
- data (bytes) – Content of the image.
Returns: depth 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.-
write
(self, data, viewport=None)¶ Update the content of the texture.
-
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.
-
width
¶ int – The width of the texture.
-
height
¶ int – The height of the texture.
-
size
¶ tuple – The size of the texture.
-
samples
¶ int – The number of samples of the texture.
-
components
¶ int – The number of components of the texture.
-
depth
¶ bool – Is the texture a depth texture?
-
Framebuffers¶
-
Context.
framebuffer
(color_attachments, depth_attachment) → Framebuffer Create a
Framebuffer
.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
¶ Create a
Framebuffer
usingContext.framebuffer()
.-
use
()¶ Bind the framebuffer. Set the target for the VertexArray.render or VertexArray.transform methods.
-
Renderbuffers¶
-
Context.
renderbuffer
(size, components=4, samples=0, floats=True) → Renderbuffer Create a
Renderbuffer
.Parameters: - size (tuple) – The width and height.
- components (int) – The number of components 1, 2, 3 or 4.
Keyword Arguments: - samples – The number of samples. Value 0 means no multisample format.
- floats – Use floating point precision.
Returns: renderbuffer
Return type:
-
Context.
depth_renderbuffer
(size, samples=0) → Renderbuffer Create a
Renderbuffer
.Parameters: size (tuple) – The width and height. Keyword Arguments: samples – 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 Create a
ComputeShader
.Parameters: source (str) – The source of the compute shader. Returns: compute shader program Return type: ComputeShader
-
class
ComputeShader
¶ -
run
(size_x=1, size_y=1, size_z=1)¶ Run the compute shader.
-
source
¶ str – The source code of the compute shader.
-
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 79 80 | 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;
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 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 | 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() {
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);
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(), alignment=4)
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)
|