Share a Shader!

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
Nuthen224
Citizen
Posts: 50
Joined: Sun Jul 28, 2013 9:40 pm

Re: Share a Shader!

Post by Nuthen224 »

4aiman, I think you would want to draw those things to a canvas first. Then apply the shader as you draw the canvas to the screen.
User avatar
rmcode
Party member
Posts: 454
Joined: Tue Jul 15, 2014 12:04 pm
Location: Germany
Contact:

Re: Share a Shader!

Post by rmcode »

4aiman wrote:It may be a little off-topic, but this thread has so many people sharing their shaders...

So, the question is: is there a way to somehow grab what was drawn so far and apply a shader to that?
I've tried using shine (and it worked ok) but failed to understand how to make it respect all my scale() and transform().
You could render the scene to a canvas and then send the canvas to the shader. IIRC that's what I've done in Bomb Dodgers (shameless plug). It allowed me to apply two shaders: One to switch the palette and one to use a wave-transformation on the level previews.
User avatar
4aiman
Party member
Posts: 262
Joined: Sat Jan 16, 2016 10:30 am

Re: Share a Shader!

Post by 4aiman »

Thanks! I'll try ^_^
User avatar
Sheepolution
Party member
Posts: 264
Joined: Mon Mar 04, 2013 9:31 am
Location: The Netherlands
Contact:

Re: Share a Shader!

Post by Sheepolution »

Code: Select all

local list = {
	noise = {
		body = [[
			p += rand(p, noise_rnd)/(1000/noise_amount);
			finTex = Texel(tex, p);
		]], externs = {amount = 10, rnd = 1}, funcs = {"rand"}},

	waves = {
		body = [[
			p.x += sin(p.y*waves_amount+waves_time*6)*0.03;
			finTex = Texel(tex, p);
		]], externs = {time = 0, amount = 5}},

	bulge = {
		body = [[
			np = vec2(p.x - bulge_pos.x, p.y - bulge_pos.y);
			a = length(np);
			b = atan(np.y, np.x);
			a = (a*a);
			np = a * vec2(cos(b), sin(b));
			p = np + bulge_pos;
			finTex = Texel(tex, p);
		]], externs = {pos = {0.5,0.5}}},

	pinch = {
		body = [[
			np = vec2(p.x - pinch_pos.x, p.y - pinch_pos.y);
			a = length(np);
			b = atan(np.y, np.x);
			a = sqrt(a);
			np = a * vec2(cos(b), sin(b));
			p = np + pinch_pos;
			finTex = Texel(tex, p);
		]], externs = {pos = {0.5,0.5}}},

	pixel = {
		body = [[
			p = floor(p*(100/pixel_amount))/(100/pixel_amount);
			finTex = Texel(tex, p);
		]], externs = {amount = 4}},

	sucker = {
		body = [[
			a = atan(sucker_pos.x - p.y, sucker_pos.y - p.x);
			p += -vec2(cos(a)/(100/(sucker_amount*sucker_amount)), sin(a)/(100/(sucker_amount*sucker_amount)));
			finTex = Texel(tex, p);
		]], externs = {amount = 1, pos = {0.5, 0.5} }},
	insidespin = {
		body = [[
			a = atan(0.5 - p.y, 0.5 - p.x);
			p += vec2(cos(a)/insidespin_amount, sin(a)/insidespin_amount);
			finTex = Texel(tex, p);
		]], externs = {amount = 1}},
	curve = {
		body = [[
			a = abs(p.x - 0.5);
			p.y -= (a*a)*3;
			p.x += (p.x > 0.5 ? a : -a)*(p.y/2);
			finTex = Texel(tex, p);
		]], externs = {}},
	rgb  = {
		body = [[
			a = 0.0025 * rgb_amount;
			finTex.r = 	texture2D(tex, vec2(p.x + a * rgb_dirs[0], p.y + a * rgb_dirs[1])).r;
			finTex.g = texture2D(tex, vec2(p.x + a * rgb_dirs[2], p.y + a * rgb_dirs[3])).g;
			finTex.b = 	texture2D(tex, vec2(p.x + a * rgb_dirs[4], p.y + a * rgb_dirs[5])).b;
		]], externs = {dirs = {1,0,0,1,-1,-1}, amount = 3}},

	tvnoise = {
		body = [[
			finTex.r -= -tvnoise_light + 1 + rand(p, tvnoise_rnd);
			finTex.g -= -tvnoise_light + 1 + rand(p, tvnoise_rnd);
			finTex.b -= -tvnoise_light + 1 + rand(p, tvnoise_rnd);
		]], externs = {light = 1, rnd = 1}, funcs = {"rand"}},
	invert = {
		body = [[
			finTex.r = 1-finTex.r;
			finTex.g = 1-finTex.g;
			finTex.b = 1-finTex.b;
		]], externs = {}},
	distortion = {
		body = [[
			finTex.r = (sin(finTex.r * distortion_amount) + 1.) * .5;
			finTex.g = (sin(finTex.g * distortion_amount) + 1.) * .5;
			finTex.b = (sin(finTex.b * distortion_amount) + 1.) * .5;
		]], externs = {amount = 20}, funcs = {"wave"}},
	spinsucker = {
		body = [[
			a = atan(p.y - 0.5, 0.5 - p.x);
			p.x += sin(a) * spinsucker_amount;
			p.y += cos(a) * spinsucker_amount;
			finTex = Texel(tex, p);
		]], externs = {amount = 1}},
	circle = {
		body = [[
			a = sqrt(abs(p.x - circle_pos[0])*abs(p.x - circle_pos[0]) + abs(p.y - circle_pos[1])*abs(p.y - circle_pos[1]));
			if (circle_soft) {
				finTex.a = 1 - a*2 / circle_amount;
			} else {
				finTex.a = floor( 1 + (1 - a*2 * circle_amount));
			}
		]], externs = {amount = 1, soft = true, pos = {0.5, 0.5}}},
	color = {
		body = [[
			finTex.r *= color_color[0]/255.0;
			finTex.g *= color_color[1]/255.0;
			finTex.b *= color_color[2]/255.0;
		]], externs = {color = {255, 255, 255}}
	},
	scan = {
		body = [[
		if (p.y > scan_y && p.y < scan_y + scan_height) {
			finTex.r -= -scan_light + 1 + rand(p, scan_rnd);
			finTex.g -= -scan_light + 1 + rand(p, scan_rnd);
			finTex.b -= -scan_light + 1 + rand(p, scan_rnd);
		}
		]], externs = {y = 0, height = 1,light = 1, rnd = 1}, funcs = {"rand"}}
	}
}


