Difference between revisions of "Writing Lua Shaders"

From GiderosMobile
 
(6 intermediate revisions by 2 users not shown)
Line 3: Line 3:
  
 
== Lua Shaders ==
 
== Lua Shaders ==
 +
'''Requirements''':
 +
'''In order to use Lua Shaders you need to include ''luashader'' standard library in your projects'''
 +
'''''luashader'' standard library is available in your Gideros installation folder under ''Library'''''
 
When you write your shaders in '''Lua''', they will be automatically translated to the relevant shader Language for the platform you are using (eg GLSL, HLSL or MSL). This is the '''recommended''' way to write your shaders in Gideros.
 
When you write your shaders in '''Lua''', they will be automatically translated to the relevant shader Language for the platform you are using (eg GLSL, HLSL or MSL). This is the '''recommended''' way to write your shaders in Gideros.
  
The [[Shader|Shader API]] allows the creation of Shader objects from within Lua. The '''''Shader.lua()''''' constructor like its counterpart custom ''Shader.new()'' takes five arguments:
+
The [[Shader|Shader API]] allows the creation of Shader objects from within Lua. The '''''Shader.lua()''''' constructor takes five arguments:
 
* the '''Vertex''' shader code (a lua function)
 
* the '''Vertex''' shader code (a lua function)
 
* the '''Fragment''' shader code (a lua function)
 
* the '''Fragment''' shader code (a lua function)
Line 11: Line 14:
 
* an array of [[Shader Uniform Descriptors|uniforms/constants descriptors]]
 
* an array of [[Shader Uniform Descriptors|uniforms/constants descriptors]]
 
* an array of [[Shader Attribute Descriptors|attributes descriptors]]
 
* an array of [[Shader Attribute Descriptors|attributes descriptors]]
 +
* an array of [[Shader Varying Descriptors|varying descriptors]]
  
 
With Lua Shaders, it is assumed that the code is within the '''Vertex''' and '''Fragment''' parameter functions.
 
With Lua Shaders, it is assumed that the code is within the '''Vertex''' and '''Fragment''' parameter functions.
Line 33: Line 37:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
Once both functions are created, instead of passing them in Shader.new you pass them in '''Shader.lua''':
+
Once both functions are created, you pass them in '''Shader.lua''':
 
<syntaxhighlight lang="lua">
 
<syntaxhighlight lang="lua">
 
local saturate = Shader.lua(vssaturate, fssaturate, 0,
 
local saturate = Shader.lua(vssaturate, fssaturate, 0,
Line 52: Line 56:
 
}
 
}
 
)
 
)
 +
</syntaxhighlight>
 +
 +
=== Working from a standard shader ===
 +
Gideros standard Sprites always use shaders internally, even if you don't supply your own. Rather than redefining everything, you can ask for a shader template, prefilled with definitions for default behavior, and override what you want.
 +
 +
<syntaxhighlight lang="lua">
 +
-- Custom shader for a plain colored pixel (BASIC PROGRAM)
 +
local shader=StandardShaders:getShaderSpecification(Shader.SHADER_PROGRAM_BASIC)
 +
-- Customized fragment shader
 +
function shader:fragmentShader() : Shader
 +
return lF4(1,0,0,1) -- Pure red for every pixel
 +
end
 +
 +
local p=Pixel.new(0x00FF00,1,30,30) -- Green pixel
 +
p:setPosition(20,20)
 +
p:setShader(shader:build()) -- Apply our customized shader
 +
stage:addChild(p)
 +
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
=== Changing Uniforms/Constants ===
 
=== Changing Uniforms/Constants ===
In order to change the value of a uniform from Lua, use the setConstant function, it takes three arguments:
+
In order to change the value of a uniform from Lua, you use the ''setConstant'' function on the Shader, it takes four arguments:
 
*the uniform name
 
*the uniform name
*the type of data to set (one of the Shader.Cxxx constants)
+
*the type of data to set: [[Shader Constants|one of the Shader.Cxxx constants]]
 +
