Difference between revisions of "love.graphics.newShader"

(Add some documentation about VideoTexel)
m (highp precision notice.)
 
(13 intermediate revisions by 3 users not shown)
Line 3: Line 3:
 
Creates a new Shader object for hardware-accelerated vertex and pixel effects. A Shader contains either vertex shader code, pixel shader code, or both.
 
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 video 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.
+
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.
  
 
== Function ==
 
== Function ==
Line 29: Line 29:
  
 
== Shader Language ==
 
== Shader Language ==
Shaders are not programmed in Lua, but by using a special shader language instead. The shader language is basically [http://www.opengl.org/sdk/docs/manglsl/ GLSL 1.20] ([http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf specs]) with a few aliases added for existing types:
+
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 <code>Texel</code> instead of <code>texture2D</code> is recommended since <code>Texel</code> works in all glsl versions, whereas <code>texture2D</code> does not work in GLSL 3.
  
 
{|cellpadding="5"
 
{|cellpadding="5"
 
!GLSL              || LÖVE shader language
 
!GLSL              || LÖVE shader language
 
|-
 
|-
|float              || number
+
|sampler2D          || Image
 
|-
 
|-
|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 <code>#pragma language glsl3</code> line is added to the top of a shader file, as well as whether LÖVE is running on a desktop or mobile device:
 +
 
 +
{|cellpadding="5"
 +
!LÖVE shader language || desktop GLSL version || mobile GLSL version
 
|-
 
|-
|uniform            || extern
+
|glsl1 (default)      || [http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf GLSL 1.20] || [https://www.khronos.org/files/opengles_shading_language.pdf GLSL ES 1.00]
 
|-
 
|-
|texture2D(tex, uv) || Texel(tex, uv)
+
|glsl3                    || [https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.3.30.pdf GLSL 3.30] || [https://www.khronos.org/registry/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf GLSL ES 3.00]
 
|}
 
|}
 +
 +
GLSL 3 is [[GraphicsFeature|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 <code>position</code>, which is the function that will produce transformed vertex positions of drawn objects in screen-space.
 
Vertex shader code must contain at least one function, named <code>position</code>, which is the function that will produce transformed vertex positions of drawn objects in screen-space.
Line 47: Line 69:
 
Pixel shader code must contain at least one function, named <code>effect</code>, which is the function that will produce the color which is blended onto the screen for each pixel a drawn object touches.
 
Pixel shader code must contain at least one function, named <code>effect</code>, which is the function that will produce the color which is blended onto the screen for each pixel a drawn object touches.
  
Additionally, LÖVE exposes a function <code>VideoTexel(uv)</code> 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.
+
LÖVE provides several useful [[Shader Variables]] by default. Additionally, LÖVE exposes a function <code>VideoTexel(uv)</code> 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.
  
 
== Pixel Shader Function ==
 
== Pixel Shader Function ==
Line 53: Line 75:
 
=== Synopsis ===
 
=== Synopsis ===
 
<source lang="glsl">
 
<source lang="glsl">
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
+
vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )
 
</source>
 
</source>
 
=== Arguments ===
 
=== Arguments ===
 
{{param|vec4|color|The drawing color set with [[love.graphics.setColor]] or the per-vertex [[Mesh]] color.}}
 
{{param|vec4|color|The drawing color set with [[love.graphics.setColor]] or the per-vertex [[Mesh]] color.}}
{{param|Image|texture|The texture of the image or canvas being drawn.}}
+
{{param|Image|tex|The texture of the image or canvas being drawn.}}
{{param|vec2|texture_coords|The location inside the texture to get pixel data from. Texture coordinates are usually normalized to the range of (0, 0) to (1, 1), with the top-left corner being (0, 0). (In LÖVE [[0.9.0]] y-axis of canvases are inverted.)}}
+
{{param|vec2|texture_coords|The location inside the texture to get pixel data from. Texture coordinates are usually normalized to the range of (0, 0) to (1, 1), with the top-left corner being (0, 0).}}
{{param|vec2|screen_coords|Coordinates of the pixel on the screen. Pixel coordinates are not normalized (unlike texture coordinates)}}
+
{{param|vec2|screen_coords|Coordinates of the pixel on the screen. Pixel coordinates are not normalized (unlike texture coordinates). (0.5, 0.5) represents the top left of the screen (bottom left in LÖVE versions prior to [[0.10.0]]).}}
  
 
=== Returns ===
 
=== Returns ===
 
{{param|vec4|output_color|The color of the pixel.}}
 
{{param|vec4|output_color|The color of the pixel.}}
 
=== Notes ===
 
=== Notes ===
 +
{{notice|On mobile devices, variables in pixel shaders use <code>mediump</code> (16 bit float) precision by default instead of 32 bit float, for performance reasons. This may cause numeric instability or visual artifacts for larger numbers. Use the <code>highp</code> qualifier when declaring a variable (for example <code>highp float pos;</code>) to make it use always 32 bit float precision. Furthermore, <code>highp</code> precision is not supported on all devices, particularly GLES2 devices. Use [[love.graphics.getSupported]] to check!}}
 
If no pixel shader is used, LÖVE internally uses a default. This is its code:
 
If no pixel shader is used, LÖVE internally uses a default. This is its code:
 
<source lang="glsl">
 
<source lang="glsl">
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords)
+
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords)
 
{
 
{
     vec4 texturecolor = Texel(texture, texture_coords);
+
     vec4 texturecolor = Texel(tex, texture_coords);
 
     return texturecolor * color;
 
     return texturecolor * color;
 
}
 
}
Line 75: Line 98:
 
Or for Video
 
Or for Video
 
<source lang="glsl">
 
<source lang="glsl">
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords)
+
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords)
 
{
 
{
 
     vec4 texturecolor = VideoTexel(texture_coords);
 
     vec4 texturecolor = VideoTexel(texture_coords);
Line 82: Line 105:
 
</source>
 
</source>
  
If multiple canvases are being rendered to simultaneously (by giving multiple Canvas parameters to [[love.graphics.setCanvas]]), you can use the '''effects''' function instead of '''effect''' in order to output a separate color to each Canvas. It has the following prototype:
+
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:
 
<source lang="glsl">
 
<source lang="glsl">
void effects(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords)
+
void effect()
 
{
 
{
     // love_Canvases is a writable array of vec4 colors. Each index corresponds to a Canvas. If you don't assign a value to all active canvases, bad things might happen.
+
     // 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[0] = color;
 
     love_Canvases[1] = color + vec4(0.5);
 
     love_Canvases[1] = color + vec4(0.5);
Line 92: Line 116:
 
}
 
}
 
</source>
 
</source>
 +
 +
If you wish to get the arguments that are passed to the single-canvas version (<code>vec4 effect</code>), see the built-in [[Shader Variables]].
 +
<code>color</code> will be in <code>VaryingColor</code>, <code>texture_coords</code> will be in <code>VaryingTexCoord</code> and <code>screen_coords</code> is in <code>love_PixelCoord</code>.
 +
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 <code>MainTex</code> or by sending it yourself via  [[Shader:send]].
  
 
== Vertex Shader Function ==
 
== Vertex Shader Function ==
Line 128: Line 156:
 
=== Create a shader using vertex and pixel shader code which behaves as if no shader is set. ===
 
=== Create a shader using vertex and pixel shader code which behaves as if no shader is set. ===
 
<source lang="lua">
 
<source lang="lua">
function love.load()
+
local pixelcode = [[
    local pixelcode = [[
+
    vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )
        vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
+
    {
        {
+
        vec4 texcolor = Texel(tex, texture_coords);
            vec4 texcolor = Texel(texture, texture_coords);
+
        return texcolor * color;
            return texcolor * color;
+
    }
        }
+
]]
    ]]
 
  
    local vertexcode = [[
+
local vertexcode = [[
        vec4 position( mat4 transform_projection, vec4 vertex_position )
+
    vec4 position( mat4 transform_projection, vec4 vertex_position )
        {
+
    {
            return transform_projection * vertex_position;
+
        return transform_projection * vertex_position;
        }
+
    }
    ]]
+
]]
  
    shader = love.graphics.newShader(pixelcode, vertexcode)
+
shader = love.graphics.newShader(pixelcode, vertexcode)
end
 
  
 
function love.draw()
 
function love.draw()
Line 170: Line 196:
 
varying vec4 vpos;
 
varying vec4 vpos;
  
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
+
vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )
 
{
 
{
 
     texture_coords += vec2(cos(vpos.x), sin(vpos.y));
 
     texture_coords += vec2(cos(vpos.x), sin(vpos.y));
     vec4 texcolor = Texel(texture, texture_coords);
+
     vec4 texcolor = Texel(tex, texture_coords);
 
     return texcolor * color;
 
     return texcolor * color;
 
}
 
}
Line 191: Line 217:
  
 
#ifdef PIXEL
 
#ifdef PIXEL
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
+
vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )
 
