⚡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
Convert photos to paintings with python

Convert-photos-to-paintings Before the changes After the changes Before the changes After the changes This code is written in the Python programming l

Amir Hussein Sharifnezhad 3 May 31, 2022
Repair broken bookmarks to referenced files in Apple Photos

Repair Apple Photos Bookmarks Work in progress to repair file location bookmarks in Apple Photos. Background Starting in macOS 10.15/Catalina, photos

Rhet Turnbull 10 Nov 03, 2022
Python implementation of image filters (such as brightness, contrast, saturation, etc.)

PyPhotoshop Python implementation of image filters Use Python to adjust brightness and contrast, add blur, and detect edges! Follow along tutorial: ht

Kylie 87 Dec 15, 2022
Manipulate EXIF and IFD metadata.

Tyf Copyright Distribution Support this project Buy Ѧ and: Send Ѧ to AUahWfkfr5J4tYakugRbfow7RWVTK35GPW Vote arky on Ark blockchain and earn Ѧ weekly

16 Jan 21, 2022
Fuzzware is a project for automated, self-configuring fuzzing of firmware images

Fuzzware Fuzzware is a project for automated, self-configuring fuzzing of firmware images. The idea of this project is to configure the memory ranges

190 Dec 21, 2022
PyGtk Color - A couple of python scripts to select a color (for scripting usage)

Selection Scripts This repository contains two scripts to be used within a scripting project, to aquire a color value. Both scripts requir

Spiros Georgaras 1 Oct 31, 2021
Pyconvert is a python script that you can use to convert image files to another image format! (eg. PNG to ICO)

Pyconvert is a python script that you can use to convert image files to another image format! (eg. PNG to ICO)

1 Jan 16, 2022
Demo of using Auto Encoder for Image Denoising

Demo of using Auto Encoder for Image Denoising

2 Aug 04, 2022
Convert a DOS Punk image to text

DOS Punk Text Inspired by MAX CAPACITY's DOS Punks & the amazing DOS Punk community. DOS Punk Text is a Python 3 script that renders a DOS Punk image

4 Jan 13, 2022
Create a QR-code Generator app using only Python.

QR-code_Generator Create a QR-code Generator app using only Python. This apps generated a QR code for a single link. Libraryes used in this app -- py

Soham P Phasalkar 1 Oct 17, 2021
An API that renders HTML/CSS content to PNG using Chromium

html_png An API that renders HTML/CSS content to PNG using Chromium Disclaimer I am not responsible if you happen to make your own instance of this AP

10 Aug 08, 2022
PyPixelArt - A keyboard-centered pixel editor

PyPixelArt - A keyboard-centered pixel editor The idea behind PyPixelArt is uniting: a cmdpxl inspired pixel image editor applied to pixel art. vim 's

Douglas 18 Nov 14, 2022
Python QR Code image generator

Pure python QR Code generator Generate QR codes. For a standard install (which will include pillow for generating images), run: pip install qrcode[pil

Lincoln Loop 3.5k Dec 31, 2022
Utilities for SteamVR on Linux

This project contains scripts to improve the functionally of SteamVR on Linux:

86 Dec 29, 2022
Image histogram remapping

Hmap An image histogram remapping script written in Python 2.7 by Anthony Kesich and Ross Goodwin. Changes source image so that source image's histogr

Ross Goodwin 199 Nov 19, 2022
Sombra is simple Raytracer written in pure Python.

Sombra Sombra is simple Raytracer written in pure Python. It's main purpose is to help understand how raytracing works with a clean code. If you are l

Hernaldo Jesus Henriquez Nuñez 10 Jul 16, 2022
Seeks to remove text from an image in a convincing way.

Text-Removal This is a Computer Vision project that seeks to successfully remove text from an image by covering the text areas in a convincing way. He

6 Nov 22, 2022
View images in the terminal using ansi escape codes and python

terminal-photo-viewer view images in the terminal using ansi escape codes and python !! Only tested on Ubuntu 20.04.3 LTS with python version 3.8.10 D

1 Nov 30, 2021
MetaStalk is a tool that can be used to generate graphs from the metadata of JPEG, TIFF, and HEIC images

MetaStalk About MetaStalk is a tool that can be used to generate graphs from the metadata of JPEG, TIFF, and HEIC images, which are tested. More forma

Cyb3r Jak3 1 Jul 05, 2021
A Toolbox for Image Feature Matching and Evaluations

This is a toolbox repository to help evaluate various methods that perform image matching from a pair of images.

Qunjie Zhou 342 Dec 29, 2022