*the number of elements of the given type to set (number)
 
*the actual data to set, either as a table or as multiple arguments
 
*the actual data to set, either as a table or as multiple arguments
 +
<syntaxhighlight lang="lua">
 +
saturate:setConstant("fSwitch", Shader.CINT, 1, 0) -- set fSwitch value to be 0 (off)
 +
</syntaxhighlight>
 +
 +
This will change the value of a Uniform for the whole Shader.
 +
 +
You can also change the value of a Uniform on a sprite to sprite basis using [[Sprite:setShaderConstant]]:
 +
<syntaxhighlight lang="lua">
 +
bmp:setShaderConstant("fSwitch", Shader.CINT, 1, 22) -- set fSwitch value to be 0 (on)
 +
</syntaxhighlight>
  
 
=== Associating a Shader to a Sprite ===
 
=== Associating a Shader to a Sprite ===
The Sprite API has a new call to deal with that: '''''Sprite:setShader(shader)''''' tells Gideros to use the specified shader for rendering the sprite. Setting back the shader to nil actually revert to the default shader.
+
The Sprite API has a new call to deal with that: '''''Sprite:setShader(shader)''''' tells Gideros to use the specified shader for rendering the sprite. Setting back the shader to '''''nil''''' actually revert to the default shader.
 +
<syntaxhighlight lang="lua">
 +
bmp:setShader(saturate)
 +
</syntaxhighlight>
  
 
=== Lua Shader Functions ===
 
=== Lua Shader Functions ===
Line 102: Line 138:
 
* Always check on all platforms: Gideros will translate your lua code to GLSL,HLSL or MSL code, but some platforms are more strict than others about what you can write, or how many arguments a common function is supposed to take
 
* Always check on all platforms: Gideros will translate your lua code to GLSL,HLSL or MSL code, but some platforms are more strict than others about what you can write, or how many arguments a common function is supposed to take
  
=== Lua Shaders Pebbles and Demos ===
+
=== Lua Shader Examples ===
'''[[Rain drops|Rain drops demo - by Hgy29]]'''</br>
+
'''[[Lua Shader Examples]]'''</br>
 +
 
 +
=== Further Reading ===
 +
OpenGL Shading Language: '''https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language'''</br>
 +
Common compatibility pitfalls: '''https://www.opengl.org/wiki/GLSL_:_common_mistakes'''</br>
 +
The Book of Shaders: '''https://thebookofshaders.com/'''</br>
 +
ShaderToy: '''https://www.shadertoy.com/'''</br>
 +
GH: '''https://github.com/mattdesl/lwjgl-basics/wiki/Shaders'''</br>
  
{{GIDEROS IMPORTANT LINKS}}
+
{{SHADERS}}

Latest revision as of 09:39, 15 November 2024

Parent: Shaders

Lua Shaders

Requirements:
In order to use Lua Shaders you need to include luashader standard library in your projects
luashader standard library is available in your Gideros installation folder under Library

When you write your shaders in Lua, they will be automatically translated to the relevant shader Language for the platform you are using (eg GLSL, HLSL or MSL). This is the recommended way to write your shaders in Gideros.

The Shader API allows the creation of Shader objects from within Lua. The Shader.lua() constructor takes five arguments:

With Lua Shaders, it is assumed that the code is within the Vertex and Fragment parameter functions.

A typical Lua Vertex and Fragment shader code looks like:

function vssaturate(vVertex, vColor, vTexCoord) : Shader -- Vertex Shader
	local vertex = hF4(vVertex, 0.0, 1.0)
	fTexCoord = vTexCoord
	return vMatrix * vertex
end

function fssaturate() : Shader -- Fragment Shader
	local frad = (1 + sin(fTime)) * 0.5
	local frag = lF4(fColor) * texture2D(fTexture, fTexCoord)
	local coef = lF3(0.2125, 0.7154, 0.0721)
	local dp = dot(frag.rgb, coef)
	frag.rgb = mix(frag.rgb, frag.rgb / dp, frad)
	if (frag.a == 0.0) then discard() end
	return frag
