ModernGL#
ModernGL is a high performance rendering module for Python.
Install#
From PyPI (pip)#
ModernGL is available on PyPI for Windows, OS X and Linux as pre-built wheels. No complication is needed unless you are setting up a development environment.
$ pip install moderngl
Verify that the package is working:
$ python -m moderngl
moderngl 5.6.0
--------------
vendor: NVIDIA Corporation
renderer: GeForce RTX 2080 SUPER/PCIe/SSE2
version: 3.3.0 NVIDIA 441.87
python: 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)]
platform: win32
code: 330
Note
If you experience issues it’s probably related to context creation. More configuration might be needed to run moderngl in some cases. This is especially true on linux running without X. See the context section.
Development Environment#
Ideally you want to fork the repository first.
# .. or clone for your fork
git clone https://github.com/moderngl/moderngl.git
cd moderngl
Building on various platforms:
On Windows you need visual c++ build tools installed: https://visualstudio.microsoft.com/visual-cpp-build-tools/
On OS X you need X Code installed + command line tools (
xcode-select --install
)Building on linux should pretty much work out of the box
To compile moderngl:
python setup.py build_ext --inplace
Package and dev dependencies:
Install
requirements.txt
,tests/requirements.txt
anddocs/requirements.txt
Install the package in editable mode:
pip install -e .
Using with Mesa 3D on Windows#
If you have an old Graphics Card that raises errors when running moderngl, you can try using this method, to make Moderngl work.
There are essentially two ways,
Compiling Mesa yourselves see https://docs.mesa3d.org/install.html.
Using msys2, which provides pre-compiled Mesa binaries.
Using MSYS2#
Download and Install https://www.msys2.org/#installation
Check whether you have 32-bit or 64-bit python.
32-bit python#
If you have 32-bit python, then open C:\msys64\mingw32.exe
and type the following
pacman -S mingw-w64-i686-mesa
It will install mesa and its dependencies. Then you can add C:\msys64\mingw32\bin
to PATH before C:\Windows
and moderngl should be working. Also, you should set
an environment variable called GLCONTEXT_WIN_LIBGL
which contains the path to opengl32
dll from mesa. In this case it should be GLCONTEXT_WIN_LIBGL=C:\msys64\mingw32\bin\opengl32.dll
.
64-bit python#
If you have 64-bit python, then open C:\msys64\mingw64.exe
and type the following
pacman -S mingw-w64-x86_64-mesa
It will install mesa and it’s dependencies. Then you can add C:\msys64\mingw64\bin
to PATH before
C:\Windows
and moderngl should be working. Also, you should set an environment variable called
GLCONTEXT_WIN_LIBGL
which contains the path to opengl32
dll from mesa. In this case it should be GLCONTEXT_WIN_LIBGL=C:\msys64\mingw64\bin\opengl32.dll
Using ModernGL in CI#
Windows CI Configuration#
ModernGL can’t be run directly on Windows CI without the use of Mesa. To get ModernGL running
you should first install Mesa from the MSYS2 project and adding it to the PATH
.
Steps#
Usually MSYS2 project should be installed by default by your CI provider in
C:\msys64
. You can refer the documentation on how to get it installed and make sure to update it.Then login through bash and enter
pacman -S --noconfirm mingw-w64-x86_64-mesa
.C:\msys64\usr\bin\bash -lc "pacman -S --noconfirm mingw-w64-x86_64-mesa"
This will install Mesa binary, which moderngl would be using.
Then add
C:\msys64\mingw64\bin
toPATH
.
$env:PATH = "C:\msys64\mingw64\bin;$env:PATH"Warning
Make sure to delete
C:\msys64\mingw64\bin\python.exe
if it exists because the python provided by them would then be added to Global and some unexpected things may happen.
Then set an environment variable
GLCONTEXT_WIN_LIBGL=C:\msys64\mingw64\bin\opengl32.dll
. This will make glcontext useC:\msys64\mingw64\bin\opengl32.dll
for opengl drivers.Then you can run moderngl as you want to.
Example Configuration#
A example configuration for Github Actions:
name: Hello World
on: [push, pull_request]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
release: false
install: mingw-w64-x86_64-mesa
- name: Test using ModernGL
shell: pwsh
run: |
Remove-Item C:\msys64\mingw64\bin\python.exe -Force
$env:GLCONTEXT_WIN_LIBGL = "C:\msys64\mingw64\bin\opengl32.dll"
python -m pip install -r requirements.txt
python -m pytest
Linux#
For running ModernGL on Linux CI, you would need to configure xvfb
so that it starts a Window in the background.
After that, you should be able to use ModernGL directly.
Steps#
Install
xvfb
from Package Manager.sudo apt-get -y install xvfb
The run the below command, to start Xvfb from background.
sudo /usr/bin/Xvfb :0 -screen 0 1280x1024x24 &
You can run ModernGL now.
Example Configuration#
A example configuration for Github Actions:
name: Hello World
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Prepare
run: |
sudo apt-get -y install xvfb
sudo /usr/bin/Xvfb :0 -screen 0 1280x1024x24 &
- name: Test using ModernGL
run: |
python -m pip install -r requirements.txt
python -m pytest
macOS#
You won’t need any special configuration to run on macOS.
The Guide#
An introduction to OpenGL#
The simplified story#
OpenGL (Open Graphics Library) has a long history reaching all the way back to 1992 when it was created by Silicon Graphics. It was partly based in their proprietary IRIS GL (Integrated Raster Imaging System Graphics Library) library.
Today OpenGL is managed by the Khronos Group, an open industry consortium of over 150 leading hardware and software companies creating advanced, royalty-free, acceleration standards for 3D graphics, Augmented and Virtual Reality, vision and machine learning
The purpose of OpenGL is to provide a standard way to interact with the graphics processing unit to achieve hardware accelerated rendering across several platforms. How this is done under the hood is up to the vendors (AMD, Nvidia, Intel, ARM .. etc) as long as the the specifications are followed.
OpenGL have gone though many versions and it can be confusing when looking up resources. Today we separate “Old OpenGL” and “Modern OpenGL”. From 2008 to 2010 version 3.x of OpenGL evolved until version 3.3 and 4.0 was released simultaneously.
In 2010 version 3.3, 4.0 and 4.1 was released to modernize the api (simplified explanation) creating something that would be able to utilize Direct3D 11-class hardware. OpenGL 3.3 is the first “Modern OpenGL” version (simplified explanation). Everything from this version is forward compatible all the way to the latest 4.x version. An optional deprecation mechanism was introduced to disable outdated features. Running OpenGL in core mode would remove all old features while running in compatibility mode would still allow mixing the old and new api.
Note
OpenGL 2.x, 3.0, 3.1 and 3.2 can of course access some modern OpenGL features directly, but for simplicity we are are focused on version 3.3 as it created the final standard we are using today. Older OpenGL was also a pretty wild world with countless vendor specific extensions. Modern OpenGL cleaned this up quite a bit.
In OpenGL we often talk about the Fixed Pipeline and the Programmable Pipeline.
OpenGL code using the Fixed Pipeline (Old OpenGL) would use functions like
glVertex
, glColor
, glMaterial
glMatrixMode
,
glLoadIdentity
, glBegin
, glEnd
, glVertexPointer
,
glColorPointer
, glPushMatrix
and glPopMatrix
.
The api had strong opinions and limitations on what you
could do hiding what really went on under the hood.
OpenGL code using the Programmable Pipeline (Modern OpenGL) would use
functions like glCreateProgram
, UseProgram
. glCreateShader
,
VertexAttrib*
, glBindBuffer*
, glUniform*
.
This API mainly works with buffers of data and smaller programs
called “shaders” running on the GPU to process this data
using the OpenGL Shading Language (GLSL). This gives
enormous flexibility but requires that we understand the
OpenGL pipeline (actually not that complicated).
Beyond OpenGL#
OpenGL has a lot of “baggage” after 25 years and hardware have drastically changed since its inception. Plans for “OpenGL 5” was started as the Next Generation OpenGL Initiative (glNext). This Turned into the Vulkan API and was a grounds-up redesign to unify OpenGL and OpenGL ES into one common API that will not be backwards compatible with existing OpenGL versions.
This doesn’t mean OpenGL is not worth learning today. In fact learning 3.3+ shaders and understanding the rendering pipeline will greatly help you understand Vulkan. In most cases you can pretty much copy paste the shaders over to Vulkan.
Where do ModernGL fit into all this?#
The ModernGL library exposes the Programmable Pipeline
using OpenGL 3.3 core or higher. However, we don’t expose OpenGL
functions directly. Instead we expose features though various
objects like Buffer
and Program
in a much more “pythonic” way. It’s in other words a higher level
wrapper making OpenGL much easier to reason with. We try to hide
most of the complicated details to make the user more productive.
There are a lot of pitfalls with OpenGL and we remove most of them.
Learning ModernGL is more about learning shaders and the OpenGL pipeline.
Creating a Context#
Before we can do anything with ModernGL we need a Context
.
The Context
object makes us able to create OpenGL resources.
ModernGL can only create headless contexts (no window), but it can also detect
and use contexts from a large range of window libraries. The moderngl-window
library is a good start or reference for rendering to a window.
Most of the example code here assumes a ctx
variable exists with a
headless context:
# standalone=True makes a headless context
ctx = moderngl.create_context(standalone=True)
Detecting an active context created by a window library is simply:
ctx = moderngl.create_context()
More details about context creation can be found in the Context Creation section.
ModernGL Types#
Before throwing you into doing shaders we’ll go through some of the most important types/objects in ModernGL.
Buffer
is an OpenGL buffer we can for example write vertex data into. This data will reside in graphics memory.Program
is a shader program. We can feed it GLSL source code as strings to set up our shader programVertexArray
is a light object responsible for communication betweenBuffer
andProgram
so it can understand how to access the provided buffers and do the rendering call. These objects are currently immutable but are cheap to make.Texture
,TextureArray
,Texture3D
andTextureCube
represents the different texture types.Texture
is a 2d texture and is most commonly used.Framebuffer
is an offscreen render target. It supports different attachments types such as aTexture
and a depth texture/buffer.
All of the objects above can only be created from a Context
object:
The ModernGL types cannot be extended as in; you cannot subclass them.
Extending them must be done through substitution and not inheritance.
This is related to performance. Most objects have an extra
property that can contain any python object.
Shader Introduction#
Shaders are small programs running on the GPU (Graphics Processing Unit). We are using a fairly simple language called GLSL (OpenGL Shading Language). This is a C-style language, so it covers most of the features you would expect with such a language. Control structures (for-loops, if-else statements, etc) exist in GLSL, including the switch statement.
Note
The name “shader” comes from the fact that these small GPU programs was originally created for shading (lighting) 3D scenes. This started as per-vertex lighting when the early shaders could only process vertices and evolved into per-pixel lighting when the fragment shader was introduced. They are used in many other areas today, but the name have stuck around.
Examples of types are:
bool value = true;
int value = 1;
uint value = 1;
float value = 0.0;
double value = 0.0;
Each type above also has a 2, 3 and 4 component version:
// float (default) type
vec2 value = vec2(0.0, 1.0);
vec3 value = vec3(0.0, 1.0, 2.0);
vec4 value = vec4(0.0);
// signed and unsigned integer vectors
ivec3 value = ivec3(0);
uvec3 value = ivec3(0);
// etc ..
More about GLSL data types can be found in the Khronos wiki.
The available functions are for example: radians
, degrees
sin
, `cos
, tan
, asin
, acos
, atan
, pow
exp
, log
, exp2
, log2
, sqrt
, inversesqrt
,
abs
, sign
, floor
, ceil
, fract
, mod
,
min
, max
, clamp
, mix
, step
, smoothstep
,
length
, distance
, dot
, cross
, normalize
,
faceforward
, reflect
, refract
, any
, all
etc.
All functions can be found in the OpenGL Reference Page
(exclude functions starting with gl
).
Most of the functions exist in several overloaded versions
supporting different data types.
The basic setup for a shader is the following:
#version 330
void main() {
}
The #version
statement is mandatory and should at least be 330
(GLSL version 3.3 matching OpenGL version 3.3). The version statement
should always be the first line in the source code.
Higher version number is only needed if more fancy features are needed.
By the time you need those you probably know what you are doing.
What we also need to realize when working with shaders is that they are executed in parallel across all the cores on your GPU. This can be everything from tens, hundreds, thousands or more cores. Even integrated GPUs today are very competent.
For those who have not worked with shaders before it can be mind-boggling to see the work they can get done in a matter of microseconds. All shader executions / rendering calls are also asynchronous running in the background while your python code is doing other things (but certain operations can cause a “sync” stalling until the shader program is done)
Vertex Shader (transforms)#
Let’s get our hands dirty right away and jump into it by showing the
simplest forms of shaders in OpenGL. These are called transforms or
transform feedback. Instead of drawing to the screen we simply
capture the output of a shader into a Buffer
.
The example below shows shader program with only a vertex shader.
It has no input data, but we can still force it to run N times.
The gl_VertexID
(int) variable is a built-in value in vertex
shaders containing an integer representing the vertex number
being processed.
Input variables in vertex shaders are called attributes (we have no inputs in this example) while output values are called varyings.
import struct
import moderngl
ctx = moderngl.create_context(standalone=True)
program = ctx.program(
vertex_shader="""
#version 330
// Output values for the shader. They end up in the buffer.
out float value;
out float product;
void main() {
// Implicit type conversion from int to float will happen here
value = gl_VertexID;
product = gl_VertexID * gl_VertexID;
}
""",
# What out varyings to capture in our buffer!
varyings=["value", "product"],
)
NUM_VERTICES = 10
# We always need a vertex array in order to execute a shader program.
# Our shader doesn't have any buffer inputs, so we give it an empty array.
vao = ctx.vertex_array(program, [])
# Create a buffer allocating room for 20 32 bit floats
buffer = ctx.buffer(reserve=NUM_VERTICES * 8)
# Start a transform with buffer as the destination.
# We force the vertex shader to run 10 times
vao.transform(buffer, vertices=NUM_VERTICES)
# Unpack the 20 float values from the buffer (copy from graphics memory to system memory).
# Reading from the buffer will cause a sync (the python program stalls until the shader is done)
data = struct.unpack("20f", buffer.read())
for i in range(0, 20, 2):
print("value = {}, product = {}".format(*data[i:i+2]))
Output the program is:
value = 0.0, product = 0.0
value = 1.0, product = 1.0
value = 2.0, product = 4.0
value = 3.0, product = 9.0
value = 4.0, product = 16.0
value = 5.0, product = 25.0
value = 6.0, product = 36.0
value = 7.0, product = 49.0
value = 8.0, product = 64.0
value = 9.0, product = 81.0
The GPU is at the very least slightly offended by the meager amount work we assigned it, but this at least shows the basic concept of transforms. We would in most situations also not read the results back into system memory because it’s slow, but sometimes it is needed.
This shader program could for example be modified to generate some
geometry or data for any other purpose you might imagine useful.
Using modulus (mod
) on gl_VertexID
can get you pretty far.
Rendering#
1import moderngl
2import numpy as np
3
4from PIL import Image
5
6ctx = moderngl.create_standalone_context()
7
8prog = ctx.program(
9 vertex_shader='''
10 #version 330
11
12 in vec2 in_vert;
13 in vec3 in_color;
14
15 out vec3 v_color;
16
17 void main() {
18 v_color = in_color;
19 gl_Position = vec4(in_vert, 0.0, 1.0);
20 }
21 ''',
22 fragment_shader='''
23 #version 330
24
25 in vec3 v_color;
26
27 out vec3 f_color;
28
29 void main() {
30 f_color = v_color;
31 }
32 ''',
33)
34
35x = np.linspace(-1.0, 1.0, 50)
36y = np.random.rand(50) - 0.5
37r = np.ones(50)
38g = np.zeros(50)
39b = np.zeros(50)
40
41vertices = np.dstack([x, y, r, g, b])
42
43vbo = ctx.buffer(vertices.astype('f4').tobytes())
44vao = ctx.simple_vertex_array(prog, vbo, 'in_vert', 'in_color')
45
46fbo = ctx.simple_framebuffer((512, 512))
47fbo.use()
48fbo.clear(0.0, 0.0, 0.0, 1.0)
49vao.render(moderngl.LINE_STRIP)
50
51Image.frombytes('RGB', fbo.size, fbo.read(), 'raw', 'RGB', 0, -1).show()
Program#
ModernGL is different from standard plotting libraries. You can define your own shader program to render stuff. This could complicate things, but also provides freedom on how you render your data.
Here is a sample program that passes the input vertex coordinates as is to screen coordinates.
Screen coordinates are in the [-1, 1], [-1, 1] range for x and y axes. The (-1, -1) point is the lower left corner of the screen.

The screen coordinates#
The program will also process a color information.
Entire source
1import moderngl
2
3ctx = moderngl.create_standalone_context()
4
5prog = ctx.program(
6 vertex_shader='''
7 #version 330
8
9 in vec2 in_vert;
10 in vec3 in_color;
11
12 out vec3 v_color;
13
14 void main() {
15 v_color = in_color;
16 gl_Position = vec4(in_vert, 0.0, 1.0);
17 }
18 ''',
19 fragment_shader='''
20 #version 330
21
22 in vec3 v_color;
23
24 out vec3 f_color;
25
26 void main() {
27 f_color = v_color;
28 }
29 ''',
30)
Vertex Shader
in vec2 in_vert;
in vec3 in_color;
out vec3 v_color;
void main() {
v_color = in_color;
gl_Position = vec4(in_vert, 0.0, 1.0);
}
Fragment Shader
in vec3 v_color;
out vec3 f_color;
void main() {
f_color = v_color;
}
Proceed to the next step.
VertexArray#
1import moderngl
2import numpy as np
3
4ctx = moderngl.create_standalone_context()
5
6prog = ctx.program(
7 vertex_shader='''
8 #version 330
9
10 in vec2 in_vert;
11 in vec3 in_color;
12
13 out vec3 v_color;
14
15 void main() {
16 v_color = in_color;
17 gl_Position = vec4(in_vert, 0.0, 1.0);
18 }
19 ''',
20 fragment_shader='''
21 #version 330
22
23 in vec3 v_color;
24
25 out vec3 f_color;
26
27 void main() {
28 f_color = v_color;
29 }
30 ''',
31)
32
33x = np.linspace(-1.0, 1.0, 50)
34y = np.random.rand(50) - 0.5
35r = np.ones(50)
36g = np.zeros(50)
37b = np.zeros(50)
38
39vertices = np.dstack([x, y, r, g, b])
40
41vbo = ctx.buffer(vertices.astype('f4').tobytes())
42vao = ctx.simple_vertex_array(prog, vbo, 'in_vert', 'in_color')
Proceed to the next step.
Topics#
The Lifecycle of a ModernGL Object#
From moderngl 5.7 we support three different garbage collection modes.
This should be configured using the Context.gc_mode
attribute
preferably right after the context is created.
The current supported modes are:
None
: (default) No garbage collection is performed. Objects needs to to be manually released like in previous versions of moderngl."context_gc"
: Dead objects are collected inContext.objects
. These can periodically be released usingContext.gc()
."auto"
: Dead objects are destroyed automatically like we would expect in python.
It’s important to realize here that garbage collection is not about the python objects itself, but the underlying OpenGL objects. ModernGL operates in many different environments were garbage collection can be a challenge. This depends on factors like who is controlling the existence of the OpenGL context and challenges around threading in python.
Standalone / Headless Context#
In this instance we control when the context is created and destroyed.
Using "auto"
garbage collection is perfectly reasonable in this
situation.
Context Detection#
When detecting an existing context from some window library we have no
direct control over the existence of the context. Using "auto"
mode
is dangerous can can cause crashes especially on application exit.
The window and context is destroyed and closed, then moderngl will
try to destroy resources in a context that no longer exists.
Use "context_gc"
mode to avoid this.
It can be possible to switch the gc_mode
to None
when
the window is closed. This can still be a problem if you have
race conditions due to resources being created in the render loop.
The Threading Issue#
When using threads in python the garbage collector can run in any thread.
This is a problem for OpenGL because only the main thread is allowed
to interact with the context. When using threads in your application
you should be using "context_gc"
mode and periodically call Context.gc
for example during every frame swap.
Manually Releasing Objects#
Objects in moderngl don’t automatically release the OpenGL resources when
gc_mode=None
is used.
Each type has a release()
method that needs to be called to properly clean
up everything:
# Create a texture
texture = ctx.texture((10, 10), 4)
# Properly release the opengl resources
texture.release()
Detecting Released Objects#
If you for some reason need to detect if a resource was released it can be done
by checking the type of the internal moderngl object (.mglo
property):
>> import moderngl
>> ctx = moderngl.create_standalone_context()
>> buffer = ctx.buffer(reserve=1024)
>> type(buffer.mglo)
<class 'mgl.Buffer'>
>> buffer.release()
>> type(buffer.mglo)
<class '_moderngl.InvalidObject'>
>> type(buffer.mglo) == moderngl.mgl.InvalidObject
True
Context Creation#
Note
From moderngl 5.6 context creation is handled by the glcontext package. This makes expanding context support easier for users lowering the bar for contributions. It also means context creation is no longer limited by a moderngl releases.
Note
This page might not list all supported backends as the glcontext project keeps evolving. If using anything outside of the default contexts provided per OS, please check the listed backends in the glcontext project.
Introduction#
A context is an object giving moderngl access to opengl instructions (greatly simplified). How a context is created depends on your operating system and what kind of platform you want to target.
In the vast majority of cases you’ll be using the default context
backend supported by your operating system. This backend will be
automatically selected unless a specific backend
parameter is used.
Default backend per OS
Windows: wgl / opengl32.dll
Linux: x11/glx/libGL
OS X: CGL
These default backends support two modes:
Detecting an exiting active context possibly created by a window library such as glfw, sdl2, pyglet etc.
Creating a headless context (No visible window)
Detecting an existing active context created by a window library:
import moderngl
# Create the window with an OpenGL context (Most window libraries support this)
ctx = moderngl.create_context()
# If successful we can now render to the window
print("Default framebuffer is:", ctx.screen)
A great reference using various window libraries can be found here: https://github.com/moderngl/moderngl-window/tree/master/moderngl_window/context
Creating a headless context:
import moderngl
# Create the context
ctx = moderngl.create_context(standalone=True)
# Create a framebuffer we can render to
fbo = ctx.simple_framebuffer((100, 100), 4)
fbo.use()
Require a minimum OpenGL version#
ModernGL only support 3.3+ contexts. By default version 3.3 is passed in as the minimum required version of the context returned by the backend.
To require a specific version:
moderngl.create_context(require=430)
This will require OpenGL 4.3. If a lower context version is returned the context creation will fail.
This attribute can be accessed in Context.version_code
and will be updated to contain the actual version code of the
context (If higher than required).
Specifying context backend#
A backend
can be passed in for more advanced usage.
For example: Making a headless EGL context on linux:
ctx = moderngl.create_context(standalone=True, backend='egl')
Note
Each backend supports additional keyword arguments for more advanced configuration. This can for example be the exact name of the library to load. More information in the glcontext docs.
Context Sharing#
Warning
Object sharing is an experimental feature
Some context support the share
parameters enabling
object sharing between contexts. This is not needed
if you are attaching to existing context with share mode enabled.
For example if you create two windows with glfw enabling object sharing.
ModernGL objects (such as moderngl.Buffer
, moderngl.Texture
, ..)
has a ctx
property containing the context they were created in.
Still ModernGL do not check what context is currently active when
accessing these objects. This means the object can be used
in both contexts when sharing is enabled.
This should in theory work fine with object sharing enabled:
data1 = numpy.array([1, 2, 3, 4], dtype='u1')
data2 = numpy.array([4, 3, 2, 1], dtype='u1')
ctx1 = moderngl.create_context(standalone=True)
ctx2 = moderngl.create_context(standalone=True, share=True)
with ctx1 as ctx:
b1 = ctx.buffer(data1)
with ctx2 as ctx:
b2 = ctx.buffer(data2)
print(b1.glo) # Displays: 1
print(b2.glo) # Displays: 2
with ctx1:
print(b1.read())
print(b2.read())
with ctx2:
print(b1.read())
print(b2.read())
Still, there are some limitations to object sharing. Especially objects that reference other objects (framebuffer, vertex array object, etc.)
More information for a deeper dive:
Context Info#
Various information such as limits and driver information can be found in the
info
property. It can often be useful to know
the vendor and render for the context:
>>> import moderngl
>>> ctx = moderngl.create_context(standalone=True, gl_version=(4.6))
>>> ctx.info["GL_VENDOR"]
'NVIDIA Corporation'
>>> ctx.info["GL_RENDERER"]
'GeForce RTX 2080 SUPER/PCIe/SSE2'
>>> ctx.info["GL_VERSION"]
'3.3.0 NVIDIA 456.71'
Note that it reports version 3.3 here because ModernGL by default requests a version 3.3 context (minimum requirement).
Texture Format#
Description#
The format of a texture can be described by the dtype
parameter
during texture creation. For example the moderngl.Context.texture()
.
The default dtype
is f1
. Each component is an unsigned byte (0-255)
that is normalized when read in a shader into a value from 0.0 to 1.0.
The formats are based on the string formats used in numpy.
Some quick example of texture creation:
# RGBA (4 component) f1 texture
texture = ctx.texture((100, 100), 4) # dtype f1 is default
# R (1 component) f4 texture (32 bit float)
texture = ctx.texture((100, 100), 1, dype="f4")
# RG (2 component) u2 texture (16 bit unsigned integer)
texture = ctx.texture((100, 100), 2, dtype="u2")
Texture contents can be passed in using the data
parameter during
creation or by using the write()
method. The object passed in
data
can be bytes or any object supporting the buffer protocol.
When writing data to texture the data type can be derived from
the internal format in the tables below. f1
textures takes
unsigned bytes (u1
or numpy.uint8
in numpy) while
f2
textures takes 16 bit floats (f2
or numpy.float16
in numpy).
Float Textures#
f1
textures are just unsigned bytes (8 bits per component) (GL_UNSIGNED_BYTE
)
The f1
texture is the most commonly used textures in OpenGL
and is currently the default. Each component takes 1 byte (4 bytes for RGBA).
This is not really a “real” float format, but a shader will read
normalized values from these textures. 0-255
(byte range) is read
as a value from 0.0
to 1.0
in shaders.
In shaders the sampler type should be sampler2D
, sampler2DArray
sampler3D
, samplerCube
etc.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
f1 |
1 |
GL_RED |
GL_R8 |
f1 |
2 |
GL_RG |
GL_RG8 |
f1 |
3 |
GL_RGB |
GL_RGB8 |
f1 |
4 |
GL_RGBA |
GL_RGBA8 |
f2
textures stores 16 bit float values (GL_HALF_FLOAT
).
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
f2 |
1 |
GL_RED |
GL_R16F |
f2 |
2 |
GL_RG |
GL_RG16F |
f2 |
3 |
GL_RGB |
GL_RGB16F |
f2 |
4 |
GL_RGBA |
GL_RGBA16F |
f4
textures store 32 bit float values. (GL_FLOAT
)
Note that some drivers do not like 3 components because of alignment.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
f4 |
1 |
GL_RED |
GL_R32F |
f4 |
2 |
GL_RG |
GL_RG32F |
f4 |
3 |
GL_RGB |
GL_RGB32F |
f4 |
4 |
GL_RGBA |
GL_RGBA32F |
Integer Textures#
Integer textures come in a signed and unsigned version. The advantage
with integer textures is that shader can read the raw integer values
from them using for example usampler*
(unsigned) or isampler*
(signed).
Integer textures do not support LINEAR
filtering (only NEAREST
).
Unsigned#
u1
textures store unsigned byte values (GL_UNSIGNED_BYTE
).
In shaders the sampler type should be usampler2D
, usampler2DArray
usampler3D
, usamplerCube
etc.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
u1 |
1 |
GL_RED_INTEGER |
GL_R8UI |
u1 |
2 |
GL_RG_INTEGER |
GL_RG8UI |
u1 |
3 |
GL_RGB_INTEGER |
GL_RGB8UI |
u1 |
4 |
GL_RGBA_INTEGER |
GL_RGBA8UI |
u2
textures store 16 bit unsigned integers (GL_UNSIGNED_SHORT
).
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
u2 |
1 |
GL_RED_INTEGER |
GL_R16UI |
u2 |
2 |
GL_RG_INTEGER |
GL_RG16UI |
u2 |
3 |
GL_RGB_INTEGER |
GL_RGB16UI |
u2 |
4 |
GL_RGBA_INTEGER |
GL_RGBA16UI |
u4
textures store 32 bit unsigned integers (GL_UNSIGNED_INT
)
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
u4 |
1 |
GL_RED_INTEGER |
GL_R32UI |
u4 |
2 |
GL_RG_INTEGER |
GL_RG32UI |
u4 |
3 |
GL_RGB_INTEGER |
GL_RGB32UI |
u4 |
4 |
GL_RGBA_INTEGER |
GL_RGBA32UI |
Signed#
i1
textures store signed byte values (GL_BYTE
).
In shaders the sampler type should be isampler2D
, isampler2DArray
isampler3D
, isamplerCube
etc.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
i1 |
1 |
GL_RED_INTEGER |
GL_R8I |
i1 |
2 |
GL_RG_INTEGER |
GL_RG8I |
i1 |
3 |
GL_RGB_INTEGER |
GL_RGB8I |
i1 |
4 |
GL_RGBA_INTEGER |
GL_RGBA8I |
i2
textures store 16 bit integers (GL_SHORT
).
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
i2 |
1 |
GL_RED_INTEGER |
GL_R16I |
i2 |
2 |
GL_RG_INTEGER |
GL_RG16I |
i2 |
3 |
GL_RGB_INTEGER |
GL_RGB16I |
i2 |
4 |
GL_RGBA_INTEGER |
GL_RGBA16I |
i4
textures store 32 bit integers (GL_INT
)
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
i4 |
1 |
GL_RED_INTEGER |
GL_R32I |
i4 |
2 |
GL_RG_INTEGER |
GL_RG32I |
i4 |
3 |
GL_RGB_INTEGER |
GL_RGB32I |
i4 |
4 |
GL_RGBA_INTEGER |
GL_RGBA32I |
Normalized Integer Textures#
Normalized integers are integer texture, but texel reads in a shader
returns normalized values ([0.0, 1.0]
). For example an unsigned 16
bit fragment with the value 2**16-1
will be read as 1.0
.
Normalized integer textures should use the sampler2D sampler type. Also note that there’s no standard for normalized 32 bit integer textures because a float32 doesn’t have enough precision to express a 32 bit integer as a number between 0.0 and 1.0.
Unsigned#
nu1
textures is really the same as an f1
. Each component
is a GL_UNSIGNED_BYTE
, but are read by the shader in normalized
form [0.0, 1.0]
.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
nu1 |
1 |
GL_RED |
GL_R8 |
nu1 |
2 |
GL_RG |
GL_RG8 |
nu1 |
3 |
GL_RGB |
GL_RGB8 |
nu1 |
4 |
GL_RGBA |
GL_RGBA8 |
nu2
textures store 16 bit unsigned integers (GL_UNSIGNED_SHORT
).
The value range [0, 2**16-1]
will be normalized into [0.0, 1.0]
.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
nu2 |
1 |
GL_RED |
GL_R16 |
nu2 |
2 |
GL_RG |
GL_RG16 |
nu2 |
3 |
GL_RGB |
GL_RGB16 |
nu2 |
4 |
GL_RGBA |
GL_RGBA16 |
Signed#
ni1
textures store 8 bit signed integers (GL_BYTE
).
The value range [0, 127]
will be normalized into [0.0, 1.0]
.
Negative values will be clamped.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
ni1 |
1 |
GL_RED |
GL_R8 |
ni1 |
2 |
GL_RG |
GL_RG8 |
ni1 |
3 |
GL_RGB |
GL_RGB8 |
ni1 |
4 |
GL_RGBA |
GL_RGBA8 |
ni2
textures store 16 bit signed integers (GL_SHORT
).
The value range [0, 2**15-1]
will be normalized into [0.0, 1.0]
.
Negative values will be clamped.
dtype |
Components |
Base Format |
Internal Format |
---|---|---|---|
ni2 |
1 |
GL_RED |
GL_R16 |
ni2 |
2 |
GL_RG |
GL_RG16 |
ni2 |
3 |
GL_RGB |
GL_RGB16 |
ni2 |
4 |
GL_RGBA |
GL_RGBA16 |
Overriding internalformat#
Context.texture()
supports overriding the internalformat
of the texture. This is only necessary when needing a different
internal formats from the tables above. This can for
example be GL_SRGB8 = 0x8C41
or some compressed format.
You may also need to look up in Context.extensions
to ensure the context supports internalformat you are using.
We do not provide the enum values for these alternative internalformats.
They can be looked up in the registry : https://raw.githubusercontent.com/KhronosGroup/OpenGL-Registry/master/xml/gl.xml
Example:
texture = ctx.texture(image.size, 3, data=srbg_data, internal_format=GL_SRGB8)
Buffer Format#
Description#
A buffer format is a short string describing the layout of data in a vertex buffer object (VBO).
A VBO often contains a homogeneous array of C-like structures. The buffer
format describes what each element of the array looks like. For example,
a buffer containing an array of high-precision 2D vertex positions might have
the format "2f8"
- each element of the array consists of two floats, each
float being 8 bytes wide, ie. a double.
Buffer formats are used in the Context.vertex_array()
constructor,
as the 2nd component of the content arg.
See the Example of simple usage below.
Syntax#
A buffer format looks like:
[count]type[size] [[count]type[size]...] [/usage]
Where:
count
is an optional integer. If omitted, it defaults to1
.type
is a single character indicating the data type:f
floati
intu
unsigned intx
padding
size
is an optional number of bytes used to store the type. If omitted, it defaults to 4 for numeric types, or to 1 for padding bytes.A format may contain multiple, space-separated
[count]type[size]
triples (See the Example of single interleaved array), followed by:/usage
is optional. It should be preceded by a space, and then consists of a slash followed by a single character, indicating how successive values in the buffer should be passed to the shader:/v
per vertex. Successive values from the buffer are passed to each vertex. This is the default behavior if usage is omitted./i
per instance. Successive values from the buffer are passed to each instance./r
per render. the first buffer value is passed to every vertex of every instance. ie. behaves like a uniform.
When passing multiple VBOs to a VAO, the first one must be of usage
/v
, as shown in the Example of multiple arrays with differing /usage.
Valid combinations of type and size are:
size |
||||
---|---|---|---|---|
type |
1 |
2 |
4 |
8 |
f |
Unsigned byte (normalized) |
Half float |
Float |
Double |
i |
Byte |
Short |
Int |
- |
u |
Unsigned byte |
Unsigned short |
Unsigned int |
- |
x |
1 byte |
2 bytes |
4 bytes |
8 bytes |
The entry f1
has two unusual properties:
Its type is
f
(for float), but it defines a buffer containing unsigned bytes. For this size of floats only, the values are normalized, ie. unsigned bytes from 0 to 255 in the buffer are converted to float values from 0.0 to 1.0 by the time they reach the vertex shader. This is intended for passing in colors as unsigned bytes.Three unsigned bytes, with a format of
3f1
, may be assigned to avec3
attribute, as one would expect. But, from ModernGL v6.0, they can alternatively be passed to avec4
attribute. This is intended for passing a buffer of 3-byte RGB values into an attribute which also contains an alpha channel.
There are no size 8 variants for types i
and u
.
This buffer format syntax is specific to ModernGL. As seen in the usage
examples below, the formats sometimes look similar to the format strings passed
to struct.pack
, but that is a different syntax (documented here.)
Buffer formats can represent a wide range of vertex attribute formats.
For rare cases of specialized attribute formats that are not expressible
using buffer formats, there is a VertexArray.bind()
method, to
manually configure the underlying OpenGL binding calls. This is not generally
recommended.
Examples#
Example buffer formats#
"2f"
has a count of 2
and a type of f
(float). Hence it describes
two floats, passed to a vertex shader’s vec2
attribute. The size of the
floats is unspecified, so defaults to 4
bytes. The usage of the buffer is
unspecified, so defaults to /v
(vertex), meaning each successive pair of
floats in the array are passed to successive vertices during the render call.
"3i2/i"
means three i
(integers). The size of each integer is 2
bytes, ie. they are shorts, passed to an ivec3
attribute.
The trailing /i
means that consecutive values
in the buffer are passed to successive instances during an instanced render
call. So the same value is passed to every vertex within a particular instance.
Buffers contining interleaved values are represented by multiple space separated count-type-size triples. Hence:
"2f 3u x /v"
means:
2f
: two floats, passed to avec2
attribute, followed by
3u
: three unsigned bytes, passed to auvec3
, then
x
: a single byte of padding, for alignment.
The /v
indicates successive elements in the buffer are passed to successive
vertices during the render. This is the default, so the /v
could be
omitted.
Example of simple usage#
Consider a VBO containing 2D vertex positions, forming a single triangle:
# a 2D triangle (ie. three (x, y) vertices)
verts = [
0.0, 0.9,
-0.5, 0.0,
0.5, 0.0,
]
# pack all six values into a binary array of C-like floats
verts_buffer = struct.pack("6f", *verts)
# put the array into a VBO
vbo = ctx.buffer(verts_buffer)
# use the VBO in a VAO
vao = ctx.vertex_array(
shader_program,
[
(vbo, "2f", "in_vert"), # <---- the "2f" is the buffer format
]
index_buffer_object
)
The line (vbo, "2f", "in_vert")
, known as the VAO content, indicates that
vbo
contains an array of values, each of which consists of two floats.
These values are passed to an in_vert
attribute,
declared in the vertex shader as:
in vec2 in_vert;
The "2f"
format omits a size
component, so the floats default to
4-bytes each. The format also omits the trailing /usage
component, which
defaults to /v
, so successive (x, y) rows from the buffer are passed to
successive vertices during the render call.
Example of single interleaved array#
A buffer array might contain elements consisting of multiple interleaved values.
For example, consider a buffer array, each element of which contains a 2D vertex position as floats, an RGB color as unsigned ints, and a single byte of padding for alignment:
position |
color |
padding |
|||
x |
y |
r |
g |
b |
- |
float |
float |
unsigned byte |
unsigned byte |
unsigned byte |
byte |
Such a buffer, however you choose to construct it, would then be passed into a VAO using:
vao = ctx.vertex_array(
shader_program,
[
(vbo, "2f 3f1 x", "in_vert", "in_color")
]
index_buffer_object
)
The format starts with 2f
, for the two position floats, which will
be passed to the shader’s in_vert
attribute, declared as:
in vec2 in_vert;
Next, after a space, is 3f1
, for the three color unsigned bytes, which
get normalized to floats by f1
. These floats will be passed to the shader’s
in_color
attribute:
in vec3 in_color;
Finally, the format ends with x
, a single byte of padding, which needs
no shader attribute name.
Example of multiple arrays with differing /usage
#
To illustrate the trailing /usage
portion, consider rendering a dozen cubes
with instanced rendering. We will use:
vbo_verts_normals
contains vertices (3 floats) and normals (3 floats) for the vertices within a single cube.vbo_offset_orientation
contains offsets (3 floats) and orientations (9 float matrices) that are used to position and orient each cube.vbo_colors
contains colors (3 floats). In this example, there is only one color in the buffer, that will be used for every vertex of every cube.
Our shader will take all the above values as attributes.
We bind the above VBOs in a single VAO, to prepare for an instanced rendering call:
vao = ctx.vertex_array(
shader_program,
[
(vbo_verts_normals, "3f 3f /v", "in_vert", "in_norm"),
(vbo_offset_orientation, "3f 9f /i", "in_offset", "in_orientation"),
(vbo_colors, "3f /r", "in_color"),
]
index_buffer_object
)
So, the vertices and normals, using /v
, are passed to each vertex within
an instance. This fulfills the rule that the first VBO in a VAO must have usage
/v
. These are passed to vertex attributes as:
in vec3 in_vert;
in vec3 in_norm;
The offsets and orientations pass the same value to each vertex within an instance, but then pass the next value in the buffer to the vertices of the next instance. Passed as:
in vec3 in_offset;
in mat3 in_orientation;
The single color is passed to every vertex of every instance.
If we had stored the color with /v
or /i
, then we would have had to
store duplicate identical color values in vbo_colors - one per instance or
one per vertex. To render all our cubes in a single color, this is needless
duplication. Using /r
, only one color is require the buffer, and it is
passed to every vertex of every instance for the whole render call:
in vec3 in_color;
An alternative approach would be to pass in the color as a uniform, since it is constant. But doing it as an attribute is more flexible. It allows us to reuse the same shader program, bound to a different buffer, to pass in color data which varies per instance, or per vertex.
Techniques#
Headless on Ubuntu 18 Server#
Dependencies#
Headless rendering can be achieved with EGL or X11. We’ll cover both cases.
Starting with fresh ubuntu 18 server install we need to install required packages:
sudo apt-install python3-pip mesa-utils libegl1-mesa xvfb
This should install mesa an diagnostic tools if needed later.
mesa-utils
installs libgl1-mesa and tools likeglxinfo`
libegl1-mesa
is optional if using EGL instead of X11
Creating a context#
The libraries we are going to interact with has the following locations:
/usr/lib/x86_64-linux-gnu/libGL.so.1
/usr/lib/x86_64-linux-gnu/libX11.so.6
/usr/lib/x86_64-linux-gnu/libEGL.so.1
Double check that you have these libraries installed. ModernGL
through the glcontext library will use ctype.find_library
to locate the latest installed version.
Before we can create a context we to run a virtual display:
export DISPLAY=:99.0
Xvfb :99 -screen 0 640x480x24 &
Now we can create a context with x11 or egl:
# X11
import moderngl
ctx = moderngl.create_context(
standalone=True,
# These are OPTIONAL if you want to load a specific version
libgl='libGL.so.1',
libx11='libX11.so.6',
)
# EGL
import moderngl
ctx = moderngl.create_context(
standalone=True,
backend='egl',
# These are OPTIONAL if you want to load a specific version
libgl='libGL.so.1',
libegl='libEGL.so.1',
)
Running an example#
Checking that everything works can be done with a basic triangle example.
Install dependencies:
pip3 install moderngl numpy pyrr pillow
The following example renders a triangle and writes it to a png file so we can verify the contents.

