Custom Shader Examples

From GiderosMobile

Parent: Writing Custom Shaders


Note: not all shaders will display correctly in html5

A Grey Shader

The code below defines a Grey shader consisting of:

  • mycshaders/vShaderGrey.glsl vertex shader
  • mycshaders/fShaderGrey.glsl fragment shader

Here the shader files are in the assets/mycshaders directory.

GLSL Vertex Shader: mycshaders/vShaderGrey.glsl

uniform highp mat4 vMatrix;
attribute highp vec3 vVertex;
attribute mediump vec2 vTexCoord;
varying mediump vec2 fTexCoord;

void main() {
	vec4 vertex = vec4(vVertex, 0.8); // vertex coords, scale
	gl_Position = vMatrix*vertex;
	fTexCoord = vTexCoord;
}

GLSL Fragment Shader: mycshaders/fShaderGrey.glsl

//precision highp float;
#ifdef GLES2
	precision highp float;
#endif
uniform lowp vec4 fColor;
uniform lowp sampler2D fTexture;
varying mediump vec2 fTexCoord;
 
void main() {
	lowp vec4 frag = fColor*texture2D(fTexture, fTexCoord);
	float color;
	if (frag.a == 0.0) {
		gl_FragColor = vec4(1.0, 0.5, 1.0, 1.0); // purple
	} else {
		color = dot(frag.rgb, vec3(0.299, 0.587, 0.114));
		gl_FragColor = vec4(color, color, color, frag.a); // gray
	}
}

Lua Code

-- open gl shader
local shadergrey = Shader.new("mycshaders/vShaderGrey", "mycshaders/fShaderGrey", 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="vVertex", type=Shader.DFLOAT, mult=3, 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},
	}
)

application:setBackgroundColor(0x333333)

local bitmap = Bitmap.new(Texture.new("gfx/test.png"))
local bitmap2 = Bitmap.new(Texture.new("gfx/arrow_0001.png"))
-- position
bitmap:setPosition(32*1, 32*4)
bitmap2:setPosition(32*6, 32*1)
-- shaders
bitmap:setShader(shadergrey)
bitmap2:setShader(shadergrey)
-- order
stage:addChild(bitmap)
stage:addChild(bitmap2)

A Wave Shader

The code below defines a Wave shader consisting of:

  • mycshaders/vShaderWave.glsl vertex shader
  • mycshaders/fShaderWave.glsl fragment shader

Here the shader files are in the assets/mycshaders directory.

GLSL Vertex Shader: mycshaders/vShaderWave.glsl

attribute vec4 POSITION0;
attribute vec2 TEXCOORD0;
uniform mat4 g_MVPMatrix;
varying vec2 texCoord;

void main()
{
	gl_Position = g_MVPMatrix * POSITION0;
	texCoord = TEXCOORD0;
}

GLSL Fragment Shader: mycshaders/fShaderWave.glsl

uniform lowp sampler2D g_Texture;
uniform lowp vec4 g_Color;
uniform highp float time;
varying highp vec2 texCoord;

void main()
{
	highp vec2 tc = texCoord.xy;
//	highp float dist = cos(tc.x * 24.0 - time * 4.0) * 0.02;
	highp float dist = cos(tc.x * 2.0 - time * 8.0) * 0.02;
	highp vec2 uv = tc + dist;
	gl_FragColor = g_Color * texture2D(g_Texture, uv);
}

Lua Code

-- open gl shader
local shaderwave = Shader.new("mycshaders/vShaderWave", "mycshaders/fShaderWave", 0,
	{
	{name="g_MVPMatrix", type=Shader.CMATRIX, sys=Shader.SYS_WVP, vertex=true},
	{name="g_Color", type=Shader.CFLOAT4, mult=1, sys=Shader.SYS_COLOR},
	{name="g_Texture", type=Shader.CTEXTURE, mult=1, vertex=false},
	{name="time", type=Shader.CFLOAT, mult=1, vertex=false}
	},
	{
	{name="POSITION0", type=Shader.DFLOAT, mult=3, slot=0, offset=0},
	{name="vColor", type=Shader.DUBYTE, mult=0, slot=1, offset=0},
	{name="TEXCOORD0", type=Shader.DFLOAT, mult=2, slot=2, offset=0}
	}
)

application:setBackgroundColor(0x333333)

