Adding shader support to pyglet

749 views
Skip to first unread message

Benjamin Moran

unread,
Feb 15, 2016, 7:53:46 PM2/15/16
to pyglet-users
Hi guys,

How would everyone feel about adding a simple shader Class to the graphics module? There have been a few go-to examples out there, such as Tristan McDonald's popular one here: https://swiftcoder.wordpress.com/2008/12/19/simple-glsl-wrapper-for-pyglet/
And Leonhard Vogt's framebuffer code that includes shaders here:
https://leovt.wordpress.com/2015/10/04/render-to-texture-with-python-3-and-pyglet/
https://github.com/leovt/leovt/blob/master/framebuffer.py

The reason I would like to see it included is because of the ctypes magic being a bit of a blocker for new users. A simple class could handle this for the users, and allow them to easily try more modern contexts with pyglet.

If I wrote this code, would it be accepted? I'm thinking a simple class, plus basic example code. (Speaking of which, many of those examples need to be updated!)

-Ben

...

unread,
Feb 15, 2016, 7:59:09 PM2/15/16
to pyglet...@googlegroups.com

Just a user but I would love that.

--
You received this message because you are subscribed to the Google Groups "pyglet-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyglet-users...@googlegroups.com.
To post to this group, send email to pyglet...@googlegroups.com.
Visit this group at https://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/d/optout.

Tristam MacDonald

unread,
Feb 15, 2016, 8:31:32 PM2/15/16
to pyglet...@googlegroups.com
+1, it's a major pain point when starting out a pyglet project

Benjamin Moran

unread,
Feb 16, 2016, 7:55:04 AM2/16/16
to pyglet-users
Hi Tristam,

Since you're here, just wanted to say thanks for your original shader class. It's still the most popular link on Google I think!

I've already put together a basic class together, based on the OpenGL docs (and yours and other pyglet examples for ctypes clarification). I'm still thinking of what it should entail, but for a start it will just be simple vertex/fragment program.

Serdar Yegulalp

unread,
Feb 16, 2016, 8:35:49 AM2/16/16
to pyglet-users
+1 as well. I used Tristan's code on my own, but would love to see a "native" shader for pyglet.

Paulo Martins

unread,
Feb 16, 2016, 9:16:20 AM2/16/16
to pyglet-users
x2 I love the idea.

Benjamin Moran

unread,
Feb 16, 2016, 9:52:34 AM2/16/16
to pyglet-users
It seems like there is a lot of demand for this!

I think there are a lot of small implementation details to think about, to make it easy for users. For example:
  • Dealing with the Window.on_resize behavior if shaders are used.
  • Should checking be done on OpenGL context versions before compiling a shader? Maybe check against the the shader source's "#version" string if it exists?
  • Debug: should the shader class have it's own debug flag, or rely on the pyglet OpenGL debug flag? Does it make sense to have it's own as GLSL is it's own thing? 
  • Needs to be Python2.7/3 compatible. This should only require a few small things, such as confirming the shader source is a byte string.

My current code has bind and unbind methods, but also has __enter__ and __exit__ methods which just call bind and unbind. I like using it with a "with" context:
shader_program = Program(vertex_source, fragment_source)

with shader_program:
    do_stuff
()

Petr Viktorin

unread,
Feb 16, 2016, 10:10:05 AM2/16/16
to pyglet...@googlegroups.com
On 02/16/2016 03:52 PM, Benjamin Moran wrote:
> It seems like there is a lot of demand for this!
>
> I think there are a lot of small implementation details to think about,
> to make it easy for users. For example:
>
> * Dealing with the Window.on_resize behavior if shaders are used.
> * Should checking be done on OpenGL context versions before compiling
> a shader? Maybe check against the the shader source's "#version"
> string if it exists?
> * Debug: should the shader class have it's own debug flag, or rely on
> the pyglet OpenGL debug flag? Does it make sense to have it's own as
> GLSL is it's own thing?
> * Needs to be Python2.7/3 compatible. This should only require a few
> small things, such as confirming the shader source is a byte string.

