Shaders and FBOs

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Shaders and FBOs

Post by vrld »

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.
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
thelinx
The Strongest
Posts: 857
Joined: Fri Sep 26, 2008 3:56 pm
Location: Sweden

Re: Shaders and FBOs

Post by thelinx »

Image
User avatar
Luiji
Party member
Posts: 396
Joined: Mon May 17, 2010 6:59 pm

Re: Shaders and FBOs

Post by Luiji »

awesome
Good bye.
User avatar
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Shaders and FBOs

Post by Jasoco »

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?
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: Shaders and FBOs

Post by Robin »

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.
Geti
Party member
Posts: 112
Joined: Tue Oct 20, 2009 6:38 am

Re: Shaders and FBOs

Post by Geti »

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 ;)
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Shaders and FBOs

Post by vrld »

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

I will post Screenshots and sample code as soon as I am home again.
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
pekka
Party member
Posts: 206
Joined: Thu Jan 07, 2010 6:48 am
Location: Oulu, Finland
Contact:

Re: Shaders and FBOs

Post by pekka »

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.
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Shaders and FBOs

Post by vrld »

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 8408 times
invert.png
invert.png (191.1 KiB) Viewed 8408 times
null.png
null.png (65.05 KiB) Viewed 8408 times
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
User avatar
vrld
Party member
Posts: 917
Joined: Sun Apr 04, 2010 9:14 pm
Location: Germany
Contact:

Re: Shaders and FBOs

Post by vrld »

more screenshots
Attachments
glow.png
glow.png (54.11 KiB) Viewed 8408 times
blur.png
blur.png (123.87 KiB) Viewed 8408 times
sobel.png
sobel.png (127.09 KiB) Viewed 8408 times
I have come here to chew bubblegum and kick ass... and I'm all out of bubblegum.

hump | HC | SUIT | moonshine
Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests