Shaders and FBOs
Posted: 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: 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?
-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
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 \
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?
-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