Lua Shader Examples

From GiderosMobile
Revision as of 02:32, 27 March 2025 by MoKaLux (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Parent: Writing 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

Gideros Effects Shaders

You can add these Effects Shader after those available in Gideros Lua Shader Examples (Lua Shader Gideros Examples).

To use them, simply add a Shader to a Sprite, for example:

local s = Pixel.new(256, 128, Texture.new("texture.jpg", false))
s:setShader(Effect.palette)

Effect.palette

-- cc0 @ https://godotshaders.com/shader/256-colour-pixelation/
Effect.palette = makeEffect("palette",
	function (vVertex, vColor, vTexCoord) : Shader
		local vertex = hF4(vVertex, 0.0, 1.0)
		fTexCoord = vTexCoord
		return vMatrix * vertex
	end,
	function () : Shader
		-- 0.100392156862 is the cube root of 255
		local rgb255 = lF3(0.100392156862, 0.100392156862, 0.100392156862)
		local tc = fTexCoord - fTextureInfo.zw
		local frag = lF4(fColor) * texture2D(fTexture, tc)
		if(frag.r < 1.0 and frag.g < 1.0 and frag.b < 1.0) then
			local remainder = mod(frag.rgb, rgb255)
			frag.rgb = frag.rgb - remainder
		end
		-- emphasize
		local e = 1.5 -- xemphasize
		frag.rgb = lF3(frag.r^e, frag.g^e, frag.b^e)
		if (frag.a == 0.0) then discard() end
		return frag
	end)

Effect.colour_pixelation

Effect.colour_pixelation = makeEffect("colour_pixelation",
	function (vVertex, vColor, vTexCoord) : Shader
		local vertex = hF4(vVertex, 0.0, 1.0)
		fTexCoord = vTexCoord
		return vMatrix * vertex
	end,
	function () : Shader
		local resX = 8*32 -- 8*32, 6*32, ...
		local resY = 8*32 -- 8*32, 6*32, ...
		-- 0.100392156862 is the cube root of 255
		local rgb255 = lF3(0.100392156862, 0.100392156862, 0.100392156862)
		local uvX = fTexCoord.x - mod(fTexCoord.x * resX, 1) / resX
		local uvY = fTexCoord.y - mod(fTexCoord.y * resY, 1) / resY
		local grid_uv = lF2(uvX, uvY)
		local frag = lF4(fColor) * texture2D(fTexture, grid_uv)
		if(frag.r < 1.0 and frag.g < 1.0 and frag.b < 1.0) then
			local remainder = mod(frag.rgb, rgb255)
			frag.rgb = frag.rgb - remainder
		end
		-- emphasize
--		local e = 0.7 -- xemphasize, 0.8, 1
--		frag.rgb = lF3(frag.r^e, frag.g^e, frag.b^e)
--		if (frag.a == 0.0) then discard() end

		return frag
	end)

Effect.outline

-- @rrraptor V1 luau -- 1px outline
Effect.outline = makeEffect("outline",
	function (vVertex, vColor, vTexCoord) : Shader
		local vertex = hF4(vVertex, 0.0, 1.0)
		fTexCoord = vTexCoord
		return vMatrix * vertex
	end,
	function () : Shader
		local outlinesize = 1.0 -- 1.0, 2.0
		local tc = fTexCoord - fTextureInfo.zw
		local original = lF4(fColor) * texture2D(fTexture, tc)
		if original.a == 0.0 then
			local step = 1.57079632679 -- math.pi/2 -- perfect for 1 to 2 pixels outline
			for theta = 0, 6.28318530718, step do -- 2 PI
				local offset = lF2(fTextureInfo.z * cos(theta) * outlinesize, fTextureInfo.w * sin(theta) * outlinesize)
				local frag = lF4(fColor) * texture2D(fTexture, tc+offset)
				if not (frag.a == 0.0) then original = lF4(0.0, 0.0, 0.0, frag.a) end -- change outline color here
			end
		end
		-- emphasize
		local e = 1
		original.rgb = lF3(original.r^e, original.g^e, original.b^e)
		if (original.a == 0.0) then discard() end

		return original
	end)

Effect.outline2

-- @rrraptor V1 -- thick pixel outline
Effect.outline2 = makeEffect("outline2",
	function (vVertex, vColor, vTexCoord) : Shader
		local vertex = hF4(vVertex, 0.0, 1.0)
		fTexCoord = vTexCoord
		return vMatrix * vertex
	end,
	function () : Shader
		local outlinesize = 1.0 -- 1.0, 2.0
		local tc = fTexCoord - fTextureInfo.zw
		local original = lF4(fColor) * texture2D(fTexture, tc)
		if original.a == 0.0 then
			for y = -1, 1 do
				for x = -1, 1 do
					local offset = lF2(fTextureInfo.z * x * outlinesize, fTextureInfo.w * y * outlinesize)
					local frag = lF4(fColor) * texture2D(fTexture, tc+offset)
					if not (frag.a == 0.0) then original = lF4(0.0, 0.0, 0.0, frag.a) end -- change outline color here
				end
			end
		end
		-- emphasize
		local e = 1
		original.rgb = lF3(original.r^e, original.g^e, original.b^e)
		if (original.a == 0.0) then discard() end

		return original
	end)

Effect.outline3 Colored

-- @rrraptor V1 -- thick pixel colored outline
Effect.outline3 = makeEffect("outline3",
	function (vVertex, vColor, vTexCoord) : Shader
		local vertex = hF4(vVertex, 0.0, 1.0)
		fTexCoord = vTexCoord
		return vMatrix * vertex
	end,
	function () : Shader
		local outlinesize = 1.0 -- 1.0, 2.0
		local tc = fTexCoord - fTextureInfo.zw
		local original = lF4(fColor) * texture2D(fTexture, tc)
		if original.a == 0.0 then
			local step = 1.57079632679 -- math.pi/2 -- perfect for 1 to 2 pixels outline
			for theta = 0, 6.28318530718, step do -- 2 PI
				local offset = lF2(fTextureInfo.z * cos(theta) * outlinesize, fTextureInfo.w * sin(theta) * outlinesize)
				local frag = lF4(fColor) * texture2D(fTexture, tc+offset)
				if not (frag.a == 0.0) then original = lF4(1.0, 1.0, 1.0, frag.a) end -- change outline color here
			end
		end
		-- emphasize
		local e = 1
		original.rgb = lF3(original.r^e, original.g^e, original.b^e)
		if (original.a == 0.0) then discard() end

		return original
	end)

Individual Shaders

Saturate

function vssaturate(vVertex, vColor, vTexCoord) : Shader
	local vertex = hF4(vVertex, 0.0, 1.0)
	fTexCoord = vTexCoord
	return vMatrix * vertex
end
function fssaturate() : Shader
	local frad = (1 + sin(fTime*7)) * 0.5
	local frag = lF4(fColor) * texture2D(fTexture, fTexCoord)
	local coef = lF3(0.2125, 0.7154, 0.0721)
	local dp = dot(frag.rgb, coef)
	if fSwitch == 22.0 then -- switched via lua code
		frag.rgb = mix(frag.rgb, frag.rgb / dp, frad)
	end
	if (frag.a == 0.0) then discard() end
	return frag
end

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="fSwitch", type=Shader.CFLOAT, vertex=false}, -- CFLOAT type to be more platforms compliant
	},
	{
	{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},
	}
)

