Shaders and FBOs

General discussion about LÖVE, Lua, game development, puns, and unicorns.

Shaders and FBOs

Postby vrld on Mon Jun 07, 2010 9:00 pm

Warning: Much text ahead. TL;DR: SHADERS, WOHOO!

If you are like me, you just have waited for this to happen:
I added GLSL shaders and Framebuffer Objects to LÖVE!

If you - on the other hand - wonder what I am talking about, let me explain what these two can do for you.
With shaders you can run code directly on you graphics hardware. There are two kinds (ok, three, but the third is bleeding edge and stuff) of shaders, vertex shaders and fragment shaders. Basically, a vertex shader can be used to modify vertices, i.e. move stuff around, rotate it and so on.
The fragment shader works on pixels and can be used to implement color keying (setting one color to transparent), blur, edge detection and so on.
Both are needed for a shader program, but I will explain that later.

A Framebuffer Object (FBO) is kind of a virtual screen that gets rendered to. After you've finished rendering to the FBO, you can draw it's content anywhere else. This can be used to create surveillance cameras or (the more popular) portals known from Portal and Prey. Technically, a FBO can do much more, but this is what it is used most for.

In combination, the FBO and shaders can be used to apply postprocessing like motion blur and HDR rendering.

I tested my patch with the sourcecode in the mercurial repository, but I think it should also work with 0.6.2. When compiling this, you also have to add these lines in the right place to src/Makefile.am:
Code: Select all
./modules/graphics/opengl/Fbo.cpp \
./modules/graphics/opengl/Fbo.h \
./modules/graphics/opengl/wrap_Fbo.cpp \
./modules/graphics/opengl/wrap_Fbo.h \
./modules/graphics/opengl/Program.cpp \
./modules/graphics/opengl/Program.h \
./modules/graphics/opengl/wrap_Program.cpp \
./modules/graphics/opengl/wrap_Program.h \
./modules/graphics/opengl/Shader.cpp \
./modules/graphics/opengl/Shader.h \
./modules/graphics/opengl/wrap_Shader.cpp \
./modules/graphics/opengl/wrap_Shader.h \
and then run automagic again.

The interface is as following:

Shaders
love.graphics.newShader(type, code)
Creates a new shader of type type with given GLSL sourcecode.
Type may be 'vertex' to create a vertex shader or 'fragment' to create a fragment shader.
Returns: The newly created and compiled shader.

shader:infolog()
Returns: A string with compilation messages.

love.graphics.newProgram()
Creates a new Shader Program. A Program consists of at least one fragment and one vertex shader.
After attaching several shaders, the program needs to be linked, before it can be used. OpenGL requires so, sorry.
Returns: A fresh shader program.

program:attachShader(...)
Attach one or more shaders to the program. Arguments must be Shader objects created by love.graphics.newShader.
Returns: Nothing.

program:link()
Links the program so it can be used in renderings. Linker errors can be requested with program:infolog()
Returns: True on success, false otherwise.

program:infolog()
Most useful to recover from a failed program:link.
Returns: A string with linker messages.

program:use()
Uses a program for rendering between until program:unuse() is called.
Returns: Nothing.

program:unuse()
Stops using a program for rendering.
Returns: Nothing.

FBOs
love.graphics.newFbo(width, height)
Creates a new FBO with width and height. Most usually width and height are those of your game window.
Will create a cryptic error message on failure.
Returns: The FBO. A drawable.

love.graphics.draw(fbo, ...)
Same as the function you know. FBO is a drawable (as said above).

fbo:render(function)
Render stuff into the fbo. function contains the code that renders.
Returns: Nothing.

fbo:bind() and fbo:unbind()
If you prefer to do things that are done by fbo:render() yourself, use fbo:bind() before and fbo:unbind() after drawing to the buffer.
Returns: Nothing.

Any chance that gets into the next version of LÖVE? :ultrahappy:
-vrld

ps: I only tested this on Linux, since I don't own a Mac or a copy of Windows. Anyone cares to test it?

Edit: Patch moved to this post
Last edited by vrld on Mon Jun 28, 2010 8:09 pm, edited 5 times in total.
When I was a kid I used to pray every night for a new bicycle. Then I realised God doesn’t work that way, so I stole one and prayed for forgiveness.
hump Helper Utilities for Massive Productivity | HardonCollider Collision detection | Quickie Easy GUI Library
User avatar
vrld
Party member
 
