Available since LÖVE 0.9.0 |
It has been renamed from love.graphics.newPixelEffect. |
![]() |
This function can be slow if it is called repeatedly, such as from love.update or love.draw. If you need to use a specific resource often, create it once and store it somewhere it can be reused! |
Creates a new Shader object for hardware-accelerated vertex and pixel effects. A Shader contains either vertex shader code, pixel shader code, or both.
Shaders are small programs which are run on the graphics card when drawing. Vertex shaders are run once for each vertex (for example, an image has 4 vertices - one at each corner. A Mesh might have many more.) Pixel shaders are run once for each pixel on the screen which the drawn object touches. Pixel shader code is executed after all the object's vertices have been processed by the vertex shader.
shader = love.graphics.newShader( code )
string code
Shader shader
shader = love.graphics.newShader( pixelcode, vertexcode )
string pixelcode
string vertexcode
Shader shader
The pixelcode and vertexcode arguments can be in any order.
Shaders are not programmed in Lua, but by using a special shader language – GLSL, with a few aliases and a different entry point for convenience – instead. GLSL has very similar syntax to C. None of the aliases LÖVE provides are mandatory, but using Texel
instead of texture2D
is recommended since Texel
works in all glsl versions, whereas texture2D
does not work in GLSL 3.
GLSL | LÖVE shader language |
---|---|
sampler2D | Image |
sampler2DArray | ArrayImage |
samplerCube | CubeImage |
sampler3D | VolumeImage |
texture2D(tex, uv) (in GLSL 1) | Texel(tex, uv) |
texture(tex, uv) (in GLSL 3) | Texel(tex, uv) |
float | number (deprecated) |
uniform | extern (deprecated) |
The version of GLSL used depends on whether the #pragma language glsl3
line is added to the top of a shader file, as well as whether LÖVE is running on a desktop or mobile device:
LÖVE shader language | desktop GLSL version | mobile GLSL version |
---|---|---|
glsl1 (default) | GLSL 1.20 | GLSL ES 1.00 |
glsl3 | GLSL 3.30 | GLSL ES 3.00 |
GLSL 3 is not supported on some older systems. Use love.graphics.getSupported to check at run-time.
Vertex shader code must contain at least one function, named position
, which is the function that will produce transformed vertex positions of drawn objects in screen-space.
Pixel shader code must contain at least one function, named effect
, which is the function that will produce the color which is blended onto the screen for each pixel a drawn object touches.
LÖVE provides several useful Shader Variables by default. Additionally, LÖVE exposes a function VideoTexel(uv)
which yields the color value of the currently drawn video at that position. Since Videos are drawn as YUV data in multiple textures, and then converted in the shader, the Texel function cannot be used.
When an object is drawn, the pixel shader effect
function is called hundreds or thousands of times: once for each pixel on the screen that the object touches. The pixel shader is run after the vertex shader, if there is one.
vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )
vec4 color
Image tex
vec2 texture_coords
vec2 screen_coords
vec4 output_color
If no pixel shader is used, LÖVE internally uses a default. This is its code:
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { vec4 texturecolor = Texel(tex, texture_coords); return texturecolor * color; }
Or for Video
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { vec4 texturecolor = VideoTexel(texture_coords); return texturecolor * color; }
If multiple canvases are being rendered to simultaneously (by giving multiple Canvas parameters to love.graphics.setCanvas), you can use the void effect (no arguments!) function instead of vec4 effect in order to output a separate color to each Canvas. It has the following prototype:
void effect() { // love_Canvases is a writable array of vec4 colors. Each index corresponds to a Canvas. // IMPORTANT: If you don't assign a value to all active canvases, bad things will happen. love_Canvases[0] = color; love_Canvases[1] = color + vec4(0.5); // etc. }
If you wish to get the arguments that are passed to the single-canvas version (vec4 effect
), see the built-in Shader Variables.
color
will be in VaryingColor
, texture_coords
will be in VaryingTexCoord
and screen_coords
is in love_PixelCoord
.
And if you wish to access the texture used in the drawing operation, you can do that by defining a uniform texture (of the appropriate type) named MainTex
or by sending it yourself via Shader:send.
vec4 position( mat4 transform_projection, vec4 vertex_position )
mat4 transform_projection
vec4 vertex_position
vec4 output_pos
If no vertex shader code is used, LÖVE uses a default. This is its code:
vec4 position(mat4 transform_projection, vec4 vertex_position) { // The order of operations matters when doing matrix multiplication. return transform_projection * vertex_position; }
Vertex shader code is run for every vertex drawn to the screen (for example, love.graphics.rectangle will produce 4 vertices) and is used to transform the vertex positions from their original coordinates into screen-space, as well as to send information such as per-vertex color and texture coordinate values to the pixel shader.
Pixel shader code is run for every pixel on the screen that a drawn object touches, and is used to produce the color that will be blended onto the screen at that pixel, often by reading from an image. Pixel shaders are sometimes called fragment shaders.
The varying
keyword can be used to set a value in the vertex shader and have it interpolated in between vertices and passed down to the pixel shader.
Vertex and Pixel shader code can be combined into one file or string if you wrap the vertex-specific code in #ifdef VERTEX .. #endif
and the pixel-specific code in #ifdef PIXEL .. #endif
.
LÖVE provides several built-in variables for both pixel and vertex shaders. The full list can be found here: Shader Variables.
local pixelcode = [[ vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ) { vec4 texcolor = Texel(tex, texture_coords); return texcolor * color; } ]] local vertexcode = [[ vec4 position( mat4 transform_projection, vec4 vertex_position ) { return transform_projection * vertex_position; } ]] shader = love.graphics.newShader(pixelcode, vertexcode) function love.draw() love.graphics.setShader(shader) -- draw things love.graphics.setShader() -- draw more things end
varying vec4 vpos; vec4 position( mat4 transform_projection, vec4 vertex_position ) { vpos = vertex_position; return transform_projection * vertex_position; }
varying vec4 vpos; vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ) { texture_coords += vec2(cos(vpos.x), sin(vpos.y)); vec4 texcolor = Texel(tex, texture_coords); return texcolor * color; }
varying vec4 vpos; #ifdef VERTEX vec4 position( mat4 transform_projection, vec4 vertex_position ) { vpos = vertex_position; return transform_projection * vertex_position; } #endif #ifdef PIXEL vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords ) { texture_coords += vec2(cos(vpos.x), sin(vpos.y)); vec4 texcolor = Texel(tex, texture_coords); return texcolor * color; } #endif