2d light effects

163 views
Skip to first unread message

Toke Ivø

unread,
Jun 21, 2018, 9:57:48 AM6/21/18
to pyglet-users
Hi there.

For a 2d game I'm creating, I wanted to add some colored lights.
I imagine this could be done the following way:

1) Render the background
---
2) Render the colored lights (sprites) to "layer 1"
3) Render every sprite in the foreground to "layer 2"
4) In combination with the use of gl.glBlendFunc(), render layer 2 on top of layer 1,
5) Render the result on top of the background.

However, when looking for a solution to this, I looked at Framebuffers and render-to-texture solutions. But none really worked - most likely due to my lack of experience with OpenGL.
Any good suggestions? Or code examples/resources, in case of a OpenGL solution?

Thanks

Neon22

unread,
Jun 21, 2018, 6:03:05 PM6/21/18
to pyglet-users
If you mean what's the general way people do this then I'd suggest examining the asteroids example. Use sprites and the order they are drawn is the order they will appear.
You could then look at Batches and Groups to see how to organise them efficiently like you refer to layers.

- https://pyglet.readthedocs.io/en/pyglet-1.3-maintenance/modules/graphics/index.html#batches-and-groups

On the other hand if you mean to change how the blend occurs then consider this:
99% of the time people use gl.glBlendFunc in this way:

pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
pyglet
.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)

to use the alpha in an image as a mask. but you want a different notion of blending where the colors mix.

There are many ways to do this.
The different options are in the table below but this page does not explain how to use them to get the effect you want.
This page does. Go crazy :)

- https://www.andersriggelsen.dk/glblendfunc.php

Swap the first and second args in the above code until you get what you need.
or read up on openGL blending functon here and make an informed choice:
- https://www.khronos.org/opengl/wiki/GlBlendFunc

you could start with:
pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
pyglet
.gl.glBlendFunc(pyglet.gl.GL_SRC_COLOR, pyglet.gl.GL_ONE_MINUS_SRC_COLOR)

or additive blending:
pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE

Toke Ivø

unread,
Jun 22, 2018, 5:23:17 AM6/22/18
to pyglet-users
Thanks. I should've explained myself better though.

Currently, I have two options (that I know about):

1) I can draw my light-sprites on a black background, then blend the foreground on top, so the dark parts of the screen is still dark.
    The problem with this, is that the foreground consists of many layered sprites (a tilemap, in a single batch, using OrderedGroups), and I don't know whether they'll overlap, or hit the "background" directly.
2) I can draw my light-sprites on top of the foreground, blending it so it darkens out the non-lit parts.
    The problem I'm having with this solution, is that I can't figure out how to dark out all the parts outside of the light-sprites.

In both cases, I'm assuming that the solution to my problem would be to merge either the foreground or the lights, (respectively to solve either 1 or 2), into a single world-sized image before blending it onto the other.

So, essentially, I'd like to draw my game, then "darken out" the inverse of a group of sprites.
It might be that there's some blending-setup that will just magically solve this problem. I just can't seem to figure out what that might be.

Neon22

unread,
Jun 22, 2018, 6:09:30 AM6/22/18
to pyglet-users
You could make your light sprites as larger than screen sized rectangles with a hole cut in the middle.
So the outer region would darken the screen and the hole would not.The alpha could cut the hole and the light could be a main RGB color.

Toke Ivø

unread,
Jun 25, 2018, 8:55:15 AM6/25/18
to pyglet-users
Thanks for the suggestion.
This might be the solution I go with, until I can figure out the "correct" solution.

Neon22

unread,
Jun 25, 2018, 4:47:36 PM6/25/18
to pyglet-users
The fastest way with the least waste is probably to create a rectangle shape the same size as the screen.
If your light is a circle or ellipse then draw it directly into the alpha channel and redraw it with the lighting tint color into the RGB. or it could itself be a sprite.
Then set the blend mode and blit it on

This way you don't have to deal with resource for a larger than canvas image and can insert it wherever you need it in the batch/group order.

Neon22

unread,
Jun 26, 2018, 7:08:47 AM6/26/18
to pyglet-users
Something like this but ran out of time to work the "blit_into" out and set the gl blend correctly.
Where the lightfile image is a soft edged circle (or whatever you need)

def build_light(w,h, x,y, lightfile, dark=128):
 
""" build a rect with light to blend over a BG
 - w,h are size of window,
 - x,y is position of the center of the light
 - dark is dimming factor outside light spill
 """

 
# create dim rectangle
 bg_pattern
= pyglet.image.SolidColorImagePattern((dark,dark,dark, 255))
 img
= pyglet.image.create(w,h, pattern=bg_pattern)
 
# add light
 light
= pyglet.image.load(lightfile)
 light
.anchor_x = img.width/2
 light
.anchor_y = img.height/2
 
# blit into img
 
#img.blit_into(light, x, y, 0)
 light
.blit_to_texture(img.get_texture, gl.GL_RGB, x, y,0)
 
return img

Toke Ivø

unread,
Jun 26, 2018, 7:27:14 AM6/26/18
to pyglet-users
Thanks!

This was actually exactly what I ended up doing.
Guess I'll just have to abandon the idea of pyglet sprites, and start learning some OpenGL :)

Neon22

unread,
Jun 26, 2018, 5:23:52 PM6/26/18
to pyglet-users
Actually I think it'd make a nice example to add. Do you mind sharing what you came up with and I'll coerce it into an example and submit it.

Its still all Sprite capable really. Certainly the light could/should be controlled as a Sprite. But instead of blitting it during a batch it gets manually blitted onto the img and then that gets inserted in the correct order (but probably always last under any UI elements).
Reply all
Reply to author
Forward
0 new messages