From a Python3 point of view, requiring bytes for textual data is a step
backwards. (And it is text - it has an encoding even if it's ASCII, it's
lines-oriented, there are no \0 bytes, etc.)

Since OpenGL 4.2, the official shader encoding is UTF-8, and before that
it was, I believe, ASCII which is a subset of UTF-8. So I think that if
unicode is passed in, it should be decoded with UTF-8 before passing it
to OpenGL.


> My current code has bind and unbind methods, but also has __enter__ and
> __exit__ methods which just call bind and unbind. I like using it with a
> "with" context:
> |
> shader_program =Program(vertex_source,fragment_source)
>
> withshader_program:
> do_stuff()
> |
>
>
>
>
> On Tuesday, February 16, 2016 at 11:16:20 PM UTC+9, Paulo Martins wrote:
>
> x2 I love the idea.
>
> terça-feira, 16 de Fevereiro de 2016 às 00:53:46 UTC, Benjamin Moran
> escreveu:
>
> Hi guys,
>
> How would everyone feel about adding a simple shader Class to
> the graphics module? There have been a few go-to examples out
> there, such as Tristan McDonald's popular one here:
> https://swiftcoder.wordpress.com/2008/12/19/simple-glsl-wrapper-for-pyglet/
> <https://swiftcoder.wordpress.com/2008/12/19/simple-glsl-wrapper-for-pyglet/>
> And Leonhard Vogt's framebuffer code that includes shaders here:
> https://leovt.wordpress.com/2015/10/04/render-to-texture-with-python-3-and-pyglet/
> <https://leovt.wordpress.com/2015/10/04/render-to-texture-with-python-3-and-pyglet/>
> https://github.com/leovt/leovt/blob/master/framebuffer.py
> <https://github.com/leovt/leovt/blob/master/framebuffer.py>
>
> The reason I would like to see it included is because of the
> ctypes magic being a bit of a blocker for new users. A simple
> class could handle this for the users, and allow them to easily
> try more modern contexts with pyglet.
>
> If I wrote this code, would it be accepted? I'm thinking a
> simple class, plus basic example code. (Speaking of which, many
> of those examples need to be updated!)
>
> -Ben
>
> --
> You received this message because you are subscribed to the Google
> Groups "pyglet-users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to pyglet-users...@googlegroups.com
> <mailto:pyglet-users...@googlegroups.com>.
> To post to this group, send email to pyglet...@googlegroups.com
> <mailto:pyglet...@googlegroups.com>.

Benjamin Moran

unread,
Feb 16, 2016, 9:17:09 PM2/16/16
to pyglet-users
Hi Petr,

I agree about not requiring sending a byte string in Python 3. It's another small thing that could trip up new users, and should not be required for Python 3. For my current code I just do a quick encode on the string if it's not already a byte string, allowing you to pass either a utf-8 or byte string to the shader class.

I'd forgotten about that change in 4.2. I'm on Linux with free drivers, so I'm only on OpenGL 4.1 at the moment (although that should change real soon). This shouldn't be a big issue. I'm looking forward to playing with 4.2+ shaders at some point myself.

Petr Viktorin

unread,
Feb 17, 2016, 4:37:19 AM2/17/16
to pyglet...@googlegroups.com
On 02/17/2016 03:17 AM, Benjamin Moran wrote:
> Hi Petr,
>
> I agree about not requiring sending a byte string in Python 3. It's
> another small thing that could trip up new users, and should not be
> required for Python 3. For my current code I just do a quick encode on
> the string if it's not already a byte string, allowing you to pass
> either a utf-8 or byte string to the shader class.
>
> I'd forgotten about that change in 4.2. I'm on Linux with free drivers,
> so I'm only on OpenGL 4.1 at the moment (although that should change
> real soon). This shouldn't be a big issue. I'm looking forward to
> playing with 4.2+ shaders at some point myself.

