⚡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
Music Thumbnail Maker

Music Thumbnail Installing pip install TMFrame

krypton 4 Jan 28, 2022
Validate arbitrary image uploads from incoming data urls while preserving file integrity but removing EXIF and unwanted artifacts and RCE exploit potential

Validate arbitrary base64-encoded image uploads as incoming data urls while preserving image integrity but removing EXIF and unwanted artifacts and mitigating RCE-exploit potential.

A3R0 1 Jan 10, 2022
MikuMikuRig是一款集生成控制器,自动导入动画,自动布料为一体的blender插件

Miku_Miku_Rig MikuMikuRig是一款集生成控制器,自动导入动画,自动布料为一体的blender插件。 MikumiKurig is a Blender plugin that can generates rig, automatically imports animations

小威廉伯爵 342 Dec 29, 2022
This repository will help you get label for images in Stanford Cars Dataset.

STANFORD CARS DATASET stanford-cars "The Cars dataset contains 16,185 images of 196 classes of cars. The data is split into 8,144 training images and

Nguyễn Trường Lâu 3 Sep 20, 2022
python app to turn a photograph into a cartoon

Draw This. Draw This is a polaroid camera that draws cartoons. You point, and shoot - and out pops a cartoon; the camera's best interpretation of what

Dan Macnish 2k Dec 19, 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
Py3D - A 3d rendering engine written entirely in python

Py3D is a 3d rendering engine written entirely in python. It is a simple and eas

1up Community 2 Nov 14, 2022
Design custom QR codes with this web app!

My-QR.Art This web app lets users design their own QR codes to any domain. It can be acessed on my-qr.art. You can find some more background info abou

Marien Raat 406 Dec 20, 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
Generate different types of random avatars.

avatar-generator Generate different types of random avatars. Requirements Python3 pytorch=1.6 cv2=3.4 tqdm 1. Github-like avatars python generate_gi

Ming 11 Apr 02, 2022
NFT collection generator. Generates layered images

NFT collection generator Generates layered images, whole collections. Provides additional functionality. Repository includes three scripts generate.py

Gleb Gonchar 10 Nov 15, 2022
A simple programme for converting url into a qr code (.png file)

QrTk A simple lightweight programme for converting url into a qr code (.png file) Pre-Requisites Before installing the programme , you need to run the

Juss Patel 4 Nov 08, 2021
Blender addon - convert empty image reference to image plane

Reference to image plane Convert reference images to a textured image mesh plane. As if it was imported with import image as plane Use on drag'n'dropp

Samuel Bernou 6 Nov 25, 2022
ProsePainter combines direct digital painting with real-time guided machine-learning based image optimization.

ProsePainter Create images by painting with words. ProsePainter combines direct digital painting with real-time guided machine-learning based image op

Morphogen 276 Dec 17, 2022
Detecting haze image with hazer.

hazer-py Detecting haze image with hazer. What is hazer Hazer is a lib for getting "haze degree". This repository is python version of hazer: https://

Joey777210 2 Dec 27, 2021
Magic-Square - Creates a magic square by randomly generating a list until the list happens to be a magic square

Magic-Square Creates a magic square by randomly generating a list until the list happens to be a magic square. Done as simply as possible... Frequentl

Nick 2 Jan 01, 2022
This is an app that allows users to upload photos and display and store the photos in a file until the user deletes them.

Qt Photo App This is an app that allows users to upload photos and display and store the photos in a file until the user deletes them. Setup python3 -

Kathy Yang 5 Jan 22, 2022
A Gtk based Image Selector with Preview

gtk-image-selector This is an attempt to restore Gtk Image Chooser "lost functionality": displaying an image preview when selecting images... This is

Spiros Georgaras 2 Sep 28, 2022
Group of interfaces interesting for users

Project: Interface to create GIF animation based on Fourier Series.

5 Aug 17, 2021
Hide sensitive information in images

Data-Preserved Script allowing to blur the most sensitive information on images. Prerequisites Before you begin, ensure you have met the following req

2 Dec 01, 2021