-- bg color
application:setBackgroundColor(0x909090)
-- a texture and a bitmap
local tex = Texture.new("gfx/test.png")
local bmp = Bitmap.new(tex, true)
local bmp2 = bmp:clone()
-- position
bmp:setPosition(32*4, 32*4)
bmp2:setPosition(32*4, 32*8)
-- lua shader
bmp:setShader(saturate)
bmp2:setShader(saturate)
bmp:setShaderConstant("fSwitch", Shader.CFLOAT, 1, 22.0) -- switch is on
bmp2:setShaderConstant("fSwitch", Shader.CFLOAT, 1, -38.0) -- switch is off
-- order
stage:addChild(bmp)
stage:addChild(bmp2)

-- loop
stage:addEventListener(Event.ENTER_FRAME, function(e)
	bmp:setX(bmp:getX() + 0.5)
	if bmp:getX() > 400 then bmp:setX(-80) end
end)

Rain drops demo - by Hgy29

Rain drops shader effect

-- Custom shader for a plain colored pixel (BASIC PROGRAM)
local shader=StandardShaders:getShaderSpecification(Shader.SHADER_PROGRAM_BASIC)

-- We will need vertex position in fragment shader
function shader:vertexShader(vVertex,vColor,vTexCoord) : Shader
	local vertex = hF4(vVertex,0.0,1.0)
	fVertex=vVertex.xy
	return vMatrix*vertex