Myself, I didn't know about the change at all, before I went hunting for
the relevant standard :)

Benjamin Moran

unread,
Feb 19, 2016, 5:53:47 AM2/19/16
to pyglet-users

As some of you probably already know, it's not possible to use the built-in pyglet.graphics.Batch() and vertex_lists with an OpenGL context that is later than 3.0.
(Due to deprecated OpenGL functions that are used by those classes, such as "glPushClientAttrib").

My question is whether or not it makes sense to limit shader support to GLSL 1.30 (OpenGL 3.0 GLSL), in order to allow Batch usage? GLSL 130 shaders and Batch drawing does work together, but I've never mixed it this way before.

Idealy the Batch class could be modernized to take advantage of OpenGL 3.2+ when such a context is available, but that's a bit beyond my current understanding.

Any feedback welcome!
-Ben

Tristam MacDonald

unread,
Feb 19, 2016, 10:06:05 AM2/19/16
to pyglet-users
It's worth documenting, it I wouldn't intentionally limit the version. Upgrading batch to work with modern OpenGL is a reasonable priority - on Mac today your choice is OpenGL 2.0 or 4.2 (there is no way to allocate a context between those two versions), so batch is basically useless.
--
You received this message because you are subscribed to the Google Groups "pyglet-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyglet-users...@googlegroups.com.
To post to this group, send email to pyglet...@googlegroups.com.

Serdar Yegulalp

unread,
Feb 19, 2016, 10:25:50 AM2/19/16
to pyglet-users
I'd go with modernizing batch support first if possible, since that would be far more broadly useful, with shader support to follow afterwards.

Perhaps there's a way to have pre- and post-3.0 Batch usage supported side-by-side; you select which one you want by way of the window creation options.

Benjamin Moran

unread,
Feb 19, 2016, 11:38:32 PM2/19/16
to pyglet-users
Tristam,  Serdar,

Thanks, I forgot about the Mac OpenGL situation. Modernizing the batch class really is starting to look like a necessity.

There are other bits that need modernizing as well, such as some of the Window class methods. Window.on_resize, for example, uses classic glMatrixMode calls. Currently this needs to be over-ridden when using a higher version context. At the least:

@window.event
def on_resize(w, h):
return pyglet.event.EVENT_HANDLED

This is not ideal for users, so It would make sense for the Window class to have something like a "self._is_core_profile = True" flag. To go along with that, a very basic pass-through vertex/fragment shader pair for 2D projection (to mimic the current default window projection). The methods could be different depending on the context the Window is created with. Maybe supplying a custom shader would automatically override the default Window methods?

A seems like a good plan of attack would be:
1. Get a shader class finished that can compile/link shaders, and expose their attributes/uniforms.
2. Update the Window class with basic 2D shader and methods.
3. Update the Batch class.

I'm realizing this is a lot of work.I would just handle these things manually in my own application, but pyglet really does need to be updated at some point.

Serdar Yegulalp

unread,
Feb 20, 2016, 4:35:06 PM2/20/16
to pyglet-users
I'm happy to try and test things out in my own apps as the changes are rolled in. I've got 3-4 apps using Pyglet now that would make a good test bed for this sort of thing. Things do work in the meantime, but I agree that modernizing iks going to be the way to go.

I think it would make sense to have some kind of default shader that is passed on window creation which can be overridden, or toggled off entirely. I have one app in the making that uses multiple shaders -- some for 2D (for color-cycling effects, etc.), some for 3D, so being able to override something like that would be a must.

Benjamin Moran

unread,
Feb 26, 2016, 10:59:30 PM2/26/16
to pyglet-users
Hi guys,

I have a ShaderProgram class in a working state, which supports only vertex/fragment shader programs for a first step. OpenGL 3.0 and 4.1 contexts work, and it's Py2/3 compatible.
 
