⚡ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

Overview

ZenGL

ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

pip install zengl

ZenGL is ...

  • high-performance
  • simple - buffers, images, pipelines and there you go
  • easy-to-learn - it is simply OpenGL with no magic added
  • verbose - most common mistakes are catched and reported in a clear and understandable way
  • robust - there is no global state or external trouble-maker affecting the render
  • backward-compatible - it requires OpenGL 3.3 - it is just enough
  • cached - most OpenGL objects are reused between renders
  • zen - there is one way to do it

Concept

ZenGL provides a simple way to render from Python. We aim to support headless rendering first, rendering to a window is done by blitting the final image to the screen. By doing this we have full control of what we render. The window does not have to be multisample, and it requires no depth buffer at all.

Offscreen rendering works out of the box on all platforms if the right loader is provided. Loaders implement a load method to resolve a subset of OpenGL 3.3 core. The return value of the load method is an int, a void pointer to the function implementation. Virtualized, traced, and debug environments can be provided by custom loaders. The current implementation uses the glcontext from moderngl to load the OpenGL methods.

ZenGL's main focus is on readability and maintainability. Pipelines in ZenGL are almost entirely immutable and they cannot affect each other except when one draws on top of the other's result that is expected. No global state is affecting the render, if something breaks there is one place to debug.

ZenGL does not use anything beyond OpenGL 3.3 core, not even if the more convenient methods are available. Implementation is kept simple. Usually, this is not a bottleneck.

ZenGL does not implement transform feedback, storage buffers or storage images, tesselation, geometry shader, and maybe many more. We have a strong reason not to include them in the feature list. They add to the complexity and are against ZenGL's main philosophy. ZenGL was built on top experience gathered on real-life projects that could never make good use of any of that.

ZenGL is using the same vertex and image format naming as WebGPU and keeping the vertex array definition from ModernGL. ZenGL is not the next version of ModernGL. ZenGL is a simplification of a subset of ModernGL with some extras that were not possible to include in ModernGL.

Examples

grass.py

grass

envmap.py

envmap

instanced_crates.py

instanced_crates

julia_fractal.py

julia_fractal

blending.py

blending

render_to_texture.py

render_to_texture

pybullet_box_pile.py

pybullet_box_pile

pygmsh_shape.py

pygmsh_shape

texture_array.py

texture_array

monkey.py

monkey

reflection.py

reflection

polygon_offset.py

polygon_offset

blur.py

blur

hello_triangle.py

hello_triangle

hello_triangle_srgb.py

hello_triangle_srgb

viewports.py

viewports

points.py

points

wireframe_terrain.py

wireframe_terrain

crate.py

crate

sdf_example.py

sdf_example

sdf_tree.py

sdf_tree

mipmaps.py

mipmaps

conways_game_of_life.py

conways_game_of_life

Headless

import zengl
from PIL import Image

ctx = zengl.context(zengl.loader(headless=True))

size = (1280, 720)
image = ctx.image(size, 'rgba8unorm', samples=1)

triangle = ctx.pipeline(
    vertex_shader='''
        #version 330

        out vec3 v_color;

        vec2 positions[3] = vec2[](
            vec2(0.0, 0.8),
            vec2(-0.6, -0.8),
            vec2(0.6, -0.8)
        );

        vec3 colors[3] = vec3[](
            vec3(1.0, 0.0, 0.0),
            vec3(0.0, 1.0, 0.0),
            vec3(0.0, 0.0, 1.0)
        );

        void main() {
            gl_Position = vec4(positions[gl_VertexID], 0.0, 1.0);
            v_color = colors[gl_VertexID];
        }
    ''',
    fragment_shader='''
        #version 330

        in vec3 v_color;

        layout (location = 0) out vec4 out_color;

        void main() {
            out_color = vec4(v_color, 1.0);
        }
    ''',
    framebuffer=[image],
    topology='triangles',
    vertex_count=3,
)

image.clear_value = (1.0, 1.0, 1.0, 1.0)
image.clear()
triangle.render()