import moderngl
import numpy as np
from PIL import Image
from pyrr import Matrix44
# -------------------
# CREATE CONTEXT HERE
# -------------------
prog = ctx.program(vertex_shader="""
#version 330
uniform mat4 model;
in vec2 in_vert;
in vec3 in_color;
out vec3 color;
void main() {
gl_Position = model * vec4(in_vert, 0.0, 1.0);
color = in_color;
}
""",
fragment_shader="""
#version 330
in vec3 color;
out vec4 fragColor;
void main() {
fragColor = vec4(color, 1.0);
}
""")
vertices = np.array([
-0.6, -0.6,
1.0, 0.0, 0.0,
0.6, -0.6,
0.0, 1.0, 0.0,
0.0, 0.6,
0.0, 0.0, 1.0,
], dtype='f4')
vbo = ctx.buffer(vertices)
vao = ctx.simple_vertex_array(prog, vbo, 'in_vert', 'in_color')
fbo = ctx.framebuffer(color_attachments=[ctx.texture((512, 512), 4)])
fbo.use()
ctx.clear()
prog['model'].write(Matrix44.from_eulers((0.0, 0.1, 0.0), dtype='f4'))
vao.render(moderngl.TRIANGLES)
data = fbo.read(components=3)
image = Image.frombytes('RGB', fbo.size, data)
image = image.transpose(Image.FLIP_TOP_BOTTOM)
image.save('output.png')
Reference#
moderngl#
Attributes#
Attributes available in the root moderngl
module.
Some may be listed in their original sub-module,
but they are imported during initialization.
Context Flags#
Also available in the Context
instance
including mode details.
- moderngl.NOTHING: moderngl.Constant#
Represents no states. Can be used with
Context.enable_only()
to disable all states.
- moderngl.BLEND: moderngl.Constant#
Enable/disable blending
- moderngl.DEPTH_TEST: moderngl.Constant#
Enable/disable depth testing
- moderngl.CULL_FACE: moderngl.Constant#
Enable/disable face culling
- moderngl.RASTERIZER_DISCARD: moderngl.Constant#
Enable/disable rasterization
- moderngl.PROGRAM_POINT_SIZE: moderngl.Constant#
Enables
gl_PointSize
in vertex or geometry shaders.When enabled we can write to
gl_PointSize
in the vertex shader to specify the point size for each individual point.If this value is not set in the shader the behavior is undefined. This means the points may or may not appear depending if the drivers enforce some default value for
gl_PointSize
.When disabled
Context.point_size
is used.- Type
Context flag
Primitive Modes#
Also available in the Context
instance
including mode details.
- moderngl.POINTS: moderngl.Constant#
Each vertex represents a point
- moderngl.LINES: moderngl.Constant#
Vertices 0 and 1 are considered a line. Vertices 2 and 3 are considered a line. And so on. If the user specifies a non-even number of vertices, then the extra vertex is ignored.
- moderngl.LINE_LOOP: moderngl.Constant#
As line strips, except that the first and last vertices are also used as a line. Thus, you get n lines for n input vertices. If the user only specifies 1 vertex, the drawing command is ignored. The line between the first and last vertices happens after all of the previous lines in the sequence.
- moderngl.LINE_STRIP: moderngl.Constant#
The adjacent vertices are considered lines. Thus, if you pass n vertices, you will get n-1 lines. If the user only specifies 1 vertex, the drawing command is ignored.
- moderngl.TRIANGLES: moderngl.Constant#
Vertices 0, 1, and 2 form a triangle. Vertices 3, 4, and 5 form a triangle. And so on.
- moderngl.TRIANGLE_STRIP: moderngl.Constant#
Every group of 3 adjacent vertices forms a triangle. The face direction of the strip is determined by the winding of the first triangle. Each successive triangle will have its effective face order reversed, so the system compensates for that by testing it in the opposite way. A vertex stream of n length will generate n-2 triangles.
- moderngl.TRIANGLE_FAN: moderngl.Constant#
The first vertex is always held fixed. From there on, every group of 2 adjacent vertices form a triangle with the first. So with a vertex stream, you get a list of triangles like so: (0, 1, 2) (0, 2, 3), (0, 3, 4), etc. A vertex stream of n length will generate n-2 triangles.
- moderngl.LINES_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- moderngl.LINE_STRIP_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- moderngl.TRIANGLES_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- moderngl.TRIANGLE_STRIP_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- moderngl.PATCHES: moderngl.Constant#
primitive type can only be used when Tessellation is active. It is a primitive with a user-defined number of vertices, which is then tessellated based on the control and evaluation shaders into regular points, lines, or triangles, depending on the TES’s settings.
Texture Filters#
Also available in the Context
instance
including mode details.
- moderngl.NEAREST: moderngl.Constant#
Returns the value of the texture element that is nearest (in Manhattan distance) to the specified texture coordinates.
- moderngl.LINEAR: moderngl.Constant#
Returns the weighted average of the four texture elements that are closest to the specified texture coordinates. These can include items wrapped or repeated from other parts of a texture, depending on the values of texture repeat mode, and on the exact mapping.
- moderngl.NEAREST_MIPMAP_NEAREST: moderngl.Constant#
Chooses the mipmap that most closely matches the size of the pixel being textured and uses the
NEAREST`
criterion (the texture element closest to the specified texture coordinates) to produce a texture value.
- moderngl.LINEAR_MIPMAP_NEAREST: moderngl.Constant#
Chooses the mipmap that most closely matches the size of the pixel being textured and uses the
LINEAR
criterion (a weighted average of the four texture elements that are closest to the specified texture coordinates) to produce a texture value.
- moderngl.NEAREST_MIPMAP_LINEAR: moderngl.Constant#
Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the
NEAREST
criterion (the texture element closest to the specified texture coordinates ) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.
- moderngl.LINEAR_MIPMAP_LINEAR: moderngl.Constant#
Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the
LINEAR
criterion (a weighted average of the texture elements that are closest to the specified texture coordinates) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.
Blend Functions#
Also available in the Context
instance
including mode details.
- moderngl.ZERO: moderngl.Constant#
(0,0,0,0)
- moderngl.ONE: moderngl.Constant#
(1,1,1,1)
- moderngl.SRC_COLOR: moderngl.Constant#
(Rs0/kR,Gs0/kG,Bs0/kB,As0/kA)
- moderngl.ONE_MINUS_SRC_COLOR: moderngl.Constant#
(1,1,1,1) - (Rs0/kR,Gs0/kG,Bs0/kB,As0/kA)
- moderngl.SRC_ALPHA: moderngl.Constant#
(As0/kA,As0/kA,As0/kA,As0/kA)
- moderngl.ONE_MINUS_SRC_ALPHA: moderngl.Constant#
(1,1,1,1) - (As0/kA,As0/kA,As0/kA,As0/kA)
- moderngl.DST_ALPHA: moderngl.Constant#
(Ad/kA,Ad/kA,Ad/kA,Ad/kA)
- moderngl.ONE_MINUS_DST_ALPHA: moderngl.Constant#
(1,1,1,1) - (Ad/kA,Ad/kA,Ad/kA,Ad/kA)
- moderngl.DST_COLOR: moderngl.Constant#
(Rd/kR,Gd/kG,Bd/kB,Ad/kA)
- moderngl.ONE_MINUS_DST_COLOR: moderngl.Constant#
(1,1,1,1) - (Rd/kR,Gd/kG,Bd/kB,Ad/kA)
Shortcuts#
- moderngl.DEFAULT_BLENDING: moderngl.Constant#
Shotcut for the default blending
SRC_ALPHA, ONE_MINUS_SRC_ALPHA
- moderngl.ADDITIVE_BLENDING: moderngl.Constant#
Shotcut for additive blending
ONE, ONE
- moderngl.PREMULTIPLIED_ALPHA: moderngl.Constant#
Shotcut for blend mode when using premultiplied alpha
SRC_ALPHA, ONE
Blend Equations#
Also available in the Context
instance
including mode details.
- moderngl.FUNC_ADD: moderngl.Constant#
source + destination
- moderngl.FUNC_SUBTRACT: moderngl.Constant#
source - destination
- moderngl.FUNC_REVERSE_SUBTRACT: moderngl.Constant#
destination - source
- moderngl.MIN: moderngl.Constant#
Minimum of source and destination
- moderngl.MAX: moderngl.Constant#
Maximum of source and destination
Provoking Vertex#
Also available in the Context
instance
including mode details.
- moderngl.FIRST_VERTEX_CONVENTION: moderngl.Constant#
Specifies the first vertex should be used as the source of data for flat shaded varyings. Used with
Context.provoking_vertex
.
- moderngl.LAST_VERTEX_CONVENTION: moderngl.Constant#
Specifies the last vertex should be used as the source of data for flat shaded varyings. Used with
Context.provoking_vertex
.
Functions#
Also see Context
.
- moderngl.create_context(require: Optional[int] = None, standalone: bool = False, share: bool = False, **settings: Dict[str, Any]) moderngl.Context
Create a ModernGL context by loading OpenGL functions from an existing OpenGL context. An OpenGL context must exists.
Example:
# Accept the current context version ctx = moderngl.create_context() # Require at least OpenGL 4.3 ctx = moderngl.create_context(require=430) # Create a headless context requiring OpenGL 4.3 ctx = moderngl.create_context(require=430, standalone=True)
- Keyword Arguments
require (int) – OpenGL version code (default: 330)
standalone (bool) – Headless flag
share (bool) – Attempt to create a shared context
**settings – Other backend specific settings
- Returns
Context
object
- moderngl.create_standalone_context(require: Optional[int] = None, share: bool = False, **settings: Dict[str, Any]) moderngl.Context
Create a standalone/headless ModernGL context.
The preferred way of making a context is through
moderngl.create_context()
.Example:
# Create a context with highest possible supported version ctx = moderngl.create_context() # Require at least OpenGL 4.3 ctx = moderngl.create_context(require=430)
- Keyword Arguments
require (int) – OpenGL version code.
share (bool) – Attempt to create a shared context
settings – keyword config values for the context backend
- Returns
Context
object
- moderngl.detect_format(program: moderngl.Program, attributes: Any, mode: str = 'mgl') str
Detect format for vertex attributes.
The format returned does not contain padding.
- Parameters
program (Program) – The program.
attributes (list) – A list of attribute names.
- Returns
str
Context#
- class moderngl.Context#
Class exposing OpenGL features.
ModernGL objects can be created from this class.
Create#
- moderngl.create_context(require: Optional[int] = None, standalone: bool = False, share: bool = False, **settings: Dict[str, Any]) moderngl.Context #
Create a ModernGL context by loading OpenGL functions from an existing OpenGL context. An OpenGL context must exists.
Example:
# Accept the current context version ctx = moderngl.create_context() # Require at least OpenGL 4.3 ctx = moderngl.create_context(require=430) # Create a headless context requiring OpenGL 4.3 ctx = moderngl.create_context(require=430, standalone=True)
- Keyword Arguments
require (int) – OpenGL version code (default: 330)
standalone (bool) – Headless flag
share (bool) – Attempt to create a shared context
**settings – Other backend specific settings
- Returns
Context
object
- moderngl.create_standalone_context(require: Optional[int] = None, share: bool = False, **settings: Dict[str, Any]) moderngl.Context #
Create a standalone/headless ModernGL context.
The preferred way of making a context is through
moderngl.create_context()
.Example:
# Create a context with highest possible supported version ctx = moderngl.create_context() # Require at least OpenGL 4.3 ctx = moderngl.create_context(require=430)
- Keyword Arguments
require (int) – OpenGL version code.
share (bool) – Attempt to create a shared context
settings – keyword config values for the context backend
- Returns
Context
object
ModernGL Objects#
- Context.program(*, vertex_shader: str, fragment_shader: Optional[str] = None, geometry_shader: Optional[str] = None, tess_control_shader: Optional[str] = None, tess_evaluation_shader: Optional[str] = None, varyings: Tuple[str, ...] = (), fragment_outputs: Optional[Dict[str, int]] = None, varyings_capture_mode: str = 'interleaved') moderngl.Program #
Create a
Program
object.The
varyings
are only used when a transform program is created to specify the names of the output varyings to capture in the output buffer.fragment_outputs
can be used to programmatically map named fragment shader outputs to a framebuffer attachment numbers. This can also be done by usinglayout(location=N)
in the fragment shader.- Parameters
vertex_shader (str) – The vertex shader source.
fragment_shader (str) – The fragment shader source.
geometry_shader (str) – The geometry shader source.
tess_control_shader (str) – The tessellation control shader source.
tess_evaluation_shader (str) – The tessellation evaluation shader source.
varyings (list) – A list of varyings.
fragment_outputs (dict) – A dictionary of fragment outputs.
- Returns
Program
object
- Context.simple_vertex_array(program: moderngl.Program, buffer: moderngl.Buffer, *attributes: Union[List[str], Tuple[str, ...]], index_buffer: Optional[moderngl.Buffer] = None, index_element_size: int = 4, mode: Optional[int] = None) moderngl.VertexArray #
Create a
VertexArray
object.Warning
This method is deprecated and may be removed in the future. Use
Context.vertex_array()
instead. It also supports the argument format this method describes.- Parameters
- Keyword Arguments
index_element_size (int) – byte size of each index element, 1, 2 or 4.
index_buffer (Buffer) – An index buffer.
mode (int) – The default draw mode (for example:
TRIANGLES
)
- Returns
VertexArray
object
- Context.vertex_array(*args, **kwargs) moderngl.VertexArray #
Create a
VertexArray
object.The vertex array describes how buffers are read by a shader program. We need to supply buffer formats and attributes names. The attribute names are defined by the user in the glsl code and can be anything.
Examples:
# Empty vertext array (no attribute input) vao = ctx.vertex_array(program) # Simple version with a single buffer vao = ctx.vertex_array(program, buffer, 'in_position', 'in_normal') vao = ctx.vertex_array(program, buffer, 'in_position', 'in_normal', index_buffer=ibo) # Multiple buffers vao = ctx.vertex_array(program, [ (buffer1, '3f', 'in_position'), (buffer2, '3f', 'in_normal'), ]) vao = ctx.vertex_array(program, [ (buffer1, '3f', 'in_position'), (buffer2, '3f', 'in_normal'), ], index_buffer=ibo, index_element_size=2, # 16 bit / 'u2' index buffer )
This method also supports arguments for
Context.simple_vertex_array()
.- Parameters
program (Program) – The program used when rendering
content (list) – A list of (buffer, format, attributes). See Buffer Format.
- Keyword Arguments
index_buffer (Buffer) – An index buffer (optional)
index_element_size (int) – byte size of each index element, 1, 2 or 4.
skip_errors (bool) – Ignore errors during creation
mode (int) – The default draw mode (for example:
TRIANGLES
)
- Returns
VertexArray
object
- Context.buffer(data: Optional[Any] = None, *, reserve: int = 0, dynamic: bool = False) moderngl.Buffer #
Create a
Buffer
object.- 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
object
- Context.texture(size: Tuple[int, int], components: int, data: Optional[Any] = None, *, samples: int = 0, alignment: int = 1, dtype: str = 'f1', internal_format: Optional[int] = None) moderngl.Texture #
Create a
Texture
object.Warning
Do not play with
internal_format
unless you know exactly you are doing. This is an override to support sRGB and compressed textures if needed.- 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.
dtype (str) – Data type.
internal_format (int) – Override the internalformat of the texture (IF needed)
- Returns
Texture
object
- Context.depth_texture(size: Tuple[int, int], data: Optional[Any] = None, *, samples: int = 0, alignment: int = 4) moderngl.Texture #
Create a
Texture
object.- 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
Texture
object
- Context.texture3d(size: Tuple[int, int, int], components: int, data: Optional[Any] = None, *, alignment: int = 1, dtype: str = 'f1') moderngl.Texture3D #
Create a
Texture3D
object.- 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.
dtype (str) – Data type.
- Returns
Texture3D
object
- Context.texture_array(size: Tuple[int, int, int], components: int, data: Optional[Any] = None, *, alignment: int = 1, dtype: str = 'f1') moderngl.TextureArray #
Create a
TextureArray
object.- Parameters
size (tuple) – The
(width, height, layers)
of the texture.components (int) – The number of components 1, 2, 3 or 4.
data (bytes) – Content of the texture. The size must be
(width, height * layers)
so each layer is stacked vertically.
- Keyword Arguments
alignment (int) – The byte alignment 1, 2, 4 or 8.
dtype (str) – Data type.
- Returns
Texture3D
object
- Context.texture_cube(size: Tuple[int, int], components: int, data: Optional[Any] = None, *, alignment: int = 1, dtype: str = 'f1', internal_format: Optional[int] = None) moderngl.TextureCube #
Create a
TextureCube
object.Note that the width and height of the cubemap must be the same unless you are using a non-standard extension.
- Parameters
size (tuple) – The width, height of the texture. Each side of the cube will have this size.
components (int) – The number of components 1, 2, 3 or 4.
data (bytes) – Content of the texture. The data should be have the following ordering: positive_x, negative_x, positive_y, negative_y, positive_z, negative_z
- Keyword Arguments
alignment (int) – The byte alignment 1, 2, 4 or 8.
dtype (str) – Data type.
internal_format (int) – Override the internalformat of the texture (IF needed)
- Returns
TextureCube
object
- Context.external_texture(glo: int, size: Tuple[int, int], components: int, samples: int, dtype: str) moderngl.Texture #
Create a
Texture
object from an existing OpenGL texture object.- Parameters
glo (int) – External OpenGL texture object.
size (tuple) – The width and height of the texture.
components (int) – The number of components 1, 2, 3 or 4.
samples (int) – The number of samples. Value 0 means no multisample format.
dtype (str) – Data type.
- Context.simple_framebuffer(size: Tuple[int, int], components: int = 4, *, samples: int = 0, dtype: str = 'f1') moderngl.Framebuffer #
Creates a
Framebuffer
with a single color attachment and depth buffer usingmoderngl.Renderbuffer
attachments.- 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.
dtype (str) – Data type.
- Returns
Framebuffer
object
- Context.framebuffer(color_attachments: Any = (), depth_attachment: Optional[Union[moderngl.Texture, moderngl.Renderbuffer]] = None) moderngl.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
orRenderbuffer
objects.depth_attachment (Renderbuffer or Texture) – The depth attachment.
- Returns
Framebuffer
object
- Context.renderbuffer(size: Tuple[int, int], components: int = 4, *, samples: int = 0, dtype: str = 'f1') moderngl.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.
dtype (str) – Data type.
- Returns
Renderbuffer
object
- Context.depth_renderbuffer(size: Tuple[int, int], *, samples: int = 0) moderngl.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
Renderbuffer
object
- Context.scope(framebuffer: Optional[moderngl.Framebuffer] = None, enable_only: Optional[int] = None, *, textures: Tuple[Tuple[moderngl.Texture, int], ...] = (), uniform_buffers: Tuple[Tuple[moderngl.Buffer, int], ...] = (), storage_buffers: Tuple[Tuple[moderngl.Buffer, int], ...] = (), samplers: Tuple[Tuple[moderngl.Sampler, int], ...] = (), enable: Optional[int] = None) moderngl.Scope #
Create a
Scope
object.- Parameters
framebuffer (Framebuffer) – The framebuffer to use when entering.
enable_only (int) – The enable_only flags to set when entering.
- Keyword Arguments
textures (tuple) – List of (texture, binding) tuples.
uniform_buffers (tuple) – Tuple of (buffer, binding) tuples.
storage_buffers (tuple) – Tuple of (buffer, binding) tuples.
samplers (tuple) – Tuple of sampler bindings
enable (int) – Flags to enable for this vao such as depth testing and blending
- Context.query(*, samples: bool = False, any_samples: bool = False, time: bool = False, primitives: bool = False) moderngl.Query #
Create a
Query
object.- Keyword Arguments
samples (bool) – Query
GL_SAMPLES_PASSED
or not.any_samples (bool) – Query
GL_ANY_SAMPLES_PASSED
or not.time (bool) – Query
GL_TIME_ELAPSED
or not.primitives (bool) – Query
GL_PRIMITIVES_GENERATED
or not.
- Context.compute_shader(source: str) moderngl.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
ComputeShader
object
- Context.sampler(repeat_x: bool = True, repeat_y: bool = True, repeat_z: bool = True, filter: Optional[Tuple[int, int]] = None, anisotropy: float = 1.0, compare_func: str = '?', border_color: Optional[Tuple[float, float, float, float]] = None, min_lod: float = - 1000.0, max_lod: float = 1000.0, texture: Optional[moderngl.Texture] = None) moderngl.Sampler #
Create a
Sampler
object.- Keyword Arguments
repeat_x (bool) – Repeat texture on x
repeat_y (bool) – Repeat texture on y
repeat_z (bool) – Repeat texture on z
filter (tuple) – The min and max filter
anisotropy (float) – Number of samples for anisotropic filtering. Any value greater than 1.0 counts as a use of anisotropic filtering
compare_func – Compare function for depth textures
border_color (tuple) – The (r, g, b, a) color for the texture border. When this value is set the
repeat_
values are overridden setting the texture wrap to return the border color when outside[0, 1]
range.min_lod (float) – Minimum level-of-detail parameter (Default
-1000.0
). This floating-point value limits the selection of highest resolution mipmap (lowest mipmap level)max_lod (float) – Minimum level-of-detail parameter (Default
1000.0
). This floating-point value limits the selection of the lowest resolution mipmap (highest mipmap level)texture (Texture) – The texture for this sampler
- Context.clear_samplers(start: int = 0, end: int = - 1) None #
Unbinds samplers from texture units.
Sampler bindings do clear automatically between every frame, but lingering samplers can still be a source of weird bugs during the frame rendering. This methods provides a fairly brute force and efficient way to ensure texture units are clear.
- Keyword Arguments
start (int) – The texture unit index to start the clearing samplers
stop (int) – The texture unit index to stop clearing samplers
Example:
# Clear texture unit 0, 1, 2, 3, 4 ctx.clear_samplers(start=0, end=5) # Clear texture unit 4, 5, 6, 7 ctx.clear_samplers(start=4, end=8)
- Context.release() None #
Release the ModernGL context.
If the context is not standalone the standard backends in
glcontext
will not do anything because the context was not created by moderngl.Standalone contexts can normally be released.
Methods#
- Context.clear(red: float = 0.0, green: float = 0.0, blue: float = 0.0, alpha: float = 0.0, depth: float = 1.0, *, viewport: Optional[Union[Tuple[int, int], Tuple[int, int, int, int]]] = None, color: Optional[Tuple[float, float, float, float]] = None) None #
Clear the bound framebuffer.
If a viewport passed in, a scissor test will be used to clear the given viewport. This viewport take prescense over the framebuffers
scissor
. Clearing can still be done with scissor if no viewport is passed in.This method also respects the
color_mask
anddepth_mask
. It can for example be used to only clear the depth or color buffer or specific components in the color buffer.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.
depth (float) – depth value.
- Keyword Arguments
viewport (tuple) – The viewport.
color (tuple) – Optional rgba color tuple
- Context.enable_only(flags: int) None #
Clears all existing flags applying new ones.
Note that the enum values defined in moderngl are not the same as the ones in opengl. These are defined as bit flags so we can logical or them together.
Available flags:
Examples:
# Disable all flags ctx.enable_only(moderngl.NOTHING) # Ensure only depth testing and face culling is enabled ctx.enable_only(moderngl.DEPTH_TEST | moderngl.CULL_FACE)
- Parameters
flags (EnableFlag) – The flags to enable
- Context.enable(flags: int) None #
Enable flags.
Note that the enum values defined in moderngl are not the same as the ones in opengl. These are defined as bit flags so we can logical or them together.
For valid flags, please see
enable_only()
.Examples:
# Enable a single flag ctx.enable(moderngl.DEPTH_TEST) # Enable multiple flags ctx.enable(moderngl.DEPTH_TEST | moderngl.CULL_FACE | moderngl.BLEND)
- Parameters
flag (int) – The flags to enable.
- Context.disable(flags: int) None #
Disable flags.
For valid flags, please see
enable_only()
.Examples:
# Only disable depth testing ctx.disable(moderngl.DEPTH_TEST) # Disable depth testing and face culling ctx.disable(moderngl.DEPTH_TEST | moderngl.CULL_FACE)
- Parameters
flag (int) – The flags to disable.
- Context.enable_direct(enum: int) None #
Gives direct access to
glEnable
so unsupported capabilities in ModernGL can be enabled.Do not use this to set already supported context flags.
Example:
# Enum value from the opengl registry GL_CONSERVATIVE_RASTERIZATION_NV = 0x9346 ctx.enable_direct(GL_CONSERVATIVE_RASTERIZATION_NV)
- Context.disable_direct(enum: int) None #
Gives direct access to
glDisable
so unsupported capabilities in ModernGL can be disabled.Do not use this to set already supported context flags.
Example:
# Enum value from the opengl registry GL_CONSERVATIVE_RASTERIZATION_NV = 0x9346 ctx.disable_direct(GL_CONSERVATIVE_RASTERIZATION_NV)
- Context.finish() None #
Wait for all drawing commands to finish.
- Context.copy_buffer(dst: moderngl.Buffer, src: moderngl.Buffer, size: int = - 1, *, read_offset: int = 0, write_offset: int = 0) None #
Copy buffer content.
- Context.copy_framebuffer(dst: Union[moderngl.Framebuffer, moderngl.Texture], src: moderngl.Framebuffer) None #
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.
- Context.detect_framebuffer(glo: Optional[int] = None) moderngl.Framebuffer #
Detect a framebuffer.
This is already done when creating a context, but if the underlying window library for some changes the default framebuffer during the lifetime of the application this might be necessary.
- Parameters
glo (int) – Framebuffer object.
- Returns
Framebuffer
object
- Context.gc() int #
Deletes OpenGL objects.
This method must be called to garbage collect OpenGL resources when
gc_mode
is'context_gc'`
.Calling this method with any other
gc_mode
configuration has no effect and is perfectly safe.- Returns
Number of objects deleted
- Return type
int
- Context.__enter__()#
Enters the context.
This should ideally be used with the
with
statement:with other_context as ctx: # Do something in this context
When exiting the context the previously bound context is activated again.
Warning
Context switching can be risky unless you know what you are doing. Use with care.
- Context.__exit__(exc_type, exc_val, exc_tb)#
Exit the context.
Attributes#
- Context.gc_mode: str#
The garbage collection mode.
The default mode is
None
meaning no automatic garbage collection is done. Other modes areauto
andcontext_gc
. Please see documentation for the appropriate configuration.Examples:
# Disable automatic garbage collection. # Each objects needs to be explicitly released. ctx.gc_mode = None # Collect all dead objects in the context and # release them by calling Context.gc() ctx.gc_mode = 'context_gc' ctx.gc() # Deletes the collected objects # Enable automatic garbage collection like # we normally expect in python. ctx.gc_mode = 'auto'
- Type
Optional[str]
- Context.objects: Deque[Any]#
Moderngl objects scheduled for deletion.
These are deleted when calling
Context.gc()
.
- Context.line_width: float#
Set the default line width.
Warning
A line width other than 1.0 is not guaranteed to work across different OpenGL implementations. For wide lines you should be using geometry shaders.
- Type
float
- Context.point_size: float#
Set/get the point size.
Point size changes the pixel size of rendered points. The min and max values are limited by
POINT_SIZE_RANGE
. This value usually at least(1, 100)
, but this depends on the drivers/vendors.If variable point size is needed you can enable
PROGRAM_POINT_SIZE
and write togl_PointSize
in the vertex or geometry shader.Note
Using a geometry shader to create triangle strips from points is often a safer way to render large points since you don’t have have any size restrictions.
- Type
float
- Context.depth_func: str#
Set the default depth func.
Example:
ctx.depth_func = '<=' # GL_LEQUAL ctx.depth_func = '<' # GL_LESS ctx.depth_func = '>=' # GL_GEQUAL ctx.depth_func = '>' # GL_GREATER ctx.depth_func = '==' # GL_EQUAL ctx.depth_func = '!=' # GL_NOTEQUAL ctx.depth_func = '0' # GL_NEVER ctx.depth_func = '1' # GL_ALWAYS
- Type
str
- Context.blend_func: Tuple[int, int]#
Set the blend func (write only).
Blend func can be set for rgb and alpha separately if needed.
Supported blend functions are:
moderngl.ZERO moderngl.ONE moderngl.SRC_COLOR moderngl.ONE_MINUS_SRC_COLOR moderngl.DST_COLOR moderngl.ONE_MINUS_DST_COLOR moderngl.SRC_ALPHA moderngl.ONE_MINUS_SRC_ALPHA moderngl.DST_ALPHA moderngl.ONE_MINUS_DST_ALPHA # Shortcuts moderngl.DEFAULT_BLENDING # (SRC_ALPHA, ONE_MINUS_SRC_ALPHA) moderngl.ADDITIVE_BLENDING # (ONE, ONE) moderngl.PREMULTIPLIED_ALPHA # (SRC_ALPHA, ONE)
Example:
# For both rgb and alpha ctx.blend_func = moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA # Separate for rgb and alpha ctx.blend_func = ( moderngl.SRC_ALPHA, moderngl.ONE_MINUS_SRC_ALPHA, moderngl.ONE, moderngl.ONE )
- Type
tuple
- Context.blend_equation: Tuple[int, int]#
Set the blend equation (write only).
Blend equations specify how source and destination colors are combined in blending operations. By default
FUNC_ADD
is used.Blend equation can be set for rgb and alpha separately if needed.
Supported functions are:
moderngl.FUNC_ADD # source + destination moderngl.FUNC_SUBTRACT # source - destination moderngl.FUNC_REVERSE_SUBTRACT # destination - source moderngl.MIN # Minimum of source and destination moderngl.MAX # Maximum of source and destination
Example:
# For both rgb and alpha channel ctx.blend_equation = moderngl.FUNC_ADD # Separate for rgb and alpha channel ctx.blend_equation = moderngl.FUNC_ADD, moderngl.MAX
- Type
tuple
- Context.viewport: Tuple[int, int, int, int]#
Get or set the viewport of the active framebuffer.
Example:
>>> ctx.viewport (0, 0, 1280, 720) >>> ctx.viewport = (0, 0, 640, 360) >>> ctx.viewport (0, 0, 640, 360)
If no framebuffer is bound
(0, 0, 0, 0)
will be returned.- Type
tuple
- Context.scissor: Optional[Tuple[int, int, int, int]]#
Get or set the scissor box for the active framebuffer.
When scissor testing is enabled fragments outside the defined scissor box will be discarded. This applies to rendered geometry or
Context.clear()
.Setting is value enables scissor testing in the framebuffer. Setting the scissor to
None
disables scissor testing and reverts the scissor box to match the framebuffer size.Example:
# Enable scissor testing >>> ctx.scissor = 100, 100, 200, 100 # Disable scissor testing >>> ctx.scissor = None
If no framebuffer is bound
(0, 0, 0, 0)
will be returned.- Type
tuple
- Context.version_code: int#
The OpenGL version code. Reports
410
for OpenGL 4.1- Type
int
- Context.screen: moderngl.Framebuffer#
A Framebuffer instance representing the screen.
Normally set when creating a context with
create_context()
attaching to an existing context. This is the special system framebuffer represented by framebufferid=0
.When creating a standalone context this property is not set since there are no default framebuffer.
- Type
- Context.fbo: moderngl.Framebuffer#
The active framebuffer. Set every time
Framebuffer.use()
is called.- Type
- Context.front_face: str#
The front_face. Acceptable values are
'ccw'
(default) or'cw'
.Face culling must be enabled for this to have any effect:
ctx.enable(moderngl.CULL_FACE)
.Example:
# Triangles winded counter-clockwise considered front facing ctx.front_face = 'ccw' # Triangles winded clockwise considered front facing ctx.front_face = 'cw'
- Type
str
- Context.cull_face: str#
The face side to cull. Acceptable values are
'back'
(default)'front'
or'front_and_back'
.This is similar to
Context.front_face()
Face culling must be enabled for this to have any effect:
ctx.enable(moderngl.CULL_FACE)
.Example:
ctx.cull_face = 'front' ctx.cull_face = 'back' ctx.cull_face = 'front_and_back'
- Type
str
- Context.wireframe: bool#
Wireframe settings for debugging.
- Type
bool
- Context.max_samples: int#
The maximum supported number of samples for multisampling.
- Type
int
- Context.max_integer_samples: int#
The max integer samples.
- Type
int
- Context.max_texture_units: int#
The max texture units.
- Type
int
- Context.default_texture_unit: int#
The default texture unit.
- Type
int
- Context.max_anisotropy: float#
The maximum value supported for anisotropic filtering.
- Type
float
- Context.multisample: bool#
Enable/disable multisample mode (
GL_MULTISAMPLE
).This property is write only.
Example:
# Enable ctx.multisample = True # Disable ctx.multisample = False
- Type
bool
- Context.patch_vertices: int#
The number of vertices that will be used to make up a single patch primitive.
- Type
int
- Context.provoking_vertex: int#
Specifies the vertex to be used as the source of data for flat shaded varyings.
Flatshading a vertex shader varying output (ie.
flat out vec3 pos
) means to assign all vetices of the primitive the same value for that output. The vertex from which these values is derived is known as the provoking vertex.It can be configured to be the first or the last vertex.
This property is write only.
Example:
# Use first vertex ctx.provoking_vertex = moderngl.FIRST_VERTEX_CONVENTION # Use last vertex ctx.provoking_vertex = moderngl.LAST_VERTEX_CONVENTION
- Type
int
- Context.polygon_offset: Tuple[float, float]#
Get or set the current polygon offset.
The tuple values represents two float values:
unit
and afactor
:ctx.polygon_offset = unit, factor
When drawing polygons, lines or points directly on top of exiting geometry the result is often not visually pleasant. We can experience z-fighting or partially fading fragments due to different primitives not being rasterized in the exact same way or simply depth buffer precision issues.
For example when visualizing polygons drawing a wireframe version on top of the original mesh, these issues are immediately apparent. Applying decals to surfaces is another common example.
The official documentation states the following:
When enabled, the depth value of each fragment is added to a calculated offset value. The offset is added before the depth test is performed and before the depth value is written into the depth buffer. The offset value o is calculated by: o = m * factor + r * units where m is the maximum depth slope of the polygon and r is the smallest value guaranteed to produce a resolvable difference in window coordinate depth values. The value r is an implementation-specific constant.
In simpler terms: We use polygon offset to either add a positive offset to the geometry (push it away from you) or a negative offset to geometry (pull it towards you).
units
is a constant offset to depth and will do the job aloneif we are working with geometry parallel to the near/far plane.
The
factor
helps you handle sloped geometry (not parallel to near/far plane).
In most cases you can get away with
[-1.0, 1.0]
for both factor and units, but definitely play around with the values. When both values are set to0
polygon offset is disabled internally.To just get started with something you can try:
# Either push the geomtry away or pull it towards you # with support for handling small to medium sloped geometry ctx.polygon_offset = 1.0, 1.0 ctx.polygon_offset = -1.0, -1.0 # Disable polygon offset ctx.polygon_offset = 0, 0
- Type
tuple
- Context.error: str#
The result of
glGetError()
but human readable.This values is provided for debug purposes only and is likely to reduce performace when used in a draw loop.
- Type
str
- Context.extensions: Set[str]#
The extensions supported by the context.
All extensions names have a
GL_
prefix, so if the spec refers toARB_compute_shader
we need to look forGL_ARB_compute_shader
:# If compute shaders are supported ... >> 'GL_ARB_compute_shader' in ctx.extensions True
Example data:
{ 'GL_ARB_multi_bind', 'GL_ARB_shader_objects', 'GL_ARB_half_float_vertex', 'GL_ARB_map_buffer_alignment', 'GL_ARB_arrays_of_arrays', 'GL_ARB_pipeline_statistics_query', 'GL_ARB_provoking_vertex', 'GL_ARB_gpu_shader5', 'GL_ARB_uniform_buffer_object', 'GL_EXT_blend_equation_separate', 'GL_ARB_tessellation_shader', 'GL_ARB_multi_draw_indirect', 'GL_ARB_multisample', .. etc .. }
- Type
Set[str]
- Context.info: Dict[str, Any]#
OpenGL Limits and information about the context.
Example:
# The maximum width and height of a texture >> ctx.info['GL_MAX_TEXTURE_SIZE'] 16384 # Vendor and renderer >> ctx.info['GL_VENDOR'] NVIDIA Corporation >> ctx.info['GL_RENDERER'] NVIDIA GeForce GT 650M OpenGL Engine
Example data:
{ 'GL_VENDOR': 'NVIDIA Corporation', 'GL_RENDERER': 'NVIDIA GeForce GT 650M OpenGL Engine', 'GL_VERSION': '4.1 NVIDIA-10.32.0 355.11.10.10.40.102', 'GL_POINT_SIZE_RANGE': (1.0, 2047.0), 'GL_SMOOTH_LINE_WIDTH_RANGE': (0.5, 1.0), 'GL_ALIASED_LINE_WIDTH_RANGE': (1.0, 1.0), 'GL_POINT_FADE_THRESHOLD_SIZE': 1.0, 'GL_POINT_SIZE_GRANULARITY': 0.125, 'GL_SMOOTH_LINE_WIDTH_GRANULARITY': 0.125, 'GL_MIN_PROGRAM_TEXEL_OFFSET': -8.0, 'GL_MAX_PROGRAM_TEXEL_OFFSET': 7.0, 'GL_MINOR_VERSION': 1, 'GL_MAJOR_VERSION': 4, 'GL_SAMPLE_BUFFERS': 0, 'GL_SUBPIXEL_BITS': 8, 'GL_CONTEXT_PROFILE_MASK': 1, 'GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT': 256, 'GL_DOUBLEBUFFER': False, 'GL_STEREO': False, 'GL_MAX_VIEWPORT_DIMS': (16384, 16384), 'GL_MAX_3D_TEXTURE_SIZE': 2048, 'GL_MAX_ARRAY_TEXTURE_LAYERS': 2048, 'GL_MAX_CLIP_DISTANCES': 8, 'GL_MAX_COLOR_ATTACHMENTS': 8, 'GL_MAX_COLOR_TEXTURE_SAMPLES': 8, 'GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS': 233472, 'GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS': 231424, 'GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS': 80, 'GL_MAX_COMBINED_UNIFORM_BLOCKS': 70, 'GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS': 233472, 'GL_MAX_CUBE_MAP_TEXTURE_SIZE': 16384, 'GL_MAX_DEPTH_TEXTURE_SAMPLES': 8, 'GL_MAX_DRAW_BUFFERS': 8, 'GL_MAX_DUAL_SOURCE_DRAW_BUFFERS': 1, 'GL_MAX_ELEMENTS_INDICES': 150000, 'GL_MAX_ELEMENTS_VERTICES': 1048575, 'GL_MAX_FRAGMENT_INPUT_COMPONENTS': 128, 'GL_MAX_FRAGMENT_UNIFORM_COMPONENTS': 4096, 'GL_MAX_FRAGMENT_UNIFORM_VECTORS': 1024, 'GL_MAX_FRAGMENT_UNIFORM_BLOCKS': 14, 'GL_MAX_GEOMETRY_INPUT_COMPONENTS': 128, 'GL_MAX_GEOMETRY_OUTPUT_COMPONENTS': 128, 'GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS': 16, 'GL_MAX_GEOMETRY_UNIFORM_BLOCKS': 14, 'GL_MAX_GEOMETRY_UNIFORM_COMPONENTS': 2048, 'GL_MAX_INTEGER_SAMPLES': 1, 'GL_MAX_SAMPLES': 8, 'GL_MAX_RECTANGLE_TEXTURE_SIZE': 16384, 'GL_MAX_RENDERBUFFER_SIZE': 16384, 'GL_MAX_SAMPLE_MASK_WORDS': 1, 'GL_MAX_SERVER_WAIT_TIMEOUT': -1, 'GL_MAX_TEXTURE_BUFFER_SIZE': 134217728, 'GL_MAX_TEXTURE_IMAGE_UNITS': 16, 'GL_MAX_TEXTURE_LOD_BIAS': 15, 'GL_MAX_TEXTURE_SIZE': 16384, 'GL_MAX_UNIFORM_BUFFER_BINDINGS': 70, 'GL_MAX_UNIFORM_BLOCK_SIZE': 65536, 'GL_MAX_VARYING_COMPONENTS': 0, 'GL_MAX_VARYING_VECTORS': 31, 'GL_MAX_VARYING_FLOATS': 0, 'GL_MAX_VERTEX_ATTRIBS': 16, 'GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS': 16, 'GL_MAX_VERTEX_UNIFORM_COMPONENTS': 4096, 'GL_MAX_VERTEX_UNIFORM_VECTORS': 1024, 'GL_MAX_VERTEX_OUTPUT_COMPONENTS': 128, 'GL_MAX_VERTEX_UNIFORM_BLOCKS': 14, 'GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET': 0, 'GL_MAX_VERTEX_ATTRIB_BINDINGS': 0, 'GL_VIEWPORT_BOUNDS_RANGE': (-32768, 32768), 'GL_VIEWPORT_SUBPIXEL_BITS': 0, 'GL_MAX_VIEWPORTS': 16 }
- Type
dict
- Context.mglo: Any#
Internal representation for debug purposes only.
- Context.extra: Any#
Any - Attribute for storing user defined objects
Context Flags#
Context flags are used to enable or disable states in the context.
These are not the same enum values as in opengl, but are rather
bit flags so we can or
them together setting multiple states
in a simple way.
These values are available in the Context
object and in the
moderngl
module when you don’t have access to the context.
import moderngl
# From moderngl
ctx.enable_only(moderngl.DEPTH_TEST | moderngl.CULL_FACE)
# From context
ctx.enable_only(ctx.DEPTH_TEST | ctx.CULL_FACE)
- Context.NOTHING: moderngl.Constant#
Represents no states. Can be used with
Context.enable_only()
to disable all states.
- Context.BLEND: moderngl.Constant#
Enable/disable blending
- Context.DEPTH_TEST: moderngl.Constant#
Enable/disable depth testing
- Context.CULL_FACE: moderngl.Constant#
Enable/disable face culling
- Context.RASTERIZER_DISCARD: moderngl.Constant#
Enable/disable rasterization
Context flag: Enables
gl_PointSize
in vertex or geometry shaders.When enabled we can write to
gl_PointSize
in the vertex shader to specify the point size for each individual point.If this value is not set in the shader the behavior is undefined. This means the points may or may not appear depending if the drivers enforce some default value for
gl_PointSize
.
- Context.PROGRAM_POINT_SIZE: moderngl.Constant#
When disabled
Context.point_size
is used.
Primitive Modes#
- Context.POINTS: moderngl.Constant#
Each vertex represents a point
- Context.LINES: moderngl.Constant#
Vertices 0 and 1 are considered a line. Vertices 2 and 3 are considered a line. And so on. If the user specifies a non-even number of vertices, then the extra vertex is ignored.
- Context.LINE_LOOP: moderngl.Constant#
As line strips, except that the first and last vertices are also used as a line. Thus, you get n lines for n input vertices. If the user only specifies 1 vertex, the drawing command is ignored. The line between the first and last vertices happens after all of the previous lines in the sequence.
- Context.LINE_STRIP: moderngl.Constant#
The adjacent vertices are considered lines. Thus, if you pass n vertices, you will get n-1 lines. If the user only specifies 1 vertex, the drawing command is ignored.
- Context.TRIANGLES: moderngl.Constant#
Vertices 0, 1, and 2 form a triangle. Vertices 3, 4, and 5 form a triangle. And so on.
- Context.TRIANGLE_STRIP: moderngl.Constant#
Every group of 3 adjacent vertices forms a triangle. The face direction of the strip is determined by the winding of the first triangle. Each successive triangle will have its effective face order reversed, so the system compensates for that by testing it in the opposite way. A vertex stream of n length will generate n-2 triangles.
- Context.TRIANGLE_FAN: moderngl.Constant#
The first vertex is always held fixed. From there on, every group of 2 adjacent vertices form a triangle with the first. So with a vertex stream, you get a list of triangles like so: (0, 1, 2) (0, 2, 3), (0, 3, 4), etc. A vertex stream of n length will generate n-2 triangles.
- Context.LINES_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- Context.LINE_STRIP_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- Context.TRIANGLES_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- Context.TRIANGLE_STRIP_ADJACENCY: moderngl.Constant#
These are special primitives that are expected to be used specifically with geomtry shaders. These primitives give the geometry shader more vertices to work with for each input primitive. Data needs to be duplicated in buffers.
- Context.PATCHES: moderngl.Constant#
primitive type can only be used when Tessellation is active. It is a primitive with a user-defined number of vertices, which is then tessellated based on the control and evaluation shaders into regular points, lines, or triangles, depending on the TES’s settings.
Texture Filters#
Also available in the Context
instance
including mode details.
- Context.NEAREST: moderngl.Constant#
Returns the value of the texture element that is nearest (in Manhattan distance) to the specified texture coordinates.
- Context.LINEAR: moderngl.Constant#
Returns the weighted average of the four texture elements that are closest to the specified texture coordinates. These can include items wrapped or repeated from other parts of a texture, depending on the values of texture repeat mode, and on the exact mapping.
- Context.NEAREST_MIPMAP_NEAREST: moderngl.Constant#
Chooses the mipmap that most closely matches the size of the pixel being textured and uses the
NEAREST
criterion (the texture element closest to the specified texture coordinates) to produce a texture value.
- Context.LINEAR_MIPMAP_NEAREST: moderngl.Constant#
Chooses the mipmap that most closely matches the size of the pixel being textured and uses the
LINEAR
criterion (a weighted average of the four texture elements that are closest to the specified texture coordinates) to produce a texture value.
- Context.NEAREST_MIPMAP_LINEAR: moderngl.Constant#
Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the
NEAREST
criterion (the texture element closest to the specified texture coordinates ) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.
- Context.LINEAR_MIPMAP_LINEAR: moderngl.Constant#
Chooses the two mipmaps that most closely match the size of the pixel being textured and uses the
LINEAR
criterion (a weighted average of the texture elements that are closest to the specified texture coordinates) to produce a texture value from each mipmap. The final texture value is a weighted average of those two values.
Blend Functions#
Blend functions are used with Context.blend_func
to control blending operations.
# Default value
ctx.blend_func = ctx.SRC_ALPHA, ctx.ONE_MINUS_SRC_ALPHA
- Context.ZERO: moderngl.Constant#
(0,0,0,0)
- Context.ONE: moderngl.Constant#
(1,1,1,1)
- Context.SRC_COLOR: moderngl.Constant#
(Rs0/kR,Gs0/kG,Bs0/kB,As0/kA)
- Context.ONE_MINUS_SRC_COLOR: moderngl.Constant#
(1,1,1,1) - (Rs0/kR,Gs0/kG,Bs0/kB,As0/kA)
- Context.SRC_ALPHA: moderngl.Constant#
(As0/kA,As0/kA,As0/kA,As0/kA)
- Context.ONE_MINUS_SRC_ALPHA: moderngl.Constant#
(1,1,1,1) - (As0/kA,As0/kA,As0/kA,As0/kA)
- Context.DST_ALPHA: moderngl.Constant#
(Ad/kA,Ad/kA,Ad/kA,Ad/kA)
- Context.ONE_MINUS_DST_ALPHA: moderngl.Constant#
(1,1,1,1) - (Ad/kA,Ad/kA,Ad/kA,Ad/kA)
- Context.DST_COLOR: moderngl.Constant#
(Rd/kR,Gd/kG,Bd/kB,Ad/kA)
- Context.ONE_MINUS_DST_COLOR: moderngl.Constant#
(1,1,1,1) - (Rd/kR,Gd/kG,Bd/kB,Ad/kA)
Blend Function Shortcuts#
- Context.DEFAULT_BLENDING: moderngl.Constant#
Shotcut for the default blending
SRC_ALPHA, ONE_MINUS_SRC_ALPHA
- Context.ADDITIVE_BLENDING: moderngl.Constant#
Shotcut for additive blending
ONE, ONE
- Context.PREMULTIPLIED_ALPHA: moderngl.Constant#
Shotcut for blend mode when using premultiplied alpha
SRC_ALPHA, ONE
Blend Equations#
Used with Context.blend_equation
.
- Context.FUNC_ADD: moderngl.Constant#
source + destination
- Context.FUNC_SUBTRACT: moderngl.Constant#
source - destination
- Context.FUNC_REVERSE_SUBTRACT: moderngl.Constant#
destination - source
- Context.MIN: moderngl.Constant#
Minimum of source and destination
- Context.MAX: moderngl.Constant#
Maximum of source and destination
Other Enums#
- Context.FIRST_VERTEX_CONVENTION: moderngl.Constant#
Specifies the first vertex should be used as the source of data for flat shaded varyings. Used with
Context.provoking_vertex
.
- Context.LAST_VERTEX_CONVENTION: moderngl.Constant#
Specifies the last vertex should be used as the source of data for flat shaded varyings. Used with
Context.provoking_vertex
.
Examples#
ModernGL Context#
import moderngl
# create a window
ctx = moderngl.create_context()
print(ctx.version_code)
Standalone ModernGL Context#
import moderngl
ctx = moderngl.create_standalone_context()
print(ctx.version_code)
ContextManager#
context_manager.py
1import moderngl
2
3
4class ContextManager:
5 ctx = None
6
7 @staticmethod
8 def get_default_context(allow_fallback_standalone_context=True) -> moderngl.Context:
9 '''
10 Default context
11 '''
12
13 if ContextManager.ctx is None:
14 try:
15 ContextManager.ctx = moderngl.create_context()
16 except:
17 if allow_fallback_standalone_context:
18 ContextManager.ctx = moderngl.create_standalone_context()
19 else:
20 raise
21
22 return ContextManager.ctx
example.py
1from context_manager import ContextManager
2
3ctx = ContextManager.get_default_context()
4print(ctx.version_code)
Buffer#
- class moderngl.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()
.
Create#
- Context.buffer(data: Optional[Any] = None, *, reserve: int = 0, dynamic: bool = False) moderngl.Buffer
Create a
Buffer
object.- 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
object
Methods#
- Buffer.assign(index: int) Tuple[moderngl.Buffer, int] #
Helper method for assigning a buffer.
- Returns
(self, index) tuple
- Buffer.bind(*attribs, layout=None)#
Helper method for binding a buffer.
- Returns
(self, layout, attribs) tuple
- Buffer.write(data: Any, *, offset: int = 0) None #
Write the content.
- Parameters
data (bytes) – The data.
- Keyword Arguments
offset (int) – The offset in bytes.
- Buffer.write_chunks(data: Any, start: int, step: int, count: int) None #
Split data to count equal parts.
Write the chunks using offsets calculated from start, step and stop.
- Parameters
data (bytes) – The data.
start (int) – First offset in bytes.
step (int) – Offset increment in bytes.
count (int) – The number of offsets.
- Buffer.read(size: int = - 1, *, offset: int = 0) bytes #
Read the content.
- Parameters
size (int) – The size in bytes. Value
-1
means all.- Keyword Arguments
offset (int) – The offset in bytes.
- Returns
bytes
- Buffer.read_into(buffer: Any, size: int = - 1, *, offset: int = 0, write_offset: int = 0) None #
Read the content into a buffer.
- Parameters
buffer (bytearray) – The buffer that will receive the content.
size (int) – The size in bytes. Value
-1
means all.
- Keyword Arguments
offset (int) – The read offset in bytes.
write_offset (int) – The write offset in bytes.
- Buffer.read_chunks(chunk_size: int, start: int, step: int, count: int) bytes #
Read the content.
Read and concatenate the chunks of size chunk_size using offsets calculated from start, step and stop.
- Parameters
chunk_size (int) – The chunk size in bytes.
start (int) – First offset in bytes.
step (int) – Offset increment in bytes.
count (int) – The number of offsets.
- Returns
bytes
- Buffer.read_chunks_into(buffer: Any, chunk_size: int, start: int, step: int, count: int, *, write_offset: int = 0) None #
Read the content.
Read and concatenate the chunks of size chunk_size using offsets calculated from start, step and stop.
- Parameters
buffer (bytearray) – The buffer that will receive the content.
chunk_size (int) – The chunk size.
start (int) – First offset.
step (int) – Offset increment.
count (int) – The number of offsets.
- Keyword Arguments
write_offset (int) – The write offset.
- Buffer.clear(size: int = - 1, *, offset: int = 0, chunk: Optional[Any] = None) None #
Clear the content.
- Parameters
size (int) – The size. Value
-1
means all.- Keyword Arguments
offset (int) – The offset.
chunk (bytes) – The chunk to use repeatedly.
- Buffer.bind_to_uniform_block(binding: int = 0, *, offset: int = 0, size: int = - 1) None #
Bind the buffer to a uniform block.
- Parameters
binding (int) – The uniform block binding.
- Keyword Arguments
offset (int) – The offset.
size (int) – The size. Value
-1
means all.
- Buffer.bind_to_storage_buffer(binding: int = 0, *, offset: int = 0, size: int = - 1) None #
Bind the buffer to a shader storage buffer.
- Parameters
binding (int) – The shader storage binding.
- Keyword Arguments
offset (int) – The offset.
size (int) – The size. Value
-1
means all.
- Buffer.orphan(size: int = - 1) None #
Orphan the buffer with the option to specify a new size.
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.
- Keyword Arguments
size (int) – The new byte size if the buffer. If not supplied the buffer size will be unchanged.
Example
# For simplicity the VertexArray creation is omitted >>> vbo = ctx.buffer(reserve=1024) # Fill the buffer >>> vbo.write(some_temporary_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_temporary_data) >>> vao.render(...) # We can also resize the buffer. In this case we double the size >> vbo.orphan(vbo.size * 2)
- Buffer.release() None #
Release the ModernGL object.
Attributes#
- Buffer.size: int#
The size of the buffer in bytes.
- Type
int
- Buffer.dynamic: bool#
Is the buffer created with the dynamic flag?.
- Type
bool
- Buffer.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- Buffer.mglo: Any#
Internal representation for debug purposes only.
- Buffer.extra: Any#
Any - Attribute for storing user defined objects
- Buffer.ctx: moderngl.Context#
The context this object belongs to
VertexArray#
- class moderngl.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.Note
Compared to OpenGL,
VertexArray
objects have some additional responsibilities:Binding a
Program
whenVertexArray.render()
orVertexArray.transform()
is called.Subroutines can be assigned. Please see the example below.
Create#
- Context.simple_vertex_array(program: moderngl.Program, buffer: moderngl.Buffer, *attributes: Union[List[str], Tuple[str, ...]], index_buffer: Optional[moderngl.Buffer] = None, index_element_size: int = 4, mode: Optional[int] = None) moderngl.VertexArray
Create a
VertexArray
object.Warning
This method is deprecated and may be removed in the future. Use
Context.vertex_array()
instead. It also supports the argument format this method describes.- Parameters
- Keyword Arguments
index_element_size (int) – byte size of each index element, 1, 2 or 4.
index_buffer (Buffer) – An index buffer.
mode (int) – The default draw mode (for example:
TRIANGLES
)
- Returns
VertexArray
object
- Context.vertex_array(*args, **kwargs) moderngl.VertexArray
Create a
VertexArray
object.The vertex array describes how buffers are read by a shader program. We need to supply buffer formats and attributes names. The attribute names are defined by the user in the glsl code and can be anything.
Examples:
# Empty vertext array (no attribute input) vao = ctx.vertex_array(program) # Simple version with a single buffer vao = ctx.vertex_array(program, buffer, 'in_position', 'in_normal') vao = ctx.vertex_array(program, buffer, 'in_position', 'in_normal', index_buffer=ibo) # Multiple buffers vao = ctx.vertex_array(program, [ (buffer1, '3f', 'in_position'), (buffer2, '3f', 'in_normal'), ]) vao = ctx.vertex_array(program, [ (buffer1, '3f', 'in_position'), (buffer2, '3f', 'in_normal'), ], index_buffer=ibo, index_element_size=2, # 16 bit / 'u2' index buffer )
This method also supports arguments for
Context.simple_vertex_array()
.- Parameters
program (Program) – The program used when rendering
content (list) – A list of (buffer, format, attributes). See Buffer Format.
- Keyword Arguments
index_buffer (Buffer) – An index buffer (optional)
index_element_size (int) – byte size of each index element, 1, 2 or 4.
skip_errors (bool) – Ignore errors during creation
mode (int) – The default draw mode (for example:
TRIANGLES
)
- Returns
VertexArray
object
Methods#
- VertexArray.render(mode: Optional[int] = None, vertices: int = - 1, *, first: int = 0, instances: int = - 1) None #
The render primitive (mode) must be the same as the input primitive of the GeometryShader.
- Parameters
mode (int) – 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.
- VertexArray.render_indirect(buffer: moderngl.Buffer, mode: Optional[int] = None, count: int = - 1, *, first: int = 0) None #
The render primitive (mode) must be the same as the input primitive of the GeometryShader.
The draw commands are 5 integers: (count, instanceCount, firstIndex, baseVertex, baseInstance).
- VertexArray.transform(buffer: Union[moderngl.Buffer, List[moderngl.Buffer]], mode: Optional[int] = None, vertices: int = - 1, *, first: int = 0, instances: int = - 1, buffer_offset: int = 0) None #
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.
buffer_offset (int) – Byte offset for the output buffer
- VertexArray.bind(attribute: int, cls: str, buffer: moderngl.Buffer, fmt: str, *, offset: int = 0, stride: int = 0, divisor: int = 0, normalize: bool = False) None #
Bind individual attributes to buffers.
- Parameters
location (int) – The attribute location.
cls (str) – The attribute class. Valid values are
f
,i
ord
.buffer (Buffer) – The buffer.
format (str) – The buffer format.
- Keyword Arguments
offset (int) – The offset.
stride (int) – The stride.
divisor (int) – The divisor.
normalize (bool) – The normalize parameter, if applicable.
- VertexArray.release() None #
Release the ModernGL object.
Attributes#
- VertexArray.mode: int#
Get or set the default rendering mode.
This value is used when
mode
is not passed in rendering calls.Examples:
vao.mode = moderngl.TRIANGLE_STRIPS
- Type
int
- VertexArray.program: moderngl.Program#
The program assigned to the VertexArray.
The program used when rendering or transforming primitives.
- Type
- VertexArray.index_buffer: moderngl.Buffer#
The index buffer if the index_buffer is set, otherwise
None
.- Type
- VertexArray.index_element_size: int#
The byte size of each element in the index buffer.
- Type
int
- VertexArray.scope: Optional[moderngl.Scope]#
The scope to use while rendering.
- VertexArray.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.
- Type
int
- VertexArray.instances: int#
Get or set the number of instances to render.
- Type
int
- VertexArray.subroutines: Tuple[int, ...]#
The subroutines assigned to the VertexArray.
The subroutines used when rendering or transforming primitives.
- Type
tuple
- VertexArray.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- VertexArray.mglo: Any#
Internal representation for debug purposes only.
- VertexArray.extra: Any#
Any - Attribute for storing user defined objects
- VertexArray.ctx: moderngl.Context#
The context this object belongs to
Program#
- class moderngl.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.Uniform buffers can be bound using
Buffer.bind_to_uniform_block()
or can be set individually. For more complex binding yielding higher performance consider usingmoderngl.Scope
.
Create#
- Context.program(*, vertex_shader: str, fragment_shader: Optional[str] = None, geometry_shader: Optional[str] = None, tess_control_shader: Optional[str] = None, tess_evaluation_shader: Optional[str] = None, varyings: Tuple[str, ...] = (), fragment_outputs: Optional[Dict[str, int]] = None, varyings_capture_mode: str = 'interleaved') moderngl.Program
Create a
Program
object.The
varyings
are only used when a transform program is created to specify the names of the output varyings to capture in the output buffer.fragment_outputs
can be used to programmatically map named fragment shader outputs to a framebuffer attachment numbers. This can also be done by usinglayout(location=N)
in the fragment shader.- Parameters
vertex_shader (str) – The vertex shader source.
fragment_shader (str) – The fragment shader source.
geometry_shader (str) – The geometry shader source.
tess_control_shader (str) – The tessellation control shader source.
tess_evaluation_shader (str) – The tessellation evaluation shader source.
varyings (list) – A list of varyings.
fragment_outputs (dict) – A dictionary of fragment outputs.
- Returns
Program
object
Methods#
- Program.get(key: str, default: Any) Union[moderngl.Uniform, moderngl.UniformBlock, moderngl.Subroutine, moderngl.Attribute, moderngl.Varying] #
Returns a Uniform, UniformBlock, Subroutine, Attribute or Varying.
- Parameters
default – This is the value to be returned in case key does not exist.
- Returns
- Program.__getitem__(key: str) Union[moderngl.Uniform, moderngl.UniformBlock, moderngl.Subroutine, moderngl.Attribute, moderngl.Varying] #
Get a member such as uniforms, uniform blocks, subroutines, attributes and varyings by name.
# Get a uniform uniform = program['color'] # Uniform values can be set on the returned object # or the `__setitem__` shortcut can be used. program['color'].value = 1.0, 1.0, 1.0, 1.0 # Still when writing byte data we need to use the `write()` method program['color'].write(buffer)
- Program.__setitem__(key: str, value: Any) None #
Set a value of uniform or uniform block.
# Set a vec4 uniform uniform['color'] = 1.0, 1.0, 1.0, 1.0 # Optionally we can store references to a member and set the value directly uniform = program['color'] uniform.value = 1.0, 0.0, 0.0, 0.0 uniform = program['cameraMatrix'] uniform.write(camera_matrix)
- Program.__iter__() Generator[str, None, None] #
Yields the internal members names as strings.
This includes all members such as uniforms, attributes etc.
Example:
# Print member information for name in program: member = program[name] print(name, type(member), member)
Output:
vert <class 'moderngl.program_members.attribute.Attribute'> <Attribute: 0> vert_color <class 'moderngl.program_members.attribute.Attribute'> <Attribute: 1> gl_InstanceID <class 'moderngl.program_members.attribute.Attribute'> <Attribute: -1> rotation <class 'moderngl.program_members.uniform.Uniform'> <Uniform: 0> scale <class 'moderngl.program_members.uniform.Uniform'> <Uniform: 1>
We can filter on member type if needed:
for name in prog: member = prog[name] if isinstance(member, moderngl.Uniform): print('Uniform', name, member)
or a less verbose version using dict comprehensions:
uniforms = {name: self.prog[name] for name in self.prog if isinstance(self.prog[name], moderngl.Uniform)} print(uniforms)
Output:
{'rotation': <Uniform: 0>, 'scale': <Uniform: 1>}
- Program.__eq__(value, /)#
Return self==value.
- Program.release() None #
Release the ModernGL object.
Attributes#
- Program.geometry_input: int#
The geometry input primitive.
The GeometryShader’s input primitive if the GeometryShader exists. The geometry input primitive will be used for validation. (from
layout(input_primitive) in;
)This can only be
POINTS
,LINES
,LINES_ADJACENCY
,TRIANGLES
,TRIANGLE_ADJACENCY
.- Type
int
- Program.geometry_output: int#
The geometry output primitive.
The GeometryShader’s output primitive if the GeometryShader exists. This can only be
POINTS
,LINE_STRIP
andTRIANGLE_STRIP
(fromlayout(output_primitive, max_vertices = vert_count) out;
)- Type
int
- Program.geometry_vertices: int#
The maximum number of vertices that.
the geometry shader will output. (from
layout(output_primitive, max_vertices = vert_count) out;
)- Type
int
- Program.subroutines: Tuple[str, ...]#
The subroutine uniforms.
- Type
tuple
- Program.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- Program.mglo: Any#
Internal representation for debug purposes only.
- Program.extra: Any#
Any - Attribute for storing user defined objects
- Program.is_transform: bool#
If this is a tranform program (no fragment shader).
- Type
bool
- Program.ctx: moderngl.Context#
The context this object belongs to
Examples#
A simple program designed for rendering
1my_render_program = ctx.program(
2 vertex_shader='''
3 #version 330
4
5 in vec2 vert;
6
7 void main() {
8 gl_Position = vec4(vert, 0.0, 1.0);
9 }
10 ''',
11 fragment_shader='''
12 #version 330
13
14 out vec4 color;
15
16 void main() {
17 color = vec4(0.3, 0.5, 1.0, 1.0);
18 }
19 ''',
20)
A simple program designed for transforming
1my_transform_program = ctx.program(
2 vertex_shader='''
3 #version 330
4
5 in vec4 vert;
6 out float vert_length;
7
8 void main() {
9 vert_length = length(vert);
10 }
11 ''',
12 varyings=['vert_length']
13)
Program Members#
Uniform#
- class moderngl.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.__getitem__()
orProgram.__iter__()
Methods#
- Uniform.read() bytes #
Read the value of the uniform.
- Uniform.write(data: Any) None #
Write the value of the uniform.
Attributes#
- Uniform.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.- Type
int
- 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
- Type
int
- Uniform.array_length: int#
The length of the array of the uniform. The array_length is 1 for non array uniforms.
- Type
int
- 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.
- Type
str
- Uniform.value: Any#
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.extra: Any#
Attribute for storing user defined objects
- Uniform.mglo: Any#
Internal moderngl core object
UniformBlock#
- class moderngl.UniformBlock#
Uniform Block metadata
- UniformBlock.binding: int#
The binding of the uniform block.
- Type
int
- UniformBlock.value: int#
The value of the uniform block.
- Type
int
- UniformBlock.name: str#
The name of the uniform block.
- Type
str
- UniformBlock.index: int#
The index of the uniform block.
- Type
int
- UniformBlock.size: int#
The size of the uniform block.
- Type
int
- UniformBlock.extra: Any#
Attribute for storing user defined objects
- UniformBlock.mglo: Any#
Internal moderngl core object
Subroutine#
- class moderngl.Subroutine#
This class represents a program subroutine.
- Subroutine.index: int#
The index of the subroutine.
- Type
int
- Subroutine.name: str#
The name of the subroutine.
- Type
str
- Subroutine.extra: Any#
Attribute for storing user defined objects
Attribute#
- class moderngl.Attribute#
This class represents a program attribute.
- Attribute.location: int#
The location of the attribute.
The result of the glGetAttribLocation.
- Type
int
- Attribute.array_length: int#
If the attribute is an array the array_length.
is the length of the array otherwise 1.
- Type
int
- Attribute.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
- Type
int
- Attribute.shape: int#
The shape is a single character, representing the scalar type of the attribute.
shape
GLSL types
'i'
int
ivec2 ivec3 ivec4
'I'
uint
uvec2 uvec3 uvec4
'f'
float
vec2 vec3 vec4
mat2 mat3 mat4
mat2x3 mat2x4 mat3x4 mat4x2 mat4x2 mat4x3
'd'
double
dvec2 dvec3 dvec4
dmat2 dmat3 dmat4
dmat2x3 dmat2x4 dmat3x4 dmat4x2 dmat4x2 dmat4x3
- Type
str
- 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.- Type
str
- Attribute.extra: Any#
Attribute for storing user defined objects
Varying#
- class moderngl.Varying#
This class represents a program varying.
- Varying.name: str#
The name of the varying.
- Type
str
- Varying.number: int#
The number of the varying.
- Type
int
- Varying.extra: Any#
Attribute for storing user defined objects
Sampler#
- class moderngl.Sampler#
A Sampler Object is an OpenGL Object that stores the sampling parameters for a Texture access inside of a shader.
When a sampler object is bound to a texture image unit, the internal sampling parameters for a texture bound to the same image unit are all ignored. Instead, the sampling parameters are taken from this sampler object.
Unlike textures, a samplers state can also be changed freely be at any time without the sampler object being bound/in use.
Samplers are bound to a texture unit and not a texture itself. Be careful with leaving samplers bound to texture units as it can cause texture incompleteness issues (the texture bind is ignored).
Sampler bindings do clear automatically between every frame so a texture unit need at least one bind/use per frame.
Create#
- Context.sampler(repeat_x: bool = True, repeat_y: bool = True, repeat_z: bool = True, filter: Optional[Tuple[int, int]] = None, anisotropy: float = 1.0, compare_func: str = '?', border_color: Optional[Tuple[float, float, float, float]] = None, min_lod: float = - 1000.0, max_lod: float = 1000.0, texture: Optional[moderngl.Texture] = None) moderngl.Sampler
Create a
Sampler
object.- Keyword Arguments
repeat_x (bool) – Repeat texture on x
repeat_y (bool) – Repeat texture on y
repeat_z (bool) – Repeat texture on z
filter (tuple) – The min and max filter
anisotropy (float) – Number of samples for anisotropic filtering. Any value greater than 1.0 counts as a use of anisotropic filtering
compare_func – Compare function for depth textures
border_color (tuple) – The (r, g, b, a) color for the texture border. When this value is set the
repeat_
values are overridden setting the texture wrap to return the border color when outside[0, 1]
range.min_lod (float) – Minimum level-of-detail parameter (Default
-1000.0
). This floating-point value limits the selection of highest resolution mipmap (lowest mipmap level)max_lod (float) – Minimum level-of-detail parameter (Default
1000.0
). This floating-point value limits the selection of the lowest resolution mipmap (highest mipmap level)texture (Texture) – The texture for this sampler
Methods#
- Sampler.use(location: int = 0) None #
Bind the sampler to a texture unit.
- Parameters
location (int) – The texture unit
- Sampler.clear(location: int = 0) None #
Clear the sampler binding on a texture unit.
- Parameters
location (int) – The texture unit
- Sampler.assign(index: int) Tuple[moderngl.Sampler, int] #
Helper method for assigning samplers to scopes.
Example:
s1 = ctx.sampler(...) s2 = ctx.sampler(...) ctx.scope(samplers=(s1.assign(0), s1.assign(1)), ...)
- Returns
(self, index) tuple
- Sampler.release() None #
Release/destroy the ModernGL object.
Attributes#
- Sampler.texture: Any#
texture
- Sampler.repeat_x: bool#
The x repeat flag for the sampler (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) sampler.repeat_x = True # Disable texture repeat (GL_CLAMP_TO_EDGE) sampler.repeat_x = False
- Type
bool
- Sampler.repeat_y: bool#
The y repeat flag for the sampler (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) sampler.repeat_y = True # Disable texture repeat (GL_CLAMP_TO_EDGE) sampler.repeat_y = False
- Type
bool
- Sampler.repeat_z: bool#
The z repeat flag for the sampler (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) sampler.repeat_z = True # Disable texture repeat (GL_CLAMP_TO_EDGE) sampler.repeat_z = False
- Type
bool
- Sampler.filter: Tuple[int, int]#
The minification and magnification filter for the sampler.
(Default
(moderngl.LINEAR. moderngl.LINEAR)
)Example:
sampler.filter == (moderngl.NEAREST, moderngl.NEAREST) sampler.filter == (moderngl.LINEAR_MIPMAP_LINEAR, moderngl.LINEAR) sampler.filter == (moderngl.NEAREST_MIPMAP_LINEAR, moderngl.NEAREST) sampler.filter == (moderngl.LINEAR_MIPMAP_NEAREST, moderngl.NEAREST)
- Type
tuple
- Sampler.compare_func: str#
The compare function for a depth textures (Default
'?'
).By default samplers don’t have depth comparison mode enabled. This means that depth texture values can be read as a
sampler2D
usingtexture()
in a GLSL shader by default.When setting this property to a valid compare mode,
GL_TEXTURE_COMPARE_MODE
is set toGL_COMPARE_REF_TO_TEXTURE
so that texture lookup functions in GLSL will return a depth comparison result instead of the actual depth value.Accepted compare functions:
.compare_func = '' # Disale depth comparison completely sampler.compare_func = '<=' # GL_LEQUAL sampler.compare_func = '<' # GL_LESS sampler.compare_func = '>=' # GL_GEQUAL sampler.compare_func = '>' # GL_GREATER sampler.compare_func = '==' # GL_EQUAL sampler.compare_func = '!=' # GL_NOTEQUAL sampler.compare_func = '0' # GL_NEVER sampler.compare_func = '1' # GL_ALWAYS
- Type
tuple
- Sampler.anisotropy: float#
Number of samples for anisotropic filtering (Default
1.0
).The value will be clamped in range
1.0
andctx.max_anisotropy
.Any value greater than 1.0 counts as a use of anisotropic filtering:
# Disable anisotropic filtering sampler.anisotropy = 1.0 # Enable anisotropic filtering suggesting 16 samples as a maximum sampler.anisotropy = 16.0
- Type
float
- Sampler.border_color: Tuple[float, float, float, float]#
The (r, g, b, a) color for the texture border (Default
(0.0, 0.0, 0.0, 0.0)
).When setting this value the
repeat_
values are overridden setting the texture wrap to return the border color when outside [0, 1] range.Example:
# Red border color sampler.border_color = (1.0, 0.0, 0.0, 0.0)
- Type
tuple
- Sampler.min_lod: float#
Minimum level-of-detail parameter (Default
-1000.0
).This floating-point value limits the selection of highest resolution mipmap (lowest mipmap level)
- Type
float
- Sampler.max_lod: float#
Minimum level-of-detail parameter (Default
1000.0
).This floating-point value limits the selection of the lowest resolution mipmap (highest mipmap level)
- Type
float
- Sampler.extra: Any#
Any - Attribute for storing user defined objects
- Sampler.mglo: Any#
Internal representation for debug purposes only.
- Sampler.ctx: moderngl.Context#
The context this object belongs to
Texture#
- class moderngl.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.
Create#
- Context.texture(size: Tuple[int, int], components: int, data: Optional[Any] = None, *, samples: int = 0, alignment: int = 1, dtype: str = 'f1', internal_format: Optional[int] = None) moderngl.Texture
Create a
Texture
object.Warning
Do not play with
internal_format
unless you know exactly you are doing. This is an override to support sRGB and compressed textures if needed.- 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.
dtype (str) – Data type.
internal_format (int) – Override the internalformat of the texture (IF needed)
- Returns
Texture
object
- Context.depth_texture(size: Tuple[int, int], data: Optional[Any] = None, *, samples: int = 0, alignment: int = 4) moderngl.Texture
Create a
Texture
object.- 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
Texture
object
Methods#
- Texture.read(*, level: int = 0, alignment: int = 1) bytes #
Read the pixel data as bytes into system memory.
The texture can also be attached to a
Framebuffer
to gain access toFramebuffer.read()
for additional features such ad reading a subsection or converting to anotherdtype
.- Keyword Arguments
level (int) – The mipmap level.
alignment (int) – The byte alignment of the pixels.
- Returns
bytes
- Texture.read_into(buffer: Any, *, level: int = 0, alignment: int = 1, write_offset: int = 0) None #
Read the content of the texture into a bytearray or
Buffer
.The advantage of reading into a
Buffer
is that pixel data does not need to travel all the way to system memory:# Reading pixel data into a bytearray data = bytearray(4) texture = ctx.texture((2, 2), 1) texture.read_into(data) # Reading pixel data into a buffer data = ctx.buffer(reserve=4) texture = ctx.texture((2, 2), 1) texture.read_into(data)
- Parameters
buffer (Union[bytearray, Buffer]) – The buffer that will receive the pixels.
- Keyword Arguments
level (int) – The mipmap level.
alignment (int) – The byte alignment of the pixels.
write_offset (int) – The write offset.
- Texture.write(data: Any, viewport: Optional[Union[Tuple[int, int], Tuple[int, int, int, int]]] = None, *, level: int = 0, alignment: int = 1) None #
Update the content of the texture from byte data or a moderngl
Buffer
.Examples:
# Write data from a moderngl Buffer data = ctx.buffer(reserve=4) texture = ctx.texture((2, 2), 1) texture.write(data) # Write data from bytes data = b'\xff\xff\xff\xff' texture = ctx.texture((2, 2), 1) texture.write(data) # Write to a sub-section of the texture using viewport texture = ctx.texture((100, 100), 4) # Fill the lower left 50x50 pixels with new data texture.write(data, viewport=(0, 0, 50, 50))
- Parameters
data (Union[bytes, Buffer]) – The pixel data.
viewport (tuple) – The sub-section of the texture to update in viewport coordinates. The data size must match the size of the area.
- Keyword Arguments
level (int) – The mipmap level.
alignment (int) – The byte alignment of the pixels.
- Texture.build_mipmaps(base: int = 0, max_level: int = 1000) None #
Generate mipmaps.
This also changes the texture filter to
LINEAR_MIPMAP_LINEAR, LINEAR
- Keyword Arguments
base (int) – The base level
max_level (int) – The maximum levels to generate
- Texture.bind_to_image(unit: int, read: bool = True, write: bool = True, level: int = 0, format: int = 0) None #
Bind a texture to an image unit (OpenGL 4.2 required).
This is used to bind textures to image units for shaders. The idea with image load/store is that the user can bind one of the images in a Texture to a number of image binding points (which are separate from texture image units). Shaders can read information from these images and write information to them, in ways that they cannot with textures.
It’s important to specify the right access type for the image. This can be set with the
read
andwrite
arguments. Allowed combinations are:Read-only:
read=True
andwrite=False
Write-only:
read=False
andwrite=True
Read-write:
read=True
andwrite=True
format
specifies the format that is to be used when performing formatted stores into the image from shaders.format
must be compatible with the texture’s internal format. By default the format of the texture is passed in. The format parameter is only needed when overriding this behavior.More information:
- Parameters
unit (int) – Specifies the index of the image unit to which to bind the texture
texture (
moderngl.Texture
) – The texture to bind
- Keyword Arguments
read (bool) – Allows the shader to read the image (default:
True
)write (bool) – Allows the shader to write to the image (default:
True
)level (int) – Level of the texture to bind (default:
0
).format (int) – (optional) The OpenGL enum value representing the format (defaults to the texture’s format)
- Texture.use(location: int = 0) None #
Bind the texture to a texture unit.
The location is the texture unit we want to bind the texture. This should correspond with the value of the
sampler2D
uniform in the shader because samplers read from the texture unit we assign to them:# Define what texture unit our two sampler2D uniforms should represent program['texture_a'] = 0 program['texture_b'] = 1 # Bind textures to the texture units first_texture.use(location=0) second_texture.use(location=1)
- Parameters
location (int) – The texture location/unit.
- Texture.release() None #
Release the ModernGL object.
Attributes#
- Texture.repeat_x: bool#
The x repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_x = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_x = False
- Type
bool
- Texture.repeat_y: bool#
The y repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_y = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_y = False
- Type
bool
- Texture.filter: Tuple[int, int]#
The minification and magnification filter for the texture.
(Default
(moderngl.LINEAR. moderngl.LINEAR)
)Example:
texture.filter == (moderngl.NEAREST, moderngl.NEAREST) texture.filter == (moderngl.LINEAR_MIPMAP_LINEAR, moderngl.LINEAR) texture.filter == (moderngl.NEAREST_MIPMAP_LINEAR, moderngl.NEAREST) texture.filter == (moderngl.LINEAR_MIPMAP_NEAREST, moderngl.NEAREST)
- Type
tuple
- Texture.swizzle: str#
The swizzle mask of the texture (Default
'RGBA'
).The swizzle mask change/reorder the
vec4
value returned by thetexture()
function in a GLSL shaders. This is represented by a 4 character string were each character can be:'R' GL_RED 'G' GL_GREEN 'B' GL_BLUE 'A' GL_ALPHA '0' GL_ZERO '1' GL_ONE
Example:
# Alpha channel will always return 1.0 texture.swizzle = 'RGB1' # Only return the red component. The rest is masked to 0.0 texture.swizzle = 'R000' # Reverse the components texture.swizzle = 'ABGR'
- Type
str
- Texture.compare_func: str#
The compare function of the depth texture (Default
'<='
).By default depth textures have
GL_TEXTURE_COMPARE_MODE
set toGL_COMPARE_REF_TO_TEXTURE
, meaning any texture lookup will return a depth comparison value.If you need to read the actual depth value in shaders, setting
compare_func
to a blank string will setGL_TEXTURE_COMPARE_MODE
toGL_NONE
making you able to read the depth texture as asampler2D
:uniform sampler2D depth; out vec4 fragColor; in vec2 uv; void main() { float raw_depth_nonlinear = texture(depth, uv); fragColor = vec4(raw_depth_nonlinear); }
Accepted compare functions:
texture.compare_func = '' # Disable depth comparison completely texture.compare_func = '<=' # GL_LEQUAL texture.compare_func = '<' # GL_LESS texture.compare_func = '>=' # GL_GEQUAL texture.compare_func = '>' # GL_GREATER texture.compare_func = '==' # GL_EQUAL texture.compare_func = '!=' # GL_NOTEQUAL texture.compare_func = '0' # GL_NEVER texture.compare_func = '1' # GL_ALWAYS
- Type
tuple
- Texture.anisotropy: float#
Number of samples for anisotropic filtering (Default
1.0
).The value will be clamped in range
1.0
andctx.max_anisotropy
.Any value greater than 1.0 counts as a use of anisotropic filtering:
# Disable anisotropic filtering texture.anisotropy = 1.0 # Enable anisotropic filtering suggesting 16 samples as a maximum texture.anisotropy = 16.0
- Type
float
- Texture.width: int#
The width of the texture.
- Type
int
- Texture.height: int#
The height of the texture.
- Type
int
- Texture.size: tuple#
The size of the texture.
- Type
tuple
- Texture.dtype: str#
Data type.
- Type
str
- Texture.components: int#
The number of components of the texture.
- Type
int
- Texture.samples: int#
The number of samples set for the texture used in multisampling.
- Type
int
- Texture.depth: bool#
Is the texture a depth texture?.
- Type
bool
- Texture.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- Texture.mglo: Any#
Internal representation for debug purposes only.
- Texture.extra: Any#
Any - Attribute for storing user defined objects
- Texture.ctx: moderngl.Context#
The context this object belongs to
TextureArray#
- class moderngl.TextureArray#
An Array Texture is a Texture where each mipmap level contains an array of images of the same size.
Array textures may have Mipmaps, but each mipmap in the texture has the same number of levels.
A TextureArray object cannot be instantiated directly, it requires a context. Use
Context.texture_array()
to create one.
Create#
- Context.texture_array(size: Tuple[int, int, int], components: int, data: Optional[Any] = None, *, alignment: int = 1, dtype: str = 'f1') moderngl.TextureArray
Create a
TextureArray
object.- Parameters
size (tuple) – The
(width, height, layers)
of the texture.components (int) – The number of components 1, 2, 3 or 4.
data (bytes) – Content of the texture. The size must be
(width, height * layers)
so each layer is stacked vertically.
- Keyword Arguments
alignment (int) – The byte alignment 1, 2, 4 or 8.
dtype (str) – Data type.
- Returns
Texture3D
object
Methods#
- TextureArray.read(*, alignment: int = 1) bytes #
Read the pixel data as bytes into system memory.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
- Returns
bytes
- TextureArray.read_into(buffer: Any, *, alignment: int = 1, write_offset: int = 0) None #
Read the content of the texture array into a bytearray or
Buffer
.The advantage of reading into a
Buffer
is that pixel data does not need to travel all the way to system memory:# Reading pixel data into a bytearray data = bytearray(8) texture = ctx.texture((2, 2, 2), 1) texture.read_into(data) # Reading pixel data into a buffer data = ctx.buffer(reserve=8) texture = ctx.texture((2, 2, 2), 1) texture.read_into(data)
- Parameters
buffer (Union[bytearray, Buffer]) – The buffer that will receive the pixels.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
write_offset (int) – The write offset.
- TextureArray.write(data: Any, viewport: Optional[Union[Tuple[int, int, int], Tuple[int, int, int, int, int, int]]] = None, *, alignment: int = 1) None #
Update the content of the texture array from byte data or a moderngl
Buffer
.The
viewport
can be used for finer control of where the data should be written in the array. The valid versions are:# Writing multiple layers from the begining of the texture texture.write(data, viewport=(width, hight, num_layers)) # Writing sub-sections of the array texture.write(data, viewport=(x, y, layer, width, height, num_layers))
Like with other texture types we can also use bytes or
Buffer
as a source:# Using a moderngl buffer data = ctx.buffer(reserve=8) texture = ctx.texture_array((2, 2, 2), 1) texture.write(data) # Using byte data from system memory data = b'\xff\xff\xff\xff\xff\xff\xff\xff' texture = ctx.texture_array((2, 2, 2), 1) texture.write(data)
- Parameters
data (bytes) – The pixel data.
viewport (tuple) – The viewport.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
- TextureArray.bind_to_image(unit: int, read: bool = True, write: bool = True, level: int = 0, format: int = 0) None #
Bind a texture to an image unit (OpenGL 4.2 required).
This is used to bind textures to image units for shaders. The idea with image load/store is that the user can bind one of the images in a Texture to a number of image binding points (which are separate from texture image units). Shaders can read information from these images and write information to them, in ways that they cannot with textures.
It’s important to specify the right access type for the image. This can be set with the
read
andwrite
arguments. Allowed combinations are:Read-only:
read=True
andwrite=False
Write-only:
read=False
andwrite=True
Read-write:
read=True
andwrite=True
format
specifies the format that is to be used when performing formatted stores into the image from shaders.format
must be compatible with the texture’s internal format. By default the format of the texture is passed in. The format parameter is only needed when overriding this behavior.Note that we bind the texture array as layered to make all the layers accessible. This can be updated to map single layers in the future.
More information:
- Parameters
unit (int) – Specifies the index of the image unit to which to bind the texture
texture (
moderngl.Texture
) – The texture to bind
- Keyword Arguments
read (bool) – Allows the shader to read the image (default:
True
)write (bool) – Allows the shader to write to the image (default:
True
)level (int) – Level of the texture to bind (default:
0
).format (int) – (optional) The OpenGL enum value representing the format (defaults to the texture’s format)
- TextureArray.build_mipmaps(base: int = 0, max_level: int = 1000) None #
Generate mipmaps.
This also changes the texture filter to
LINEAR_MIPMAP_LINEAR, LINEAR
(Will be removed in6.x
)- Keyword Arguments
base (int) – The base level
max_level (int) – The maximum levels to generate
- TextureArray.use(location: int = 0) None #
Bind the texture to a texture unit.
The location is the texture unit we want to bind the texture. This should correspond with the value of the
sampler2DArray
uniform in the shader because samplers read from the texture unit we assign to them:# Define what texture unit our two sampler2DArray uniforms should represent program['texture_a'] = 0 program['texture_b'] = 1 # Bind textures to the texture units first_texture.use(location=0) second_texture.use(location=1)
- Parameters
location (int) – The texture location/unit.
- TextureArray.release() None #
Release the ModernGL object.
Attributes#
- TextureArray.repeat_x: bool#
The x repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_x = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_x = False
- Type
bool
- TextureArray.repeat_y: bool#
The y repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_y = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_y = False
- Type
bool
- TextureArray.filter: Tuple[int, int]#
The minification and magnification filter for the texture.
(Default
(moderngl.LINEAR. moderngl.LINEAR)
)Example:
texture.filter == (moderngl.NEAREST, moderngl.NEAREST) texture.filter == (moderngl.LINEAR_MIPMAP_LINEAR, moderngl.LINEAR) texture.filter == (moderngl.NEAREST_MIPMAP_LINEAR, moderngl.NEAREST) texture.filter == (moderngl.LINEAR_MIPMAP_NEAREST, moderngl.NEAREST)
- Type
tuple
- TextureArray.swizzle: str#
The swizzle mask of the texture (Default
'RGBA'
).The swizzle mask change/reorder the
vec4
value returned by thetexture()
function in a GLSL shaders. This is represented by a 4 character string were each character can be:'R' GL_RED 'G' GL_GREEN 'B' GL_BLUE 'A' GL_ALPHA '0' GL_ZERO '1' GL_ONE
Example:
# Alpha channel will always return 1.0 texture.swizzle = 'RGB1' # Only return the red component. The rest is masked to 0.0 texture.swizzle = 'R000' # Reverse the components texture.swizzle = 'ABGR'
- Type
str
- TextureArray.anisotropy: float#
Number of samples for anisotropic filtering (Default
1.0
).The value will be clamped in range
1.0
andctx.max_anisotropy
.Any value greater than 1.0 counts as a use of anisotropic filtering:
# Disable anisotropic filtering texture.anisotropy = 1.0 # Enable anisotropic filtering suggesting 16 samples as a maximum texture.anisotropy = 16.0
- Type
float
- TextureArray.width: int#
The width of the texture array.
- Type
int
- TextureArray.height: int#
The height of the texture array.
- Type
int
- TextureArray.layers: int#
The number of layers of the texture array.
- Type
int
- TextureArray.size: tuple#
The size of the texture array.
- Type
tuple
- TextureArray.dtype: str#
Data type.
- Type
str
- TextureArray.components: int#
The number of components of the texture array.
- Type
int
- TextureArray.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- TextureArray.mglo: Any#
Internal representation for debug purposes only.
- TextureArray.extra: Any#
Any - Attribute for storing user defined objects
- TextureArray.ctx: moderngl.Context#
The context this object belongs to
Texture3D#
- class moderngl.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.
Create#
- Context.texture3d(size: Tuple[int, int, int], components: int, data: Optional[Any] = None, *, alignment: int = 1, dtype: str = 'f1') moderngl.Texture3D
Create a
Texture3D
object.- 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.
dtype (str) – Data type.
- Returns
Texture3D
object
Methods#
- Texture3D.read(*, alignment: int = 1) bytes #
Read the pixel data as bytes into system memory.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
- Returns
bytes
- Texture3D.read_into(buffer: Any, *, alignment: int = 1, write_offset: int = 0) None #
Read the content of the texture into a bytearray or
Buffer
.The advantage of reading into a
Buffer
is that pixel data does not need to travel all the way to system memory:# Reading pixel data into a bytearray data = bytearray(8) texture = ctx.texture3d((2, 2, 2), 1) texture.read_into(data) # Reading pixel data into a buffer data = ctx.buffer(reserve=8) texture = ctx.texture3d((2, 2, 2), 1) texture.read_into(data)
- Parameters
buffer (Union[bytearray, Buffer]) – The buffer that will receive the pixels.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
write_offset (int) – The write offset.
- Texture3D.write(data: Any, viewport: Optional[Union[Tuple[int, int, int], Tuple[int, int, int, int, int, int]]] = None, *, alignment: int = 1) None #
Update the content of the texture from byte data or a moderngl
Buffer
.Examples:
# Write data from a moderngl Buffer data = ctx.buffer(reserve=8) texture = ctx.texture3d((2, 2, 2), 1) texture.write(data) # Write data from bytes data = b'\xff\xff\xff\xff\xff\xff\xff\xff' texture = ctx.texture3d((2, 2), 1) texture.write(data)
- Parameters
data (bytes) – The pixel data.
viewport (tuple) – The viewport.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
- Texture3D.build_mipmaps(base: int = 0, max_level: int = 1000) None #
Generate mipmaps.
This also changes the texture filter to
LINEAR_MIPMAP_LINEAR, LINEAR
(Will be removed in6.x
)- Keyword Arguments
base (int) – The base level
max_level (int) – The maximum levels to generate
- Texture3D.bind_to_image(unit: int, read: bool = True, write: bool = True, level: int = 0, format: int = 0) None #
Bind a texture to an image unit (OpenGL 4.2 required).
This is used to bind textures to image units for shaders. The idea with image load/store is that the user can bind one of the images in a Texture to a number of image binding points (which are separate from texture image units). Shaders can read information from these images and write information to them, in ways that they cannot with textures.
It’s important to specify the right access type for the image. This can be set with the
read
andwrite
arguments. Allowed combinations are:Read-only:
read=True
andwrite=False
Write-only:
read=False
andwrite=True
Read-write:
read=True
andwrite=True
format
specifies the format that is to be used when performing formatted stores into the image from shaders.format
must be compatible with the texture’s internal format. By default the format of the texture is passed in. The format parameter is only needed when overriding this behavior.Note that we bind the 3D textured layered making the entire texture readable and writable. It is possible to bind a specific 2D section in the future.
More information:
- Parameters
unit (int) – Specifies the index of the image unit to which to bind the texture
texture (
moderngl.Texture
) – The texture to bind
- Keyword Arguments
read (bool) – Allows the shader to read the image (default:
True
)write (bool) – Allows the shader to write to the image (default:
True
)level (int) – Level of the texture to bind (default:
0
).format (int) – (optional) The OpenGL enum value representing the format (defaults to the texture’s format)
- Texture3D.use(location: int = 0) None #
Bind the texture to a texture unit.
The location is the texture unit we want to bind the texture. This should correspond with the value of the
sampler3D
uniform in the shader because samplers read from the texture unit we assign to them:# Define what texture unit our two sampler3D uniforms should represent program['texture_a'] = 0 program['texture_b'] = 1 # Bind textures to the texture units first_texture.use(location=0) second_texture.use(location=1)
- Parameters
location (int) – The texture location/unit.
- Texture3D.release() None #
Release the ModernGL object.
Attributes#
- Texture3D.repeat_x: bool#
The x repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_x = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_x = False
- Type
bool
- Texture3D.repeat_y: bool#
The y repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_y = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_y = False
- Type
bool
- Texture3D.repeat_z: bool#
The z repeat flag for the texture (Default
True
).Example:
# Enable texture repeat (GL_REPEAT) texture.repeat_z = True # Disable texture repeat (GL_CLAMP_TO_EDGE) texture.repeat_z = False
- Type
bool
- Texture3D.filter: Tuple[int, int]#
The filter of the texture.
- Type
tuple
- Texture3D.swizzle: str#
The swizzle mask of the texture (Default
'RGBA'
).The swizzle mask change/reorder the
vec4
value returned by thetexture()
function in a GLSL shaders. This is represented by a 4 character string were each character can be:'R' GL_RED 'G' GL_GREEN 'B' GL_BLUE 'A' GL_ALPHA '0' GL_ZERO '1' GL_ONE
Example:
# Alpha channel will always return 1.0 texture.swizzle = 'RGB1' # Only return the red component. The rest is masked to 0.0 texture.swizzle = 'R000' # Reverse the components texture.swizzle = 'ABGR'
- Type
str
- Texture3D.width: int#
The width of the texture.
- Type
int
- Texture3D.height: int#
The height of the texture.
- Type
int
- Texture3D.depth: int#
The depth of the texture.
- Type
int
- Texture3D.size: tuple#
The size of the texture.
- Type
tuple
- Texture3D.dtype: str#
Data type.
- Type
str
- Texture3D.components: int#
The number of components of the texture.
- Type
int
- Texture3D.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- Texture3D.mglo: Any#
Internal representation for debug purposes only.
- Texture3D.extra: Any#
Any - Attribute for storing user defined objects
- Texture3D.ctx: moderngl.Context#
The context this object belongs to
TextureCube#
- class moderngl.TextureCube#
Cubemaps are a texture using the type GL_TEXTURE_CUBE_MAP.
They are similar to 2D textures in that they have two dimensions. However, each mipmap level has 6 faces, with each face having the same size as the other faces.
The width and height of a cubemap must be the same (ie: cubemaps are squares), but these sizes need not be powers of two.
Note
ModernGL enables
GL_TEXTURE_CUBE_MAP_SEAMLESS
globally to ensure filtering will be done across the cube faces.A Texture3D object cannot be instantiated directly, it requires a context. Use
Context.texture_cube()
to create one.
Create#
- Context.texture_cube(size: Tuple[int, int], components: int, data: Optional[Any] = None, *, alignment: int = 1, dtype: str = 'f1', internal_format: Optional[int] = None) moderngl.TextureCube
Create a
TextureCube
object.Note that the width and height of the cubemap must be the same unless you are using a non-standard extension.
- Parameters
size (tuple) – The width, height of the texture. Each side of the cube will have this size.
components (int) – The number of components 1, 2, 3 or 4.
data (bytes) – Content of the texture. The data should be have the following ordering: positive_x, negative_x, positive_y, negative_y, positive_z, negative_z
- Keyword Arguments
alignment (int) – The byte alignment 1, 2, 4 or 8.
dtype (str) – Data type.
internal_format (int) – Override the internalformat of the texture (IF needed)
- Returns
TextureCube
object
Methods#
- TextureCube.read(face: int, *, alignment: int = 1) bytes #
Read a face from the cubemap as bytes into system memory.
Face values are:
0: Positive X 1: Negative X 2: Positive Y 3: Negative Y 4: Positive Z 5: Negative Z
- Parameters
face (int) – The face to read.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
- TextureCube.read_into(buffer: Any, face: int, *, alignment: int = 1, write_offset: int = 0) None #
Read a face from the cubemap texture.
Read a face of the cubemap into a bytearray or
Buffer
. The advantage of reading into aBuffer
is that pixel data does not need to travel all the way to system memory:# Reading pixel data into a bytearray data = bytearray(4) texture = ctx.texture_cube((2, 2), 1) texture.read_into(data, 0) # Reading pixel data into a buffer data = ctx.buffer(reserve=4) texture = ctx.texture_cube((2, 2), 1) texture.read_into(data, 0)
- Parameters
buffer (bytearray) – The buffer that will receive the pixels.
face (int) – The face to read.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
write_offset (int) – The write offset.
- TextureCube.write(face: int, data: Any, viewport: Optional[Union[Tuple[int, int], Tuple[int, int, int, int]]] = None, *, alignment: int = 1) None #
Update the content of the texture.
Update the content of a face in the cubemap from byte data or a moderngl
Buffer
:# Write data from a moderngl Buffer data = ctx.buffer(reserve=4) texture = ctx.texture_cube((2, 2), 1) texture.write(0, data) # Write data from bytes data = b'\xff\xff\xff\xff' texture = ctx.texture_cube((2, 2), 1) texture.write(0, data)
- Parameters
face (int) – The face to update.
data (bytes) – The pixel data.
viewport (tuple) – The viewport.
- Keyword Arguments
alignment (int) – The byte alignment of the pixels.
- TextureCube.bind_to_image(unit: int, read: bool = True, write: bool = True, level: int = 0, format: int = 0) None #
Bind a texture to an image unit (OpenGL 4.2 required).
This is used to bind textures to image units for shaders. The idea with image load/store is that the user can bind one of the images in a Texture to a number of image binding points (which are separate from texture image units). Shaders can read information from these images and write information to them, in ways that they cannot with textures.
It’s important to specify the right access type for the image. This can be set with the
read
andwrite
arguments. Allowed combinations are:Read-only:
read=True
andwrite=False
Write-only:
read=False
andwrite=True
Read-write:
read=True
andwrite=True
format
specifies the format that is to be used when performing formatted stores into the image from shaders.format
must be compatible with the texture’s internal format. By default the format of the texture is passed in. The format parameter is only needed when overriding this behavior.Note that we bind the texture cube as layered to make all the faces accessible. This can be updated to map single faces in the future. The Z component in imageLoad/Store represents the face id we are writing to (0-5).
More information:
- Parameters
unit (int) – Specifies the index of the image unit to which to bind the texture
texture (
moderngl.Texture
) – The texture to bind
- Keyword Arguments
read (bool) – Allows the shader to read the image (default:
True
)write (bool) – Allows the shader to write to the image (default:
True
)level (int) – Level of the texture to bind (default:
0
).format (int) – (optional) The OpenGL enum value representing the format (defaults to the texture’s format)
- TextureCube.use(location: int = 0) None #
Bind the texture to a texture unit.
The location is the texture unit we want to bind the texture. This should correspond with the value of the
samplerCube
uniform in the shader because samplers read from the texture unit we assign to them:# Define what texture unit our two samplerCube uniforms should represent program['texture_a'] = 0 program['texture_b'] = 1 # Bind textures to the texture units first_texture.use(location=0) second_texture.use(location=1)
- Parameters
location (int) – The texture location/unit.
- TextureCube.release() None #
Release the ModernGL object.
Attributes#
- TextureCube.size: Tuple[int, int]#
The size of the texture cube (single face).
- Type
tuple
- TextureCube.dtype: str#
Data type.
- Type
str
- TextureCube.components: int#
The number of components of the texture.
- Type
int
- TextureCube.filter: Tuple[int, int]#
The minification and magnification filter for the texture.
(Default
(moderngl.LINEAR. moderngl.LINEAR)
)Example:
texture.filter == (moderngl.NEAREST, moderngl.NEAREST) texture.filter == (moderngl.LINEAR_MIPMAP_LINEAR, moderngl.LINEAR) texture.filter == (moderngl.NEAREST_MIPMAP_LINEAR, moderngl.NEAREST) texture.filter == (moderngl.LINEAR_MIPMAP_NEAREST, moderngl.NEAREST)
- Type
tuple
- TextureCube.swizzle: str#
The swizzle mask of the texture (Default
'RGBA'
).The swizzle mask change/reorder the
vec4
value returned by thetexture()
function in a GLSL shaders. This is represented by a 4 character string were each character can be:'R' GL_RED 'G' GL_GREEN 'B' GL_BLUE 'A' GL_ALPHA '0' GL_ZERO '1' GL_ONE
Example:
# Alpha channel will always return 1.0 texture.swizzle = 'RGB1' # Only return the red component. The rest is masked to 0.0 texture.swizzle = 'R000' # Reverse the components texture.swizzle = 'ABGR'
- Type
str
- TextureCube.anisotropy: float#
Number of samples for anisotropic filtering (Default
1.0
).The value will be clamped in range
1.0
andctx.max_anisotropy
.Any value greater than 1.0 counts as a use of anisotropic filtering:
# Disable anisotropic filtering texture.anisotropy = 1.0 # Enable anisotropic filtering suggesting 16 samples as a maximum texture.anisotropy = 16.0
- Type
float
- TextureCube.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- TextureCube.mglo: Any#
Internal representation for debug purposes only.
- TextureCube.extra: Any#
Any - Attribute for storing user defined objects
- TextureCube.ctx: moderngl.Context#
The context this object belongs to
Framebuffer#
- class moderngl.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()
.
Create#
- Context.simple_framebuffer(size: Tuple[int, int], components: int = 4, *, samples: int = 0, dtype: str = 'f1') moderngl.Framebuffer
Creates a
Framebuffer
with a single color attachment and depth buffer usingmoderngl.Renderbuffer
attachments.- 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.
dtype (str) – Data type.
- Returns
Framebuffer
object
- Context.framebuffer(color_attachments: Any = (), depth_attachment: Optional[Union[moderngl.Texture, moderngl.Renderbuffer]] = None) moderngl.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
orRenderbuffer
objects.depth_attachment (Renderbuffer or Texture) – The depth attachment.
- Returns
Framebuffer
object
Methods#
- Framebuffer.clear(red: float = 0.0, green: float = 0.0, blue: float = 0.0, alpha: float = 0.0, depth: float = 1.0, *, viewport: Optional[Union[Tuple[int, int], Tuple[int, int, int, int]]] = None, color: Optional[Tuple[float, float, float, float]] = None) None #
Clear the framebuffer.
If a viewport passed in, a scissor test will be used to clear the given viewport. This viewport take presence over the framebuffers
scissor
. Clearing can still be done with scissor if no viewport is passed in.This method also respects the
color_mask
anddepth_mask
. It can for example be used to only clear the depth or color buffer or specific components in the color buffer.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.
depth (float) – depth value.
- Keyword Arguments
viewport (tuple) – The viewport.
color (tuple) – Optional tuple replacing the red, green, blue and alpha arguments
- Framebuffer.read(viewport: Optional[Union[Tuple[int, int], Tuple[int, int, int, int]]] = None, components: int = 3, *, attachment: int = 0, alignment: int = 1, dtype: str = 'f1', clamp: bool = False) bytes #
Read the content of the framebuffer.
# Read the first color attachment's RGBA data data = fbo.read(components=4) # Read the second color attachment's RGB data data = fbo.read(attachment=1) # Read the depth attachment data = fbo.read(attachment=-1) # Read the lower left 10 x 10 pixels from the first color attachment data = fbo.read(viewport=(0, 0, 10, 10))
- Parameters
viewport (tuple) – The viewport.
components (int) – The number of components to read.
- Keyword Arguments
attachment (int) – The color attachment number. -1 for the depth attachment
alignment (int) – The byte alignment of the pixels.
dtype (str) – Data type.
clamp (bool) – Clamps floating point values to
[0.0, 1.0]
- Returns
bytes
- Framebuffer.read_into(buffer: Any, viewport: Optional[Union[Tuple[int, int], Tuple[int, int, int, int]]] = None, components: int = 3, *, attachment: int = 0, alignment: int = 1, dtype: str = 'f1', write_offset: int = 0) None #
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.
dtype (str) – Data type.
write_offset (int) – The write offset.
- Framebuffer.use() None #
Bind the framebuffer. Sets the target for rendering commands.
- Framebuffer.release() None #
Release the ModernGL object.
Attributes#
- Framebuffer.viewport: Tuple[int, int, int, int]#
Get or set the viewport of the framebuffer.
- Type
tuple
- Framebuffer.scissor: Tuple[int, int, int, int]#
Get or set the scissor box of the framebuffer.
When scissor testing is enabled fragments outside the defined scissor box will be discarded. This applies to rendered geometry or
Framebuffer.clear()
.Setting is value enables scissor testing in the framebuffer. Setting the scissor to
None
disables scissor testing and reverts the scissor box to match the framebuffer size.Example:
# Enable scissor testing >>> ctx.scissor = 100, 100, 200, 100 # Disable scissor testing >>> ctx.scissor = None
- Type
tuple
- Framebuffer.color_mask: Tuple[bool, bool, bool, bool]#
The color mask of the framebuffer.
Color masking controls what components in color attachments will be affected by fragment write operations. This includes rendering geometry and clearing the framebuffer.
Default value:
(True, True, True, True)
.Examples:
# Block writing to all color components (rgba) in color attachments fbo.color_mask = False, False, False, False # Re-enable writing to color attachments fbo.color_mask = True, True, True, True # Block fragment writes to alpha channel fbo.color_mask = True, True, True, False
- Type
tuple
- Framebuffer.depth_mask: bool#
The depth mask of the framebuffer.
Depth mask enables or disables write operations to the depth buffer. This also applies when clearing the framebuffer. If depth testing is enabled fragments will still be culled, but the depth buffer will not be updated with new values. This is a very useful tool in many rendering techniques.
Default value:
True
- Type
bool
- Framebuffer.width: int#
The width of the framebuffer.
Framebuffers created by a window will only report its initial size. It’s better get size information from the window itself.
- Type
int
- Framebuffer.height: int#
The height of the framebuffer.
Framebuffers created by a window will only report its initial size. It’s better get size information from the window itself.
- Type
int
- Framebuffer.size: Tuple[int, int]#
The size of the framebuffer.
Framebuffers created by a window will only report its initial size. It’s better get size information from the window itself.
- Type
Tuple[int, int]
- Framebuffer.samples: int#
The samples of the framebuffer.
- Type
int
- Framebuffer.bits: Dict[str, str]#
The bits of the framebuffer.
- Type
dict
- Framebuffer.color_attachments: Tuple[Union[moderngl.Texture, moderngl.Renderbuffer], ...]#
The color attachments of the framebuffer.
- Type
tuple
- Framebuffer.depth_attachment: Union[moderngl.Texture, moderngl.Renderbuffer]#
The depth attachment of the framebuffer.
- Type
- Framebuffer.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- Framebuffer.mglo: Any#
Internal representation for debug purposes only.
- Framebuffer.extra: Any#
Any - Attribute for storing user defined objects
- Framebuffer.ctx: moderngl.Context#
The context this object belongs to
Renderbuffer#
- class moderngl.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.
Create#
- Context.renderbuffer(size: Tuple[int, int], components: int = 4, *, samples: int = 0, dtype: str = 'f1') moderngl.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.
dtype (str) – Data type.
- Returns
Renderbuffer
object
- Context.depth_renderbuffer(size: Tuple[int, int], *, samples: int = 0) moderngl.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
Renderbuffer
object
Methods#
- Renderbuffer.release() None #
Release the ModernGL object.
Attributes#
- Renderbuffer.width: int#
The width of the renderbuffer.
- Type
int
- Renderbuffer.height: int#
The height of the renderbuffer.
- Type
int
- Renderbuffer.size: tuple#
The size of the renderbuffer.
- Type
tuple
- Renderbuffer.samples: int#
The samples of the renderbuffer.
- Type
int
- Renderbuffer.components: int#
The components of the renderbuffer.
- Type
int
- Renderbuffer.depth: bool#
Is the renderbuffer a depth renderbuffer?.
- Type
bool
- Renderbuffer.dtype: str#
Data type.
- Type
str
- Renderbuffer.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- Renderbuffer.mglo: Any#
Internal representation for debug purposes only.
- Renderbuffer.extra: Any#
Any - Attribute for storing user defined objects
- Renderbuffer.ctx: moderngl.Context#
The context this object belongs to
Scope#
- class moderngl.Scope#
This class represents a Scope object.
Responsibilities on enter:
Set the enable flags.
Bind the framebuffer.
Assigning textures to texture locations.
Assigning buffers to uniform buffers.
Assigning buffers to shader storage buffers.
Responsibilities on exit:
Restore the enable flags.
Restore the framebuffer.
Create#
- Context.scope(framebuffer: Optional[moderngl.Framebuffer] = None, enable_only: Optional[int] = None, *, textures: Tuple[Tuple[moderngl.Texture, int], ...] = (), uniform_buffers: Tuple[Tuple[moderngl.Buffer, int], ...] = (), storage_buffers: Tuple[Tuple[moderngl.Buffer, int], ...] = (), samplers: Tuple[Tuple[moderngl.Sampler, int], ...] = (), enable: Optional[int] = None) moderngl.Scope
Create a
Scope
object.- Parameters
framebuffer (Framebuffer) – The framebuffer to use when entering.
enable_only (int) – The enable_only flags to set when entering.
- Keyword Arguments
textures (tuple) – List of (texture, binding) tuples.
uniform_buffers (tuple) – Tuple of (buffer, binding) tuples.
storage_buffers (tuple) – Tuple of (buffer, binding) tuples.
samplers (tuple) – Tuple of sampler bindings
enable (int) – Flags to enable for this vao such as depth testing and blending
Methods#
- Scope.__enter__()#
- Scope.__exit__(*args: Tuple[Any])#
- Scope.release() None #
Destroy the Scope object.
Attributes#
- Scope.extra: Any#
Any - Attribute for storing user defined objects
- Scope.mglo: Any#
Internal representation for debug purposes only.
- Scope.ctx: moderngl.Context#
The context this object belongs to
Examples#
Simple scope example
scope1 = ctx.scope(fbo1, moderngl.BLEND)
scope2 = ctx.scope(fbo2, moderngl.DEPTH_TEST | moderngl.CULL_FACE)
with scope1:
# do some rendering
with scope2:
# do some rendering
Scope for querying
query = ctx.query(samples=True)
scope = ctx.scope(ctx.screen, moderngl.DEPTH_TEST | moderngl.RASTERIZER_DISCARD)
with scope, query:
# do some rendering
print(query.samples)
Understanding what scope objects do
scope = ctx.scope(
framebuffer=framebuffer1,
enable_only=moderngl.BLEND,
textures=[
(texture1, 4),
(texture2, 3),
],
uniform_buffers=[
(buffer1, 6),
(buffer2, 5),
],
storage_buffers=[
(buffer3, 8),
],
)
# Let's assume we have some state before entering the scope
some_random_framebuffer.use()
some_random_texture.use(3)
some_random_buffer.bind_to_uniform_block(5)
some_random_buffer.bind_to_storage_buffer(8)
ctx.enable_only(moderngl.DEPTH_TEST)
with scope:
# on __enter__
# framebuffer1.use()
# ctx.enable_only(moderngl.BLEND)
# texture1.use(4)
# texture2.use(3)
# buffer1.bind_to_uniform_block(6)
# buffer2.bind_to_uniform_block(5)
# buffer3.bind_to_storage_buffer(8)
# do some rendering
# on __exit__
# some_random_framebuffer.use()
# ctx.enable_only(moderngl.DEPTH_TEST)
# Originally we had the following, let's see what was changed
some_random_framebuffer.use() # This was restored hurray!
some_random_texture.use(3) # Have to restore it manually.
some_random_buffer.bind_to_uniform_block(5) # Have to restore it manually.
some_random_buffer.bind_to_storage_buffer(8) # Have to restore it manually.
ctx.enable_only(moderngl.DEPTH_TEST) # This was restored too.
# Scope objects only do as much as necessary.
# Restoring the framebuffer and enable flags are lowcost operations and
# without them you could get a hard time debugging the application.
Query#
- class moderngl.Query#
This class represents a Query object.
Create#
- Context.query(*, samples: bool = False, any_samples: bool = False, time: bool = False, primitives: bool = False) moderngl.Query
Create a
Query
object.- Keyword Arguments
samples (bool) – Query
GL_SAMPLES_PASSED
or not.any_samples (bool) – Query
GL_ANY_SAMPLES_PASSED
or not.time (bool) – Query
GL_TIME_ELAPSED
or not.primitives (bool) – Query
GL_PRIMITIVES_GENERATED
or not.
Attributes#
- Query.samples: int#
The number of samples passed.
- Type
int
- Query.primitives: int#
The number of primitives generated.
- Type
int
- Query.elapsed: int#
The time elapsed in nanoseconds.
- Type
int
- Query.crender: Optional[moderngl.ConditionalRender]#
Can be used in a
with
statement.
- Query.extra: Any#
Any - Attribute for storing user defined objects
- Query.mglo: Any#
Internal representation for debug purposes only.
- Query.ctx: moderngl.Context#
The context this object belongs to
Examples#
Simple query example
1import moderngl
2import numpy as np
3
4ctx = moderngl.create_standalone_context()
5prog = ctx.program(
6 vertex_shader='''
7 #version 330
8
9 in vec2 in_vert;
10
11 void main() {
12 gl_Position = vec4(in_vert, 0.0, 1.0);
13 }
14 ''',
15 fragment_shader='''
16 #version 330
17
18 out vec4 color;
19
20 void main() {
21 color = vec4(1.0, 0.0, 0.0, 1.0);
22 }
23 ''',
24)
25
26vertices = np.array([
27 0.0, 0.0,
28 1.0, 0.0,
29 0.0, 1.0,
30], dtype='f4')
31
32vbo = ctx.buffer(vertices.tobytes())
33vao = ctx.simple_vertex_array(prog, vbo, 'in_vert')
34
35fbo = ctx.simple_framebuffer((64, 64))
36fbo.use()
37
38query = ctx.query(samples=True, time=True)
39
40with query:
41 vao.render()
42
43print('It took %d nanoseconds' % query.elapsed)
44print('to render %d samples' % query.samples)
Output
It took 13529 nanoseconds
to render 496 samples
ConditionalRender#
- class moderngl.ConditionalRender#
This class represents a ConditionalRender object.
ConditionalRender objects can only be accessed from
Query
objects.
Attributes#
- ConditionalRender.mglo: Any#
Internal representation for debug purposes only.
Examples#
Simple conditional rendering example
query = ctx.query(any_samples=True)
with query:
vao1.render()
with query.crender:
print('This will always get printed')
vao2.render() # But this will be rendered only if vao1 has passing samples.
ComputeShader#
- class moderngl.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.
- Compute shaders support uniforms are other member object just like a
Storage buffers can be bound using
Buffer.bind_to_storage_buffer()
.Uniform buffers can be bound using
Buffer.bind_to_uniform_block()
.Images can be bound using
Texture.bind_to_image()
.
Create#
- Context.compute_shader(source: str) moderngl.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
ComputeShader
object
Methods#
- ComputeShader.run(group_x: int = 1, group_y: int = 1, group_z: int = 1) None #
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.
- ComputeShader.get(key: str, default: Any) Union[moderngl.Uniform, moderngl.UniformBlock, moderngl.Subroutine, moderngl.Attribute, moderngl.Varying] #
Returns a Uniform, UniformBlock, Subroutine, Attribute or Varying.
- Parameters
default – This is the value to be returned in case key does not exist.
- Returns
- ComputeShader.release() None #
Release the ModernGL object.
- ComputeShader.__eq__(value, /)#
Return self==value.
- ComputeShader.__getitem__(key: str) Union[moderngl.Uniform, moderngl.UniformBlock, moderngl.Subroutine, moderngl.Attribute, moderngl.Varying] #
Get a member such as uniforms, uniform blocks, subroutines, attributes and varyings by name.
# Get a uniform uniform = program['color'] # Uniform values can be set on the returned object # or the `__setitem__` shortcut can be used. program['color'].value = 1.0, 1.0, 1.0, 1.0 # Still when writing byte data we need to use the `write()` method program['color'].write(buffer)
- ComputeShader.__setitem__(key: str, value: Any)#
Set a value of uniform or uniform block.
# Set a vec4 uniform uniform['color'] = 1.0, 1.0, 1.0, 1.0 # Optionally we can store references to a member and set the value directly uniform = program['color'] uniform.value = 1.0, 0.0, 0.0, 0.0 uniform = program['cameraMatrix'] uniform.write(camera_matrix)
- ComputeShader.__iter__() Generator[str, None, None] #
Yields the internal members names as strings.
This includes all members such as uniforms, attributes etc.
Attributes#
- ComputeShader.glo: int#
The internal OpenGL object.
This values is provided for debug purposes only.
- Type
int
- ComputeShader.mglo: Any#
Internal representation for debug purposes only.
- ComputeShader.extra: Any#
Any - Attribute for storing user defined objects
- ComputeShader.ctx: moderngl.Context#
The context this object belongs to