local bitmap = Bitmap.new(Texture.new("gfx/test.png"))
local bitmap2 = bitmap:clone()
-- position
bitmap:setPosition(32*1, 32*4)
bitmap2:setPosition(32*6, 32*1)
-- shaders
bitmap:setShader(shaderwave)
bitmap2:setShader(shaderwave)
-- order
stage:addChild(bitmap)
stage:addChild(bitmap2)

-- loop
local timer = 0
stage:addEventListener(Event.ENTER_FRAME, function(e)
	timer += 0.018
	shaderwave:setConstant("time", Shader.CFLOAT, 1, timer)
	bitmap:setX(bitmap:getX() + 1)
	if bitmap:getX() > 400 then bitmap:setX(-80) end
end)

An Outline Shader FLAG_FROM_CODE

spriteOutline = {}

spriteOutline.VS_GL = [[

	uniform highp mat4 vMatrix;

	attribute highp vec3 vVertex;
	attribute mediump vec2 vTexCoord;

	varying mediump vec2 fTexCoord;

	void main() {
		vec4 vertex = vec4(vVertex, 1.0);
		gl_Position = vMatrix*vertex;
		fTexCoord = vTexCoord;
	}
]]

spriteOutline.FS_GL = [[

	#ifdef GL_ES
		precision highp float;
	#endif

	const float offseta = 0.010;

	uniform lowp vec4 fColor;
	uniform mediump vec4 fTexSize;
	uniform lowp sampler2D fTexture;

	uniform lowp int fSwitch;

	varying mediump vec2 fTexCoord;

	vec4 getSample(float x, float y, float offset, float num)
	{
		vec4 result = vec4(0);
		float size = 360.0 / num;

		for (float a; a <= 360.0; a += size)
		{
			vec2 coord = vec2(cos(a) * offset + x, sin(a) * offset + y);

			result += texture2D(fTexture, coord);
		}

		return result;
	}

	void main()
	{
		vec4 col = texture2D(fTexture, fTexCoord);

		float nums = 32.0;

		if (fSwitch == 44) // fSwitch can be changed in code, 44 is some random value for documentation purposes
		{
			vec4 nb = getSample(fTexCoord.x, fTexCoord.y, 0.020, nums);

			if (col.a > 0. && nb.a < nums)
			{
				col.a = nb.a / nums;
				col.r = nb.a / nums;
				col.g = 0.0;
				col.b = 0.0;
			}
		}

		gl_FragColor = col;
	}
]]

spriteOutline.Shader=Shader.new(spriteOutline.VS_GL, spriteOutline.FS_GL, Shader.FLAG_FROM_CODE,
	{
	{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="fSwitch",type=Shader.CINT,vertex=false},
	},
	{
	{name="vVertex",type=Shader.DFLOAT,mult=3,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},
	}
)

local sprite = Bitmap.new(Texture.new("gfx/test.png"))
--spriteOutline.Shader:setConstant("fSwitch", Shader.CINT, 1, 44) -- set fSwitch value to be 44
sprite:setShader(spriteOutline.Shader)
sprite:setShaderConstant("fSwitch", Shader.CINT, 1, 44) -- set fSwitch value to be 44
stage:addChild(sprite)

A Pulsing Effect Shader FLAG_FROM_CODE - by Hgy29

local shaderV=[[
attribute highp vec3 vVertex;
attribute mediump vec2 vTexCoord;
uniform highp mat4 vMatrix;
varying mediump vec2 fTexCoord;
 
void main() {
  vec4 vertex = vec4(vVertex,1.0);
  gl_Position = vMatrix*vertex;
  fTexCoord=vTexCoord;
}	
]]
 