Posts: 834
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany

Re: Shaders and FBOs

Postby thelinx on Mon Jun 07, 2010 9:03 pm

Image
User avatar
thelinx
The Strongest
 
Posts: 844
Joined: Fri Sep 26, 2008 3:56 pm
Location: Sweden

Re: Shaders and FBOs

Postby Luiji on Mon Jun 07, 2010 9:04 pm

awesome
Good bye.
User avatar
Luiji
Party member
 
Posts: 396
Joined: Mon May 17, 2010 6:59 pm

Re: Shaders and FBOs

Postby Jasoco on Tue Jun 08, 2010 3:51 am

So, any way us non compiling normal Löve using people can try it? Also.. what is a shader? Can you take a screenshot of an example?
Love.filesystem.enumerate is a very serious problem in our lives, we need to understand the problem about Love.filesystem.enumerate. We can discuss how to make it work, to avoid the inconvenience of our lives. -- Some Spambot
User avatar
Jasoco
Inner party member
 
Posts: 2840
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA

Re: Shaders and FBOs

Postby Robin on Tue Jun 08, 2010 5:58 am

Mucho interesting.

Code: Select all
program:use()
Uses a program for rendering between until program:unuse() is called.
Returns: Nothing.

program:use()
Stops using a program for rendering.
Returns: Nothing.

program:use()
Use a program for rendering between until program:unuse() is called.
Returns: Nothing.

Waitwhat?
Help us help you: attach a .love.
User avatar
Robin
The Omniscient
 
Posts: 6078
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands

Re: Shaders and FBOs

Postby Geti on Tue Jun 08, 2010 6:40 am

Wait holy shit, do want. I'll try this soon, hopefully once this week is out. Fucking A+, no more hating love.graphics.newScreenshot() and it's uselessness for this ;)
Geti
Party member
 
Posts: 112
Joined: Tue Oct 20, 2009 6:38 am

Re: Shaders and FBOs

Postby vrld on Tue Jun 08, 2010 6:49 am

Robin wrote:Waitwhat?
Whoops... Changed ;)

I will post Screenshots and sample code as soon as I am home again.
When I was a kid I used to pray every night for a new bicycle. Then I realised God doesn’t work that way, so I stole one and prayed for forgiveness.
hump Helper Utilities for Massive Productivity | HardonCollider Collision detection | Quickie Easy GUI Library
User avatar
vrld
Party member
 
Posts: 834
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany

Re: Shaders and FBOs

Postby pekka on Tue Jun 08, 2010 7:58 am

Jasoco wrote: Also.. what is a shader?


tl;dr: A shader will let you draw graphics in new neat ways that were not previously practical.

It's a program written in a special language called GLSL (GL Shading Language) that either

a) runs every time a vertex is drawn (a vertex shader)
b) runs every time a pixel is drawn (a fragment shader)

Vertices are essentially coordinate positions that make up the different geometrical shapes we use. For example, using four vertices you can define a quad, since it has four corners. There is a technical difference between pixels and fragments that I won't go into here, but they're close enough. It's actually also not correct to say things are drawn here, but I don't want to write out a full explanation of the OpenGL rendering pipeline. Let's just say these things allow you to modify where and how things are drawn in various limited but highly useful ways.

You need an implementation of OpenGL 2.0 or possiby newer(?) to use them. Pretty much all modern graphics cards can do this, but people with ancient computers using software GL renderers might be out of luck. The shader programs make good use of the modern hardware's capabilities to run fast.

The simplest way to use them in LOVE will be to wait for someone else to write some good shaders and then just plug them into your own program. I'm sure that if this becomes part of LOVE, people will start writing and publishing all kinds of neat shader programs in no time. So, the lazy person's option will be just to wait and see waht people do with these :)

You can find plenty of demonstrations on the net with search terms such as OpenGL + Shader. One of the first hits I got was this gallery:

http://www.clockworkcoders.com/oglsl/gallery.htm

EDIT: I won't be compiling a Windows version, since it is too much trouble to set up the libraries and the tools given that I don't normally program for windows, but I'll try it on Linux sooner or later.
pekka
Party member
 
Posts: 206
Joined: Thu Jan 07, 2010 6:48 am
Location: Oulu, Finland

Re: Shaders and FBOs

Postby vrld on Tue Jun 08, 2010 6:53 pm