Image.frombuffer('RGBA', size, image.read(), 'raw', 'RGBA', 0, -1).save('hello.png')
Comments
  • Error loading example

    Error loading example

    I ran into this issue while trying out examples. Technically it seems to be a pyglet issue, but since I ran into it while trying out your library you may still want to be aware.

    $ python3 examples/hello_triangle.py
    2021-11-12 19:53:40.357 Python[11913:760548] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to /var/folders/96/t_1vtxwn7z5b5g22grwztfq80000gn/T/com.apple.python3.savedState
    Traceback (most recent call last):
      File "examples/hello_triangle.py", line 5, in <module>
        window = Window(1280, 720)
      File "/Users/ades/repos/zengl/examples/window.py", line 17, in __init__
        super().__init__(width=width, height=height, config=config)
      File "/Users/ades/Library/Python/3.8/lib/python/site-packages/pyglet/window/__init__.py", line 658, in __init__
        self._create()
      File "/Users/ades/Library/Python/3.8/lib/python/site-packages/pyglet/window/cocoa/__init__.py", line 197, in _create
        self.context.attach(self.canvas)
      File "/Users/ades/Library/Python/3.8/lib/python/site-packages/pyglet/gl/cocoa.py", line 299, in attach
        self._nscontext.setView_(canvas.nsview)
    AttributeError: 'NoneType' object has no attribute 'setView_'
    

    I'm using:

    • macOS Big Sur 11.1:
    • Python 3.8.2
    • pyglet==1.5.21
    • numpy==1.21.4

    I tested another app that uses pyglet and that loaded up just fine.

    opened by anderslindho 9
  • Dependencies for the examples

    Dependencies for the examples

    I noticed that numpy was a requirement to use this library.

    I suppose that pyglet also could be added to this list, but since it technically only is used for the examples that part was less clear to me. I could add it to this MR as an optional feature if you'd like (through use of extras_requires).

    opened by anderslindho 6
  • Examples only cover lower-left corner of Pyglet window

    Examples only cover lower-left corner of Pyglet window

    Broke this out of #18.

    The examples only cover the lower-left corner of the Pyglet window:

    Screenshot 2022-06-02 at 21 15 04 Screenshot 2022-06-02 at 21 18 38

    Other output, such as the mp4 generated by ffmpeg_stream.py are just fine (1280x720).


    Python 3.9.12 on macOS 10.15.7 on AMD Radeon Pro 5500M 4 GB graphics (macbook pro 2019), libraries:

    ffmpeg-python==0.2.0
    glcontext==2.3.6
    moderngl==5.6.4
    Pillow==9.1.1
    pyglet==1.5.26
    
    opened by akx 4
  • Leave GL_FRAMEBUFFER_SRGB disabled by default

    Leave GL_FRAMEBUFFER_SRGB disabled by default

    Despite it is recommended to keep this enabled, it breaks integrations like imgui rendering to the default framebuffer. Also it affects the glBlitFramebuffers in an odd way copying between non srgb and srgb images. With the zengl examples it is more common to disable it for the blit than to actually use it while enabled. Some drivers are not supporting GL_FRAMEBUFFER_SRGB according to the specs.

    ZenGL should enable GL_FRAMEBUFFER_SRGB when needed and disable it afterwards. This change should not affect existing users.

    opened by szabolcsdombi 2
  • Examples fail with

    Examples fail with "ValueError: Unbound vertex attribute "gl_VertexID" at location 0"

    Running on a Macbook Pro 2019, Python 3.9, macOS 10.15.7, the examples (tried a few) fail with

    $ python julia_fractal.py
    2022-06-02 21:03:34.519 Python[79599:798132] ApplePersistenceIgnoreState: Existing state will not be touched. New state will be written to (null)
    Traceback (most recent call last):
      File "/Users/akx/build/zengl/examples/julia_fractal.py", line 14, in <module>
        scene = ctx.pipeline(
      File "/Users/akx/build/zengl/_zengl.py", line 382, in validate
        raise ValueError(f'Unbound vertex attribute "{name}" at location {location}')
    ValueError: Unbound vertex attribute "gl_VertexID" at location 0
    

    (please ignore the f string, I'm running #17 right now)

    Is gl_VertexID supposed to be somehow implicitly bound by... something..?

    Commenting out the check makes things work, but it sounds like there's something weird here :)

    opened by akx 2
  • just getting started, using streaming_video.py example

    just getting started, using streaming_video.py example

    Realizing what I'm looking for may not be in zengl; when I run the streaming_video.py example I see my webcam0 fine, but it is vertically flipped.

    To vertically flip the video frame, would that be done at the imageio, the zengl, or some other image module level I need to bring into that minimal example? I am thinking the return value from zengl.rgba(next(it), 'rgb') would saved to an intermediate variable, potentially as input to some image object that allows basic graphical operations, such as the vertical flip I want?

    opened by bsenftner 2
  • Better support for non double buffering windows

    Better support for non double buffering windows

    Double buffering is not necessary with zengl. Rendering is done entirely offscreen and the final image may be blitted to the screen. This technique does not require double buffering to hide in-progress rendering artifacts. When double buffering is off, it seems the rendering queue is not flushed automatically at the end of a frame. (the end of the frame is not clearly defined in this case) glFlush must be called

    TODO: implement Context.flush() TODO: maybe Image.blit(..., flush=True) TODO: keep only one of the above

    opened by szabolcsdombi 2
  • Constant uniform support

    Constant uniform support

    Support binding uniform values at create time this might be useful for flags, render modes, ...

    For example:

    blur pipeline with uniform to set vertical / horizontal blur render pipeline with a uniform flag/mode to switch between rendering for reflection, rendering shadow maps render shadow pipeline to switch between light sources rendering to cubemap and define the face

    These values must be bound at render time, but at least they can be encoded in pipeline create time. Allowing to change these values at runtime would require more components for not much extra value (for that uniform buffers seem to be a better fit)

    opened by szabolcsdombi 1
  • Convert string formatting to f-strings

    Convert string formatting to f-strings

    Since this project is Python 3.6+, string formatting could just as well use the faster and more convenient f-strings.

    This was a mechanical conversion with pyupgrade and flynt, followed up by some manual fixups.

    opened by akx 1
  • Pipeline vertex_count, first_vertex and instance_count cannot be read or written after creation

    Pipeline vertex_count, first_vertex and instance_count cannot be read or written after creation

    In zengl.cpp (currently at line 2124)

    PyMemberDef Pipeline_members[] = {
        {"vertex_count", T_OBJECT_EX, offsetof(Pipeline, vertex_count), 0, NULL},
        {"instance_count", T_OBJECT_EX, offsetof(Pipeline, instance_count), 0, NULL},
        {"first_vertex", T_OBJECT_EX, offsetof(Pipeline, first_vertex), 0, NULL},
        {},
    };
    

    should use T_INT instead

    PyMemberDef Pipeline_members[] = {
        {"vertex_count", T_INT, offsetof(Pipeline, vertex_count), 0, NULL},
        {"instance_count", T_INT, offsetof(Pipeline, instance_count), 0, NULL},
        {"first_vertex", T_INT, offsetof(Pipeline, first_vertex), 0, NULL},
        {},
    };
    
    opened by mrossetti 1
  • Check for multisample support

    Check for multisample support

    It is very common to have samples=4 supported. It even works with software renderers. However, the supported number of samples should be collected and checked against the image parameters.

    opened by szabolcsdombi 1
Releases(1.10.2)
Owner
Szabolcs Dombi
Creator of ModernGL
Szabolcs Dombi
LSB Image Steganography Using Python

Steganography is the science that involves communicating secret data in an appropriate multimedia carrier, e.g., image, audio, and video files

Mahmut Can Gönül 2 Nov 04, 2021
Image Compression GUI APP Python: PyQt5

Image Compression GUI APP Image Compression GUI APP Python: PyQt5 Use : f5 or debug or simply run it on your ids(vscode , pycham, anaconda etc.) socia

Sourabh Dhalia 1 May 21, 2022
Draw a torus passing through three given points.

PyTorusThreePoints Draw a torus passing through three given points. Usage import numpy as np import pyvista as pv from torus_three_points.main import

2 Nov 19, 2021
An add to make adding screenshots and copied images to the scene easy

Blender Clipboard to Scene It doesn't work with version 2.93 and higher (I tested it on 2.91 and 2.83) There is an issue with importing the Pillow mod

Mohammad Mehdi Afkhami 3 Dec 29, 2021
Convert any image into greyscale ASCII art.

Image-to-ASCII Convert any image into greyscale ASCII art.

Ben Smith 12 Jan 15, 2022
Convert HDR photos taken by iPhone 12 (or later) to regular HDR images

heif-hdrgainmap-decode Convert HDR photos taken by iPhone 12 (or later) to regular HDR images. Installation First, make sure you have the following pa

Star Brilliant 5 Nov 13, 2022
Glyphtracer is an app for converting images of letters to a font

Glyphtracer takes an image that contains pictures of several letters. It recognizes all them and lets the user tag each letter to a Unicode code point. It then converts the images to vector form and

Jussi Pakkanen 38 Dec 24, 2022
A collection of python scripts which help you programatically create PNGs or GIFs

A collection of python scripts which help you programatically create PNGs or GIFs and their Metadata in bulk with custom rarity rates, upload them to OpenSea & list them for sale.

Tom 30 Dec 24, 2022
Simple Python package to convert an image into a quantized image using a customizable palette

Simple Python package to convert an image into a quantized image using a customizable palette. Resulting image can be displayed by ePaper displays such as Waveshare displays.

Luis Obis 3 Apr 13, 2022
Simple to use image handler for python sqlite3.

SQLite Image Handler Simple to use image handler for python sqlite3. Functions Function Name Parameters Returns init databasePath : str tableName : st

Mustafa Ozan Çetin 7 Sep 16, 2022
Image generation API.

Image Generator API This is an api im working on Currently its just a test project Im trying to make custom readme images with your discord account pr

Siddhesh Zantye 2 Feb 19, 2022
A QR Code encode and decode python module

A QR Code encode and decode python module

Fayas Noushad 4 Feb 10, 2022
A python script for extracting/removing exif data from images by @AbirHasan2005

Image-Exif A Python script for extracting exif metadata from images. How to use? Using this script you can extract exif data from image and save in .c

Abir Hasan 13 Dec 16, 2022
Generate your own QR Code and scan it to see the results! Never use it for malicious purposes.

QR-Code-Generator-Python Choose the name of your generated QR .png file. If it happens to open the .py file (the application), there are specific comm

1 Dec 23, 2021
Extract the ISO 11146 beam size from an image file

laserbeamsize Simple and fast calculation of beam sizes from a single monochrome image based on the ISO 11146 method of variances. Some effort has bee

Scott Prahl 21 Jan 06, 2023
With this simple py script you will be able to get all the .png from a folder and generate a yml for Oraxen

Oraxen-item-to-yml With this simple py script you will be able to get all the .png from a folder and generate a yml for Oraxen How to use Install the

Akex 1 Dec 29, 2021
A tool for hiding data inside of images

Stegenography-tool a tool for hiding data inside of images Quick test: do python steg-encode.py test/message.txt test/covid19.png to generate the test

luke 2 Nov 02, 2021
Fixed Version Of Blender Low Poly Rock Generator For Blender 3.0.0

Blender (3.0.0) - Low Poly Rock Generator This is an addon for Blender 3.0.0 to generate low poly rocks. It was based on an addon that unfortunately h

3 Mar 24, 2022
Multi-view 3D reconstruction using neural rendering. Unofficial implementation of UNISURF, VolSDF, NeuS and more.

Multi-view 3D reconstruction using neural rendering. Unofficial implementation of UNISURF, VolSDF, NeuS and more.

Jianfei Guo 683 Jan 04, 2023
QR code python application which can read(decode) and generate(encode) QR codes.

QR Code Application This is a basic QR Code application. Using this application you can generate QR code for you text/links. Using this application yo

Atharva Parkhe 1 Aug 09, 2022