local functions = { 
	rand = [[float rand(vec2 co, float v) {
			return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453 * v);
		}]],
	wave = [[float wave(float x, float amount) {
	  		return (sin(x * amount) + 1.) * .5;
		}]]
	
}


local function getExternType(a)
	local t = type(a)
	if t == "number" then return "float" end
	if t == "boolean" then return "bool" end
	if t == "table" then
		local t2 = type(a[1])
		if t2 == "number" then
			if #a <= 4 then
				return "vec" .. #a
			else
				return "float[" .. #a .. "]"
			end
		elseif t2 == "table" then
			return "vec" .. #a[1] .. "[" .. #a .. "]"
		end
	end
end


local Shader = {}

function Shader.new(...)
	local names = {...}

	local funcs = {}
	local externs = {}
	local header = [[
		vec4 effect(vec4 color, Image tex, vec2 p, vec2 pc) {
		vec4 finTex = Texel(tex, p);
		vec2 np;
		float a, b, c;
	]]
	local bodies = {}

	for i,v in ipairs(names) do
		local shader = list[v]
		table.insert(bodies, shader.body)

		for k,ext in pairs(shader.externs) do
			table.insert(externs, "extern " .. getExternType(ext) .. " " .. v .. "_" .. k .. ";\n")
		end

		if shader.funcs then
			for i,func in ipairs(shader.funcs) do
				table.insert(funcs, functions[shader.funcs[i]])
			end
		end
	end

	extern_string = table.concat(externs, "")
	funcs_string = table.concat(lume.set(funcs), "")
	body_string = table.concat(bodies, "")
	local footer = "return finTex;}"
	local final = extern_string .. funcs_string .. header .. body_string .. footer

	local s = love.graphics.newShader(final)
	for i,v in ipairs(names) do
		for k,ext in pairs(list[v].externs) do
			if type(ext) == "table" and #ext > 4 then
				s:send(v.."_"..k, unpack(ext))
			else
				s:send(v.."_"..k, ext)
			end
		end
	end
	return s
end


--check whether a shader has a certain extern
function Shader.has(name, extern)
	return list[name].externs[extern]
end


return Shader
I made this a while back when learning shaders, and I thought it would be nice to share it. Note that my knowledge about shaders is still pretty limited so it can probably be improved in some way. Also as I'm writing this I'm learning that shine exists, which from what I understand has the same goal? Anyway, I couldn't really turn this into a library so I thought I'd share it here.

It's very simple. You use Shader.new to create a new shader. You pass the names of the shaders you want to include.

Example:
Image

You can also use Shader.has to check if a shader has a certain extern.

It is important that you first pass shaders that affect the shape, like "waves" and "noise", and then shaders that affect colors like "rgb" or "invert". This is because a new texture will be made after every shader that affects p.

Code: Select all

finTex = Texel(tex, p);
You can add your own shaders of course, just make sure you get the variable names right (look at the header).

Enjoy?
User avatar
Ulydev
Party member
Posts: 445
Joined: Mon Nov 10, 2014 10:46 pm
Location: Paris
Contact:

Re: Share a Shader!

Post by Ulydev »

Sheepolution wrote:-snip-
Hey Sheepolution, that looks amazing!

I'm quite interested in knowing how it runs with multiple shaders/objects. I've had a lot of performance issues with my earlier games which were all linked to using shaders... :death:
rungo73
Prole
Posts: 11
Joined: Thu Oct 20, 2016 3:43 am

Re: Share a Shader!

Post by rungo73 »

@Sheepolution

I've been using the shine shader library in my current project pretty much straight outta the box. It doesnt have a wave shader though and today I found this thread.

I'm new to shaders and am not really sure how to adapt your effect to the Shine library. If you have the time, can you show me how I can adapt that effect from your library? Would be a great addition to the library.

Many thanks.
User avatar
Tanner
Party member
Posts: 166
Joined: Tue Apr 10, 2012 1:51 am

Re: Share a Shader!

Post by Tanner »

Not a useful shader but it's got some colors in it at least. https://www.shadertoy.com/view/MlcXDB
creeper9207
Prole
Posts: 2
Joined: Sat Feb 25, 2017 1:12 am

Re: Share a Shader!

Post by creeper9207 »

Someone here may find it useful, takes any texture that is drawn while the shader is active and maps it onto a 3d sphere (some distortion but not very noticeable if you don't spin it too fast. stars not included). http://pastebin.com/jRp6LCnz

Image
User avatar
Imaculata
Party member
Posts: 102
Joined: Mon Aug 10, 2015 2:51 pm

Re: Share a Shader!

Post by Imaculata »

Loving that wave shader! I'm going to give that a try for the water in my 2d platformer.
User avatar
Drak
Prole
Posts: 2
Joined: Mon Apr 17, 2017 12:59 am

Re: Share a Shader!

Post by Drak »

Just got into writing some shaders, and I'm trying to dry a "overlay" texture on an existing image.

Code: Select all

[[
	extern Image player;
        vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords )
        {
            vec4 texcolor = Texel(texture, texture_coords);
			vec4 t2 = Texel( player, texture_coords );
			
			if( t2.a > 0 )
				return t2 * color;
			else
				return texcolor * color;
        }
    ]]
    
I pass the player texture/image, and this draws the texture over the existing image.
Is there anyway to resize the "overlay", it currently stretches over the entire image. Or is what I'm doing not possible in a single pass?
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 44 guests