As promised, some examples and screenshots. I took the particle demo and changed the following:

Code: Select all
function love.load()
[...]
    fbo = love.graphics.newFbo(love.graphics.getWidth(), love.graphics.getHeight())

    local vs = love.graphics.newShader('vertex', love.filesystem.read("null.vertex.glsl"))
    local function makeProgram(fs_source)
        local program = love.graphics.newProgram()
        local fs = love.graphics.newShader('fragment', love.filesystem.read(fs_source))
        program:attachShader(vs, fs)
        program:link()
        return program
    end
    programs = {}
    programs.null   = makeProgram("null.fragment.glsl")
    programs.invert = makeProgram("invert.fragment.glsl")
    programs.color  = makeProgram("color.fragment.glsl")
    programs.sobel  = makeProgram("sobel.fragment.glsl")
    programs.blur   = makeProgram("blur.fragment.glsl")
    programs.glow   = makeProgram("glow.fragment.glsl")
    program = programs.null
    programs.name = {
        [programs.null]   = "null",
        [programs.invert] = "invert",
        [programs.color]  = "color",
        [programs.sobel]  = "sobel",
        [programs.blur]   = "blur",
        [programs.glow]   = "glow",
    }
end

function love.draw()
    fbo:render(function()
    love.graphics.setColorMode("modulate")
    love.graphics.setBlendMode("additive")

        love.graphics.draw(systems[current], 0, 0)
        love.graphics.print("System: [" .. current .. "/"..table.getn(systems).."] - " .. systems[current]:count() .. " particles. Shader: " .. programs.name[program], 30, 570);
        love.graphics.print("Click: spawn particles. Mousewheel: change system.", 30, 530);
        love.graphics.print("Press escape to exit. n,i,c,s,b and g change Shaders.", 30, 550);
    end)

    program:use()
    love.graphics.setColor(255,255,255)
    love.graphics.draw(fbo, 0, 0)
    program:unuse()

    if program == programs.invert then
        love.graphics.setColor(0,0,0)
    end
    love.graphics.print("System: [" .. current .. "/"..table.getn(systems).."] - " .. systems[current]:count() .. " particles. Shader: " .. programs.name[program], 30, 570);
    love.graphics.print("Click: spawn particles. Mousewheel: change system.", 30, 530);
    love.graphics.print("Press escape to exit. n,i,c,s,b and g change Shaders.", 30, 550);
end

function love.keypressed(key)
    if key == "n" then
        program = programs.null
    elseif key == "i" then
        program = programs.invert
    elseif key == "c" then
        program = programs.color
    elseif key == "s" then
        program = programs.sobel
    elseif key == "b" then
        program = programs.blur
    elseif key == "g" then
        program = programs.glow
    end
[...]


All shaders are packed in particles.love. The invert shader for example looks like this:
Code: Select all
uniform sampler2D tex0;

void main(void)
{
    vec4 col = texture2D(tex0, gl_TexCoord[0].st);
    col[0] = 1.0 - col[0];
    col[1] = 1.0 - col[1];
    col[2] = 1.0 - col[2];
    gl_FragColor = col + gl_Color;
}
Attachments
color.png
color.png (80.1 KiB) Viewed 1864 times
invert.png
invert.png (191.1 KiB) Viewed 1864 times
null.png
null.png (65.05 KiB) Viewed 1864 times
When I was a kid I used to pray every night for a new bicycle. Then I realised God doesn’t work that way, so I stole one and prayed for forgiveness.
hump Helper Utilities for Massive Productivity | HardonCollider Collision detection | Quickie Easy GUI Library
User avatar
vrld
Party member
 
Posts: 834
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany

Re: Shaders and FBOs

Postby vrld on Tue Jun 08, 2010 6:53 pm

more screenshots
Attachments
glow.png
glow.png (54.11 KiB) Viewed 1864 times
blur.png
blur.png (123.87 KiB) Viewed 1864 times
sobel.png
sobel.png (127.09 KiB) Viewed 1864 times
When I was a kid I used to pray every night for a new bicycle. Then I realised God doesn’t work that way, so I stole one and prayed for forgiveness.
hump Helper Utilities for Massive Productivity | HardonCollider Collision detection | Quickie Easy GUI Library
User avatar
vrld
Party member
 
Posts: 834
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany

Next

Return to General

Who is online

Users browsing this forum: Bing [Bot], markgo and 4 guests