{
 
{
 
     texture_coords += vec2(cos(vpos.x), sin(vpos.y));
 
     texture_coords += vec2(cos(vpos.x), sin(vpos.y));
     vec4 texcolor = Texel(texture, texture_coords);
+
     vec4 texcolor = Texel(tex, texture_coords);
 
     return texcolor * color;
 
     return texcolor * color;
 
}
 
}

Latest revision as of 04:02, 14 February 2020

Available since LÖVE 0.9.0
It has been renamed from love.graphics.newPixelEffect.


O.png 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.

Function

Synopsis

shader = love.graphics.newShader( code )

Arguments

string code
The pixel shader or vertex shader code, or a filename pointing to a file with the code.

Returns

Shader shader
A Shader object for use in drawing operations.

Function

Synopsis

shader = love.graphics.newShader( pixelcode, vertexcode )

Arguments

string pixelcode
The pixel shader code, or a filename pointing to a file with the code.
string vertexcode
The vertex shader code, or a filename pointing to a file with the code.

Returns

Shader shader
A Shader object for use in drawing operations.

Notes

The pixelcode and vertexcode arguments can be in any order.

Shader Language

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.

Pixel Shader Function

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.

Synopsis

vec4 effect( vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords )

Arguments

vec4 color
The drawing color set with love.graphics.setColor or the per-vertex Mesh color.
Image tex
The texture of the image or canvas being drawn.
vec2 texture_coords
The location inside the texture to get pixel data from. Texture coordinates are usually normalized to the range of (0, 0) to (1, 1), with the top-left corner being (0, 0).
vec2 screen_coords
Coordinates of the pixel on the screen. Pixel coordinates are not normalized (unlike texture coordinates). (0.5, 0.5) represents the top left of the screen (bottom left in LÖVE versions prior to 0.10.0).