end

Once both functions are created, you pass them in Shader.lua:

local saturate = Shader.lua(vssaturate, fssaturate, 0,
	{
	{name = "vMatrix", type = Shader.CMATRIX, sys = Shader.SYS_WVP, vertex = true},
	{name = "fColor", type = Shader.CFLOAT4, sys = Shader.SYS_COLOR, vertex = false},
	{name = "fTexture", type = Shader.CTEXTURE, vertex = false},
	{name = "fTextureInfo", type = Shader.CFLOAT4, sys = Shader.SYS_TEXTUREINFO, vertex = false},
	{name = "fTime", type = Shader.CFLOAT, sys = Shader.SYS_TIMER, vertex = false},
	},
	{
	{name = "vVertex", type = Shader.DFLOAT, mult = 2, slot = 0, offset = 0},
	{name = "vColor", type = Shader.DUBYTE, mult = 4, slot = 1, offset = 0},
	{name = "vTexCoord", type = Shader.DFLOAT, mult = 2, slot = 2, offset = 0},
	},
	{
	{name = "fTexCoord", type = Shader.CFLOAT2},
	}
)

Working from a standard shader

Gideros standard Sprites always use shaders internally, even if you don't supply your own. Rather than redefining everything, you can ask for a shader template, prefilled with definitions for default behavior, and override what you want.

-- Custom shader for a plain colored pixel (BASIC PROGRAM)
local shader=StandardShaders:getShaderSpecification(Shader.SHADER_PROGRAM_BASIC)
-- Customized fragment shader
function shader:fragmentShader() : Shader
	return lF4(1,0,0,1) -- Pure red for every pixel
end

local p=Pixel.new(0x00FF00,1,30,30) -- Green pixel
p:setPosition(20,20)
p:setShader(shader:build()) -- Apply our customized shader
stage:addChild(p)

Changing Uniforms/Constants

In order to change the value of a uniform from Lua, you use the setConstant function on the Shader, it takes four arguments:

  • the uniform name
  • the type of data to set: one of the Shader.Cxxx constants
  • the number of elements of the given type to set (number)
  • the actual data to set, either as a table or as multiple arguments
saturate:setConstant("fSwitch", Shader.CINT, 1, 0) -- set fSwitch value to be 0 (off)

This will change the value of a Uniform for the whole Shader.

You can also change the value of a Uniform on a sprite to sprite basis using Sprite:setShaderConstant:

bmp:setShaderConstant("fSwitch", Shader.CINT, 1, 22) -- set fSwitch value to be 0 (on)

Associating a Shader to a Sprite

The Sprite API has a new call to deal with that: Sprite:setShader(shader) tells Gideros to use the specified shader for rendering the sprite. Setting back the shader to nil actually revert to the default shader.

bmp:setShader(saturate)

Lua Shader Functions

(Please note that these functions may or may not be available, the Lua shader is still under development)

Restrictions

Don't rely on anything external, basically no globals except for attributes, uniforms and varying.

  • No Do..While
  • No Repeat..Until
  • No tables. The only allowed form of table lookup is for vector component swizzling and access to uniform arrays
  • No strings, userdata, etc. Basically only numbers are supported
  • Mind your types! Although lua is not a typed language, shaders need types
  • Always check on all platforms: Gideros will translate your lua code to GLSL,HLSL or MSL code, but some platforms are more strict than others about what you can write, or how many arguments a common function is supposed to take

Lua Shader Examples

Lua Shader Examples

Further Reading

OpenGL Shading Language: https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language
Common compatibility pitfalls: https://www.opengl.org/wiki/GLSL_:_common_mistakes
The Book of Shaders: https://thebookofshaders.com/
ShaderToy: https://www.shadertoy.com/
GH: https://github.com/mattdesl/lwjgl-basics/wiki/Shaders