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
Jasoco
Inner party member
Posts: 3727
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: Share a Shader!

Post by Jasoco »

I can't figure out how to properly implement it into my game. Never comes out right. But that might be my fault.
User avatar
retrotails
Party member
Posts: 212
Joined: Wed Apr 18, 2012 12:37 am

Re: Share a Shader!

Post by retrotails »

Warps UVs with a normal map.
It also adds a gradient to make the sphere look nicer but that's not necessary.
edf.png
edf.png (528.67 KiB) Viewed 2753 times
mikeisinlove
Prole
Posts: 44
Joined: Sun Mar 31, 2013 11:55 am

Re: Share a Shader!

Post by mikeisinlove »

slime wrote:Bloom.

Code: Select all

local math, love = math, love

local function FindSmallestPO2(num)
	return 2 ^ math.ceil(math.log(num)/math.log(2))
end

local function ScaleToPO2(xsize, ysize)
	if love.graphics.isSupported("npot") then return xsize, ysize end
	return FindSmallestPO2(xsize), FindSmallestPO2(ysize)
end

-- i've found xsize and ysize of 1/2 - 1/4 the screen resolution to be nice
-- smaller values make the bloom more apparent and give much better performance, but can make it look bad if too small
function CreateBloomEffect(xsize, ysize) 
	if not love.graphics.newPixelEffect
	or not love.graphics.isSupported
	or not love.graphics.isSupported("pixeleffect")
	or not love.graphics.isSupported("canvas") then
		return
	end
	
	local function newPixelEffect(code)
		local success, result = pcall(love.graphics.newPixelEffect, code)
		if success then
			return result
		else
			print("Error compiling shader!\n"..result)
		end
	end
	
	local bloom = {}
	
	local shaders = {
		blur_vert = [[
			extern number canvas_h = 256.0;
			
			const number offset_1 = 1.3846153846;
			const number offset_2 = 3.2307692308;
			
			const number weight_0 = 0.2270270270;
			const number weight_1 = 0.3162162162;
			const number weight_2 = 0.0702702703;
			
			vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
			{
				vec4 texcolor = Texel(texture, texture_coords);
				vec3 tc = texcolor.rgb * weight_0;
				
				tc += Texel(texture, texture_coords + vec2(0.0, offset_1)/canvas_h).rgb * weight_1;
				tc += Texel(texture, texture_coords - vec2(0.0, offset_1)/canvas_h).rgb * weight_1;
				
				tc += Texel(texture, texture_coords + vec2(0.0, offset_2)/canvas_h).rgb * weight_2;
				tc += Texel(texture, texture_coords - vec2(0.0, offset_2)/canvas_h).rgb * weight_2;
				
				return color * vec4(tc, 1.0);
			}
		]],
		blur_horiz = [[
			extern number canvas_w = 256.0;

			const number offset_1 = 1.3846153846;
			const number offset_2 = 3.2307692308;
			
			const number weight_0 = 0.2270270270;
			const number weight_1 = 0.3162162162;
			const number weight_2 = 0.0702702703;

			vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
			{
				vec4 texcolor = Texel(texture, texture_coords);
				vec3 tc = texcolor.rgb * weight_0;
				
				tc += Texel(texture, texture_coords + vec2(offset_1, 0.0)/canvas_w).rgb * weight_1;
				tc += Texel(texture, texture_coords - vec2(offset_1, 0.0)/canvas_w).rgb * weight_1;
				
				tc += Texel(texture, texture_coords + vec2(offset_2, 0.0)/canvas_w).rgb * weight_2;
				tc += Texel(texture, texture_coords - vec2(offset_2, 0.0)/canvas_w).rgb * weight_2;
				
				return color * vec4(tc, 1.0);
			}
		]],
		bloom = [[
			extern number threshold = 1.0;
			
			float luminance(vec3 color)
			{
				// numbers make 'true grey' on most monitors, apparently
				return (0.212671 * color.r) + (0.715160 * color.g) + (0.072169 * color.b);
			}
			
			vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
			{
				vec4 texcolor = Texel(texture, texture_coords);
				
				vec3 extract = smoothstep(threshold * 0.7, threshold, luminance(texcolor.rgb)) * texcolor.rgb;
				return vec4(extract, 1.0);
			}
		]],
		
		combine = [[
			extern Image bloomtex;
			
			extern number basesaturation = 1.0;
			extern number bloomsaturation = 1.0;
			
			extern number baseintensity = 1.0;
			extern number bloomintensity = 1.0;
			
			vec3 AdjustSaturation(vec3 color, number saturation)
			{
    			vec3 grey = vec3(dot(color, vec3(0.212671, 0.715160, 0.072169)));
    			return mix(grey, color, saturation);
			}
		
			vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
			{
				vec4 basecolor = Texel(texture, texture_coords);
				vec4 bloomcolor = Texel(bloomtex, texture_coords);
				
				bloomcolor.rgb = AdjustSaturation(bloomcolor.rgb, bloomsaturation) * bloomintensity;
				basecolor.rgb = AdjustSaturation(basecolor.rgb, basesaturation) * baseintensity;
				
				basecolor.rgb *= (1.0 - clamp(bloomcolor.rgb, 0.0, 1.0));
				
				bloomcolor.a = 0.0;
				
				return clamp(basecolor + bloomcolor, 0.0, 1.0);
			}
		]]
	}
	
	for k,v in pairs(shaders) do
		local shader = newPixelEffect(v)
		if shader then
			shaders[k] = shader
		else
			return
		end
	end
	
	if not shaders.blur_vert or not shaders.blur_horiz or not shaders.bloom or not shaders.combine then
		return
	end

	
	local intensity_base, intensity_bloom = 1, 1
	local saturation_base, saturation_bloom = 1, 1
	local threshold_bloom = 0.5
	
	local debugdraw = false
	
	function bloom:refresh(xs, ys)
		xs, ys = math.floor(xs+0.5), math.floor(ys+0.5)
		
		local renderingtoscene = false

		self.xsize, self.ysize = xs, ys
		
		self.po2xsize, self.po2ysize = ScaleToPO2(self.xsize, self.ysize) -- scales x and y to next power of 2 if npot is false
		
		self.xres, self.yres = love.graphics.getWidth(), love.graphics.getHeight()
		self.po2xres, self.po2yres = ScaleToPO2(self.xres, self.yres)

	
		self.quad = love.graphics.newQuad(0, 0, self.xsize, self.ysize, self.po2xsize, self.po2ysize)
		self.scenequad = love.graphics.newQuad(0, 0, self.xres, self.yres, self.po2xres, self.po2yres)
	
		self.canvas = {
			bloom = love.graphics.newCanvas(self.po2xsize, self.po2ysize),
			blur_horiz = love.graphics.newCanvas(self.po2xsize, self.po2ysize),
			blur_vert = love.graphics.newCanvas(self.po2xsize, self.po2ysize),
			scene = love.graphics.newCanvas(self.po2xres, self.po2yres),
			bloomscene = love.graphics.newCanvas(self.po2xres, self.po2yres),
		}
				
		for k,v in pairs(self.canvas) do
			v:clear()
		end
		
		shaders.blur_horiz:send("canvas_w", self.po2xsize)
		shaders.blur_vert:send("canvas_h", self.po2ysize)
		self:setThreshold(self:getThreshold())
		self:setIntensity(self:getIntensity())
		self:setSaturation(self:getSaturation())
		
		if renderingtoscene then
			love.graphics.setCanvas(self.canvas.scene)
		end
		
		collectgarbage("collect")
	end
	
	function bloom:debugDraw(shoulddebugdraw)
		debugdraw = not not shoulddebugdraw
	end
	
	function bloom:setIntensity(ibase, ibloom)
		intensity_base = ibase
		intensity_bloom = ibloom
		
		shaders.combine:send("baseintensity", ibase)
		shaders.combine:send("bloomintensity", ibloom)
	end
	function bloom:getIntensity()
		return intensity_base, intensity_bloom
	end
	
	function bloom:setSaturation(sbase, sbloom)
		saturation_base = sbase
		saturation_bloom = sbloom
		
		shaders.combine:send("basesaturation", sbase)
		shaders.combine:send("bloomsaturation", sbloom)
	end
	function bloom:getSaturation()
		return saturation_base, saturation_bloom
	end
	
	function bloom:setThreshold(threshold)
		threshold_bloom = threshold
		
		shaders.bloom:send("threshold", threshold)
	end
	function bloom:getThreshold()
		return threshold_bloom
	end
	
	
	-- call right before drawing the stuff you want bloomed
	function bloom:predraw()
		for k,v in pairs(self.canvas) do
			v:clear()
		end
		love.graphics.setCanvas(self.canvas.scene)
		
		self.drawing = true
	end
	
	function bloom:enabledrawtobloom()
		love.graphics.setCanvas(self.canvas.bloomscene)
	end
	
	-- call after drawing the stuff you want bloomed
	function bloom:postdraw()			
		love.graphics.setColor(255, 255, 255)
		local blendmode = love.graphics.getBlendMode()
		love.graphics.setBlendMode("premultiplied")
		
		love.graphics.push()
		love.graphics.scale(self.po2xsize/self.po2xres, self.po2ysize/self.po2yres)
		
		-- apply bloom extract shader
		love.graphics.setCanvas(self.canvas.bloom)
		love.graphics.setPixelEffect(shaders.bloom)
		love.graphics.drawq(self.canvas.bloomscene, self.scenequad, 0, 0)
		
		love.graphics.pop()
					
		-- apply horizontal blur shader to extracted bloom
		love.graphics.setCanvas(self.canvas.blur_horiz)
		love.graphics.setPixelEffect(shaders.blur_horiz)
		love.graphics.drawq(self.canvas.bloom, self.quad, 0, 0)
		
		-- apply vertical blur shader to blurred bloom
		love.graphics.setCanvas(self.canvas.blur_vert)
		love.graphics.setPixelEffect(shaders.blur_vert)
		love.graphics.drawq(self.canvas.blur_horiz, self.quad, 0, 0)
		
		-- render final scene combined with bloom canvas
		love.graphics.setCanvas()
		shaders.combine:send("bloomtex", self.canvas.blur_vert)
		love.graphics.setPixelEffect(shaders.combine)
		love.graphics.drawq(self.canvas.scene, self.scenequad, 0, 0)
		
		love.graphics.setPixelEffect()
		
		if debugdraw then
			-- love.graphics.setColor(255, 255, 255, 128)
			love.graphics.draw(self.canvas.bloom, 0, 0)
			love.graphics.draw(self.canvas.blur_horiz, self.po2xsize+4, 0)
			love.graphics.draw(self.canvas.blur_vert, self.po2xsize*2+8, 0)
			-- love.graphics.draw(self.canvas.blur_vert, 0, 0, 0, self.po2xres/self.po2xsize, self.po2yres/self.po2ysize)
		end
		
		love.graphics.setBlendMode(blendmode)
		
		self.drawing = false
	end
	
	function bloom:isDrawing()
		return not not self.drawing
	end
	
	bloom:refresh(xsize, ysize)
	
	bloom:setIntensity(1, 1)
	bloom:setSaturation(1, 1)
	bloom:setThreshold(0.35)
	
	return bloom