end

-- Fragment shader will compute caustics and ripples
function shader:fragmentShader() : Shader
	local tp = hF2(1.0/32.0,1.0/16.0)
	local mt = fVertex/1024.0
	local p = mod(mt*6.28, 6.28)-360.0
	local i = p
	local c = 1.0
	local inten = .005

	for n=1,3 do 
		local t = fTime*0.5 * (1.0 - (3.0 / hF1(n)))
		i = p + hF2(cos(t - i.x) + sin(t + i.y), sin(t - i.y) + cos(t + i.x))
		c += 1.0/length(hF2(p.x / (sin(i.x+t)/inten),p.y / (cos(i.y+t)/inten)))
	end
	for n=1,32 do
		local fr=fRippleT[n]
		if (fr>0.0) then
			local pd=length(fVertex-fRippleC[n])
			local rd=1.0-smoothstep(0.0,128.0,pd)
			if (rd>0.0) then
				local td=(fTime-fr)*10.0
				local dr=min(1.0,max(0.0,1.0-abs(td-(1.0-rd)*20.0)/10.0))
				c+=sin(rd*20.0+td)*rd*dr
			end
		end
	end
	c /= 3
	c = (1.5-c^.5)^4
	return lF4((hF4(c,c,c,1.0) + hF4(0.0, 0.3, 0.5, 1.0))*fColor)
end

-- Add our custom constants and inter-stage varibale
local NDROPS=32
table.insert(shader.uniforms,{name="fRippleC",type=Shader.CFLOAT2,vertex=false,mult=NDROPS})
table.insert(shader.uniforms,{name="fTime",type=Shader.CFLOAT,sys=Shader.SYS_TIMER,vertex=false})
table.insert(shader.uniforms,{name="fRippleT",type=Shader.CFLOAT,vertex=false,mult=NDROPS})
table.insert(shader.varying,{name="fVertex",type=Shader.CFLOAT2})

-- A plain blue screen wide Pixel with our shader
local ax,ay,aw,ah=application:getLogicalBounds()
local p=Pixel.new(0x5678CD,1,aw-ax,ah-ay) p:setPosition(ax,ay)
p:setShader(shader:build())
stage:addChild(p)

-- Main loop: create random rain drops
local drop=0
local dropsP,dropsT={},{}
for i=1,NDROPS do dropsP[i*2-1]=0 dropsP[i*2]=0 dropsT[i]=0 end
Core.asyncCall(function()
	while true do
		Core.yield(.05)
		drop+=1
		if drop==(NDROPS+1) then drop=1 end
		dropsP[drop*2-1]=math.random(aw-ax)
		dropsP[drop*2]=math.random(ah-ay)
		dropsT[drop]=os:timer()
		p:setShaderConstant("fRippleC",Shader.CFLOAT2,NDROPS,dropsP)
		p:setShaderConstant("fRippleT",Shader.CFLOAT,NDROPS,dropsT)
	end
end)