Currently there is code in there to create a VBO and VBA, which should be moved out eventually. It currently only works by feeding it vertex data from a ctypes.Structure, so it's not exactly user friendly at the moment.

My next step is to work on pyglet.graphics.vertex_list, and see if I can enhance it to create vertex lists that are compatible with the OpenGL core profile. Basically, just to be able to feed it vertex data and display some shapes without ctypes. Once I get this going I'll post a link to my fork and ask for feedback/assistance.

Benjamin Moran

unread,
Mar 6, 2016, 10:47:48 PM3/6/16
to pyglet-users
I've been a little busy, so I figured I'd share the simple shader program class I wrote a week or two ago. I've been mostly poking around with the rest of the graphics module these days, which is quite a beast (but impressive piece of software!). The shader code can be found in this branch:
https://bitbucket.org/treehousegames/pyglet/src?at=shader_class
There is a new pyglet.graphics.shader.py file, and a new examples/opengl_core.py file.

It's already "useable" if you want to feed it your own ctypes.Structure's, but idealy support will need to be added to the existing vertex_lists and VBO classes.

shader.py is obviously not finished code, but I would appreciate any comments on the general layout and structure of it. Does it make sense to have the shader programs compile and link as they do, in the __init__ section? Are there any glaring omissions?  The VAO stuff in specific is going to need to be handled in the general graphics module, but maybe it would also make sense to have some simple methods to handle that in the shader class.

Thanks everyone.

Serdar Yegulalp

unread,
Mar 8, 2016, 10:37:23 AM3/8/16
to pyglet-users
Hi, Benjamin - I can't find the shader class you're talking about. Can you link directly to it in your repository?

Benjamin Moran

unread,
Mar 8, 2016, 8:27:43 PM3/8/16
to pyglet-users
Hi Serdar,

Give this link a try. It should take you to the "shader_class" branch:
https://bitbucket.org/treehousegames/pyglet/src/e9cb1eb0c7492e681b4bc98035ab260f73498b5b/?at=shader_class

The two new files are located in:
/pyglet/graphics/shader.py
and
/examples/opengl_core.py

-Ben

Serdar Yegulalp

unread,
Mar 17, 2016, 3:58:03 PM3/17/16
to pyglet-users
Sorry, forgot to mention I'll be giving this a quick shot in the next couple of weeks. Life got busy! But I do want to try it out along with the beta of the new Pyglet build.

Benjamin Moran

unread,
Mar 18, 2016, 11:37:53 PM3/18/16
to pyglet-users
No problem. I'd appreciate any feedback.

Aiden Ward

unread,
Apr 20, 2016, 12:12:09 AM4/20/16
to pyglet-users
i need help getting shaders to work in pyglet.

did you get this working in python 3?

shader_program = Program(vertex_source, fragment_source)

with shader_program:
    do_stuff
()

Benjamin Moran

unread,
Apr 20, 2016, 5:34:49 AM4/20/16
to pyglet-users
Hi Aiden,

Yes, compiling a shader works fine in Python 3. You can check out my shader branch here:
https://bitbucket.org/treehousegames/pyglet/src/196e5086a04cbedd4bab9d47c8ae8361f7040d23/?at=shader_class
Also, If you look in the root of that directory, you will see a lab.py file with an example of creating an OpenGL 3.3 context and some dead simple GLSL 3.3 vert/frag shaders. It works just fine with an OpenGL 4.x context and shaders as well. If you are using an OpenGL core profile, you MUST override the window.on_resize() method as shown in the lab.py file, otherwise your program will crash due to some legacy OpenGL code being called.

The shader library itself is located inside the graphics module, at pyglet/graphics/shader.py.
You can either use it as a context manager, using the "with" statement (like you were asking about), or you can use it's .stop_progam() and .use_program() methods.

It works fine as it is, but I'm really looking for feedback on it. I'd appreciate it if you could let me know how it works out for you, or why it doesn't.

-Ben
Reply all
Reply to author
Forward
0 new messages