end
Hey this looked pretty cool so I tried it out but the line
shaders.combine:send("bloomtex", self.canvas.blur_vert)
crashes it with no error message so I'm assuming there is a problem with sending canvases to a shader or something? Can someone help me understand the problem? I'd like to be able to write my own shaders but I can't even tell what the problem really is here.
Germanunkol
Party member
Posts: 712
Joined: Fri Jun 22, 2012 4:54 pm
Contact:

Re: Share a Shader!

Post by Germanunkol »

Useless first distortion shader of mine.
...
Scroll wheel to change number of squares.
Attachments
Squary.love
(1.21 KiB) Downloaded 263 times
trAInsported - Write AI to control your trains
Bandana (Dev blog) - Platformer featuring an awesome little ninja by Micha and me
GridCars - Our jam entry for LD31
Germanunkol.de
Germanunkol
Party member
Posts: 712
Joined: Fri Jun 22, 2012 4:54 pm
Contact:

Re: Share a Shader!

Post by Germanunkol »

Still just as useless, but a little prettier :P
trAInsported - Write AI to control your trains
Bandana (Dev blog) - Platformer featuring an awesome little ninja by Micha and me
GridCars - Our jam entry for LD31
Germanunkol.de
User avatar
shatterblast
Party member
Posts: 136
Joined: Tue Dec 11, 2012 9:47 pm
Location: Dallas, Texas, USA

Re: Share a Shader!

Post by shatterblast »

Germanunkol wrote:Still just as useless, but a little prettier :P
Kind of odd on this last one if you zoom out all the way. From a top-down view, it looks like a whirlwind, a fractal in motion, or something similar.
Germanunkol
Party member
Posts: 712
Joined: Fri Jun 22, 2012 4:54 pm
Contact:

Re: Share a Shader!

Post by Germanunkol »

shatterblast wrote: Kind of odd on this last one if you zoom out all the way. From a top-down view, it looks like a whirlwind, a fractal in motion, or something similar.
True, I think the problem is that the square's borders are "cut off", a pixel is either part of the square or not, there's no smooth transitions. That's why the growing and shrinking of the squares doesn't look all that great...
trAInsported - Write AI to control your trains
Bandana (Dev blog) - Platformer featuring an awesome little ninja by Micha and me
GridCars - Our jam entry for LD31
Germanunkol.de
User avatar
Ref
Party member
Posts: 702
Joined: Wed May 02, 2012 11:05 pm

Re: Share a Shader!

Post by Ref »

Would like a peek at version 0.9 shader syntax.
Got everything working except Shader:send.
What is the new syntax?
Attachments
shade_ver8.love
Working version 0.8 (with some other stuff)
(48.06 KiB) Downloaded 210 times
shade_ver_9.love
width & height not being sent
(499 Bytes) Downloaded 222 times
User avatar
slime
Solid Snayke
Posts: 3166
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Share a Shader!

Post by slime »

It works fine for me. What happens for you?
User avatar
Ref
Party member
Posts: 702
Joined: Wed May 02, 2012 11:05 pm

Re: Share a Shader!

Post by Ref »

For version 0.9, I get solid yellow triangles (no error messages) - not the shaded triangles I get with 0.8.
Post Reply

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Semrush [Bot] and 8 guests