⚡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
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
Forza painter app with python

forza-painter Discord: A-Dawg#0001 (AE) Supports: Forza Horizon 5 Offically (OTHER v1.405.2.0, MS STORE v3.414.967.0, STEAM v1.414.967.0) Unofficially

320 Dec 31, 2022
Blender addon to generate better building models from satellite imagery.

Blender addon to generate better building models from satellite imagery.

Ivan Ereshchenko 24 Apr 14, 2022
HTML2Image is a lightweight Python package that acts as a wrapper around the headless mode of existing web browsers to generate images from URLs and from HTML+CSS strings or files.

A package acting as a wrapper around the headless mode of existing web browsers to generate images from URLs and from HTML+CSS strings or files.

176 Jan 01, 2023
⚡ZenGL is a minimalist Python module providing exactly one way to render scenes with OpenGL.

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

Szabolcs Dombi 133 Dec 17, 2022
Advance Image Steganography

Chaya Advance Image Steganography Using LSB-LPS + AES-256-GCM + FLIF Right To Privacy! United Nations Declaration of Human Rights (UDHR) 1948, Article

XeroHack 113 Dec 02, 2022
Python library that finds the size / type of an image given its URI by fetching as little as needed

FastImage This is an implementation of the excellent Ruby library FastImage - but for Python. FastImage finds the size or type of an image given its u

Brian Muller 28 Mar 01, 2022
Png2Jpg tool will help you convert from png image format to jpg images format.

PNG 2 JPG All codes assume running from root directory. Please update the sys path at the beginning of the codes before running. Over View Png2Jpg too

Nguyễn Trường Lâu 2 Dec 27, 2021
Rembg is a tool to remove images background.

Rembg is a tool to remove images background.

Daniel Gatis 7.8k Jan 05, 2023
📷 Python package and CLI utility to create photo mosaics.

📷 Python package and CLI utility to create photo mosaics.

Loic Coyle 7 Oct 29, 2022
A little Python tool to convert a TrueType (ttf/otf) font into a PNG for use in demos.

font2png A little Python tool to convert a TrueType (ttf/otf) font into a PNG for use in demos. To use from command line it expects python3 to be at /

Rich Elmes 3 Dec 22, 2021
The aim is to extract timeseries water level 2D information for any designed boundaries within the EasyGSH model domain

bct_file_generator_for_EasyGSH The aim is to extract timeseries water level 2D information for any designed boundaries within the EasyGSH model domain

Clayton Soares 1 Jul 08, 2022
Create a 2D mesh for an airfoil in GMSH using python.

GMSHFoil A simple class to create a 2D mesh for an airfoil in GMSH using python. Requirements pip install airfoils

Charilaos Mylonas 1 May 16, 2022
A simple Streamlit Component to compare images in Streamlit apps. It integrates Knightlab's JuxtaposeJS

streamlit-image-juxtapose A simple Streamlit Component to compare images in Streamlit apps using Knightlab's JuxtaposeJS. The images are saved to the

Robin 30 Dec 31, 2022
The ctypes-based simple ImageMagick binding for Python

Wand Wand is a ctypes-based simple ImageMagick binding for Python, supporting 2.7, 3.3+, and PyPy. All functionalities of MagickWand API are implement

Eric McConville 1.2k Dec 30, 2022
Photini - A free, easy to use, digital photograph metadata (Exif, IPTC, XMP) editing application for Linux, Windows and MacOS.

A free, easy to use, digital photograph metadata (Exif, IPTC, XMP) editing application for Linux, Windows and MacOS. "Metadata" is said to mea

Jim Easterbrook 120 Dec 20, 2022
Python Digital Art Generator

Python Digital Art Generator The main goal of this repository is to generate all possible layers permutations given by the user in order to get unique

David Cuentas Mar 3 Mar 12, 2022
Convert Image to ASCII Art

Convert Image to ASCII Art Persiapan aplikasi ini menggunakan bahasa python dan beberapa package python. oleh karena itu harus menginstall python dan

Huda Damar 48 Dec 20, 2022
missing-pixel-filler is a python package that, given images that may contain missing data regions (like satellite imagery with swath gaps), returns these images with the regions filled.

Missing Pixel Filler This is the official code repository for the Missing Pixel Filler by SpaceML. missing-pixel-filler is a python package that, give

SpaceML 11 Jul 19, 2022
Black-white image converter - Black-white photo colorization

Black-white image converter - Black-white photo colorization

1 Jan 02, 2022