Returns

vec4 output_color
The color of the pixel.

Notes

O.png On mobile devices, variables in pixel shaders use mediump (16 bit float) precision by default instead of 32 bit float, for performance reasons. This may cause numeric instability or visual artifacts for larger numbers. Use the highp qualifier when declaring a variable (for example highp float pos;) to make it use always 32 bit float precision. Furthermore, highp precision is not supported on all devices, particularly GLES2 devices. Use love.graphics.getSupported to check!  


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.

Vertex Shader Function

Synopsis

vec4 position( mat4 transform_projection, vec4 vertex_position )

Arguments

mat4 transform_projection
The transformation matrix affected by love.graphics.translate and friends combined with the orthographic projection matrix.
vec4 vertex_position
The raw un-transformed position of the current vertex.

Returns

vec4 output_pos
The final transformed position of the current vertex.

Notes

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;
}

Notes

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.

Built-in variables

LÖVE provides several built-in variables for both pixel and vertex shaders. The full list can be found here: Shader Variables.

Examples

Create a shader using vertex and pixel shader code which behaves as if no shader is set.

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

Access the pre-transformed vertex position in the pixel shader with the varying keyword.

vertex shader code

varying vec4 vpos;

vec4 position( mat4 transform_projection, vec4 vertex_position )
{
    vpos = vertex_position;
    return transform_projection * vertex_position;
}

pixel shader code

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;
}

Combine the above example into one string or file with the help of #ifdef.

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

See Also


Other Languages