local scanlinesF=[[
uniform lowp sampler2D fTexture;
varying mediump vec2 fTexCoord;
uniform mediump vec4 fTextureSize;
uniform mediump float fTime;
 
lowp vec3 hsv2rgb(vec3 c) {
  lowp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
  lowp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
  return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
 
void main() {
 mediump vec4 pixel=texture2D(fTexture, fTexCoord);
 mediump vec4 frag=pixel; 
 mediump vec2 centerDir=normalize((fTextureSize.xy/2.0-fTexCoord)/fTextureSize.xy)*fTextureSize.zw;
 for (int k=-5;k<=5;k++)
	frag=frag+texture2D(fTexture, fTexCoord-centerDir*float(k));
 frag=frag/12.0;
 if (frag.a<=0.0) discard;
 if (pixel.a>=1.0)
	gl_FragColor = pixel;
 else
	gl_FragColor = vec4(hsv2rgb(vec3(frag.a/2.0+fTime*2.0,0.7,1.0)),frag.a);
}
]]
 
local result,reply=pcall(Shader.new,shaderV,scanlinesF,Shader.FLAG_FROM_CODE,{
	{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="fTextureSize",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=3,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}, })
 
PulsingEffect=reply

application:setBackgroundColor(0x442200)
local mysprite = Bitmap.new(Texture.new("gfx/checkbox.png"))
local mysprite2 = Bitmap.new(Texture.new("gfx/clock_hand_h.png"))
local mysprite3 = Bitmap.new(Texture.new("gfx/clock_hand_m.png"))
local mysprite4 = Bitmap.new(Texture.new("gfx/test.png"))
-- position
mysprite:setPosition(32*6, 32*3.35)
mysprite2:setPosition(32*10, 32*2)
mysprite3:setPosition(32*14, 32*2)
mysprite4:setPosition(32*10, 32*8)
-- order
stage:addChild(mysprite)
stage:addChild(mysprite2)
stage:addChild(mysprite3)
stage:addChild(mysprite4)

if not result then
	print("Shader Compilation error:"..reply)
else
	mysprite:setShader(PulsingEffect)
	mysprite2:setShader(PulsingEffect)
	mysprite3:setShader(PulsingEffect)
	mysprite4:setShader(PulsingEffect)
end

Shadertoy Code Viewer (glsl)

This code reads Shadertoy shaders (no texture, no mouse). Simply replace the code in the local shadertoycode variable
https://www.shadertoy.com/view/MsjSW3
https://www.shadertoy.com/view/Xt2SDc
...
Full Shadertoy Gideros Viewer: https://forum.gideros.rocks/discussion/comment/66639#Comment_66639
Note: Shadertoy shaders are copyrighted

local function loadShader(xshader)
	local vs = [[
	attribute vec4 POSITION0;
	attribute vec2 TEXCOORD0;

	uniform mat4 g_MVPMatrix;

	varying vec2 fragCoord;
	varying vec2 texCoord;

	void main()
	{
		texCoord = TEXCOORD0;
		gl_Position = g_MVPMatrix * POSITION0;
	}
	]]
	
	local ps = [[
	#extension GL_OES_standard_derivatives : enable
	#extension GL_EXT_shader_texture_lod : enable

	vec4 texture2DGrad(sampler2D s, in vec2 uv, vec2 gx, vec2 gy) {
		return texture2D(s, uv);
	}

	vec4 texture2DLod(sampler2D s, in vec2 uv, in float lod) {
		return texture2D(s, uv);
	}

	uniform vec4      iResolution;				// viewport resolution (in pixels)
	uniform float     iGlobalTime;				// shader playback time (in seconds)
	uniform float     iTime;					// shader playback time (in seconds)
	uniform float     iTimeDelta;				// render time (in seconds)
	uniform int       iFrame;					// shader playback frame
	uniform float     iChannelTime[4];			// channel playback time (in seconds)
	uniform vec4      iMouse;					// mouse pixel coords. xy: current (if MLB down), zw: click
	uniform sampler2D iChannel0;				// input channel #0. XX = 2D/Cube
	uniform sampler2D iChannel1;				// input channel #1. XX = 2D/Cube
	uniform sampler2D iChannel2;				// input channel #2. XX = 2D/Cube
	uniform sampler2D iChannel3;				// input channel #3. XX = 2D/Cube
	uniform vec4      iDate;					// (year, month, day, time in seconds)
	uniform float     iSampleRate;				// sound sample rate (i.e., 44100)

	varying vec2 texCoord;
	varying vec2 fragCoord;

	#ifdef GL_ES
	precision mediump float;
	#endif

	]] .. xshader[1] .. [[

	void main() {
		vec4 color = vec4(0.0,0.0,0.0,1.0);
		mainImage(color, gl_FragCoord.xy);
		color.w = 1.0;
		gl_FragColor = color;
	}
	]]

	return Shader.new(vs, ps, Shader.FLAG_FROM_CODE,
		{
		{name="g_MVPMatrix",type=Shader.CMATRIX,sys=Shader.SYS_WVP, vertex=true},
		{name="g_Color",type=Shader.CFLOAT4,mult=1,sys=Shader.SYS_COLOR},
		
		{name="iResolution",type=Shader.CFLOAT4,mult=1,vertex=false},
		{name="iGlobalTime",type=Shader.CFLOAT,mult=1,vertex=false},
		{name="iTime",type=Shader.CFLOAT,mult=1,vertex=false},
		{name="iTimeDelta",type=Shader.CFLOAT,mult=1,vertex=false},
		{name="iFrame",type=Shader.CINT,mult=1,vertex=false},
		{name="iChannelTime",type=Shader.CFLOAT,mult=1,vertex=false},
		{name="iMouse",type=Shader.CFLOAT4,mult=1,vertex=false},
		{name="iDate",type=Shader.CFLOAT4,mult=1,vertex=false},
		{name="iSampleRate",type=Shader.CFLOAT,mult=1,vertex=false},
		{name="iChannel0",type=Shader.CTEXTURE,mult=1,vertex=false},
		{name="iChannel1",type=Shader.CTEXTURE,mult=1,vertex=false},
		{name="iChannel2",type=Shader.CTEXTURE,mult=1,vertex=false},
		{name="iChannel3",type=Shader.CTEXTURE,mult=1,vertex=false},
		},
		{
		{name="POSITION0",type=Shader.DFLOAT,mult=3,slot=0,offset=0},
		{name="vColor",type=Shader.DUBYTE,mult=0,slot=1,offset=0},
		{name="TEXCOORD0",type=Shader.DFLOAT,mult=2,slot=2,offset=0},
		}
	)
end

function Shadertoy(xcode, width, height)
	local effect = assert(loadShader(xcode))

	local sprite
	if application:getDeviceOrientation() == "Portrait" then
		sprite = Pixel.new(nil, width, height)
	else -- landscape
		sprite = Pixel.new(nil, height, width)
	end
	sprite:setShader(effect)

	local frame, time = 0, 0
	stage:addEventListener(Event.ENTER_FRAME, function(event)
		if xcapture then return end
		frame = frame + 1
		local t = time
		local d = os.date("*t")
		local s = d.hour * 3600 + d.min * 60 + d.sec
		effect:setConstant("iResolution", Shader.CFLOAT4, 1, width, height, 0, 0)
		effect:setConstant("iSampleRate", Shader.CFLOAT, 1, 44100)
		effect:setConstant("iGlobalTime", Shader.CFLOAT, 1, t)
		effect:setConstant("iTime", Shader.CFLOAT, 1, t)
		effect:setConstant("iTimeDelta", Shader.CFLOAT, 1, event.deltaTime)
		effect:setConstant("iFrame", Shader.CINT, 1, frame)
		effect:setConstant("iChannelTime", Shader.CFLOAT, 4, t, t, t, t)
		effect:setConstant("iDate", Shader.CFLOAT4, 1, d.year, d.month, d.day, s)
		time = time + event.deltaTime
	end)
	
	return sprite
end

local w, h = application:getDeviceWidth(), application:getDeviceHeight()
local shadertoycode = [[
// Ether by nimitz 2014 (twitter: @stormoid)
// https://www.shadertoy.com/view/MsjSW3
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// Contact the author for other licensing options

#define t iTime
mat2 m(float a){float c=cos(a), s=sin(a);return mat2(c,-s,s,c);}
float map(vec3 p){
    p.xz*= m(t*0.4);p.xy*= m(t*0.3);
    vec3 q = p*2.+t;
    return length(p+vec3(sin(t*0.7)))*log(length(p)+1.) + sin(q.x+sin(q.z+sin(q.y)))*0.5 - 1.;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord ){	
	vec2 p = fragCoord.xy/iResolution.y - vec2(.9,.5);
    vec3 cl = vec3(0.);
    float d = 2.5;
    for(int i=0; i<=5; i++)	{
		vec3 p = vec3(0,0,5.) + normalize(vec3(p, -1.))*d;
        float rz = map(p);
		float f =  clamp((rz - map(p+.1))*0.5, -.1, 1. );
        vec3 l = vec3(0.1,0.3,.4) + vec3(5., 2.5, 3.)*f;
        cl = cl*l + smoothstep(2.5, .0, rz)*.7*l;
		d += min(rz, 1.);
	}
    fragColor = vec4(cl, 1.);
}
]]
local ok, image
if application:getDeviceOrientation() == "Portrait" then
	ok, image = pcall(Shadertoy, {shadertoycode}, w, h)
else
	ok, image = pcall(Shadertoy, {shadertoycode}, h, w) -- landscape
end
if ok then stage:addChild(image) else image = nil print("shader error") end