Page 11 of 33

Re: Share a Shader!

Posted: Mon Jul 09, 2012 7:49 am
by vrld
Ref wrote:Anybody create a Sobel (edge detection) PixelEffect
Untested:

Code: Select all

effect = love.graphics.newPixelEffect[[
extern vec2 pixel_size;

vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pixel_coords)
{
    color = vec4(0.0);
    // the kernel
    color += 1. * Texel(tex, tc + vec2(-1./pixel_size.x, -pixel_size.y));
    color += 2. * Texel(tex, tc + vec2(0, -pixel_size.y));
    color += 1. *Texel(tex, tc + vec2(pixel_size.x, -pixel_size.y));
    color += -1. * Texel(tex, tc + vec2(-pixel_size.x, pixel_size.y));
    color += -2. * Texel(tex, tc + vec2(0, pixel_size.y));
    color += -1. *Texel(tex, tc + vec2(pixel_size.x, pixel_size.y));

    return color;
}]]
effect:send('pixel_size', {1/love.graphics.getWidth(), 1/love.graphics.getHeight()})
You can implement any convolution using this code, e.g. simple blur:

Code: Select all

1/9 1/9 1/9
1/9 1/9 1/9
1/9 1/9 1/9

Re: Share a Shader!

Posted: Mon Jul 09, 2012 3:17 pm
by Ref
Thanks vrid for sobel effect!
Made a minor change to effect to avoid white screen of oblivion.
Changed color = vec4(0.0); to color = vec4(1.0);
Worked.
Don't appreciate why first color change was:
color += 1. * Texel(tex, tc + vec2(-1./pixel_size.x, -pixel_size.y));
Didn't see to be consisting with following code so I changed it to:
color += 1. * Texel(tex, tc + vec2(-pixel_size.x, -pixel_size.y));
This also works as far as I can see.
Any reason for difference (really just key punching here)?
Provided a 'Love" file for those who would like to see what a Sobel effect is.

Re: Share a Shader!

Posted: Mon Jul 09, 2012 4:01 pm
by vrld
Oh, I totally forgot about the alpha value. Since the kernel (with an e) sums to 0 and the alpha value is consistent over the image, the alpha value will be \(1 + 2 + 1 - 1 - 2 - 1 = 0\).
You should get the correct result using

Code: Select all

return vec4(color.rgb * 0.5 + vec3(0.5), 1.0);
This does two things:
  1. It makes the image opaque (alpha = 1).
  2. It "normalizes" the image, so that you can see negative and positive edges (color.rgb*0.5 + vec3(0.5)).
Initializing the color with white is possible, but will return a technically incorrect result.

Btw: to get the "full" sobel operator, apply it horizontally and vertically (just rotate the kernel about 90 degree):

Code: Select all

kernel = love.graphics.newPixelEffect[[
extern vec2 pixel_size;

vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pixel_coords)
{
    vec4 vert = vec4(0.0);
    // the kernel
    vert +=  1. * Texel(tex, tc + vec2(-pixel_size.x, -pixel_size.y));
    vert +=  2. * Texel(tex, tc + vec2( 0, -pixel_size.y));
    vert +=  1. * Texel(tex, tc + vec2( pixel_size.x, -pixel_size.y));
    vert += -1. * Texel(tex, tc + vec2(-pixel_size.x, pixel_size.y));
    vert += -2. * Texel(tex, tc + vec2( 0, pixel_size.y));
    vert += -1. * Texel(tex, tc + vec2(pixel_size.x, pixel_size.y));

    vec4 horiz = vec4(0.0);
    horiz +=  1. * Texel(tex, tc + vec2(-pixel_size.x,  pixel_size.y));
    horiz +=  2. * Texel(tex, tc + vec2(-pixel_size.x, 0));
    horiz +=  1. * Texel(tex, tc + vec2(-pixel_size.x, -pixel_size.y));
    horiz += -1. * Texel(tex, tc + vec2( pixel_size.x,  pixel_size.y));
    horiz += -2. * Texel(tex, tc + vec2( pixel_size.x,  0));
    horiz += -1. * Texel(tex, tc + vec2( pixel_size.x, -pixel_size.y));

    return vec4((horiz+vert).rgb * .5 + vec3(.5), 1.0);
}]]

Re: Share a Shader!

Posted: Mon Jul 09, 2012 9:00 pm
by Ref
Ah! Ha!
Thought there was something not quite right.
Thanks vrid for the update.
Made some minor changes to the effect (always messing around).

Code: Select all

kernal = love.graphics.newPixelEffect[[
    extern vec2 pixel_size;
    extern mat3x3 ker;
    int ix = -1;
    int iy = -1;
    vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pixel_coords)
    {
    vec4 vert  = vec4(0.0);
    vec4 horiz = vec4(0.0);
    for( int j = 0; j < 3; j++ ){
        for( int i = 0; i < 3 ; i++ ){
            vert  +=  ker[j][i] * Texel(tex, tc + vec2(ix*pixel_size.x, iy*pixel_size.y));
            horiz +=  ker[j][i] * Texel(tex, tc + vec2(ix*pixel_size.x, iy*pixel_size.y));
            ix = ix + 1;
            }
        iy = iy + 1;
        ix = -1;
        }
   return vec4((horiz+vert).rgb * .5 + vec3(.5), 1.0);
    } ]]
This allows me to pass a 3x3 kernal directly to the effect via:

Code: Select all

ker={
    {{1, 2,  1}, {0, 0, 0}, {-1, -2, -1}},	-- Sobel
    {{-1,-1,-1},{-1,8,-1},{-1,-1,-1}},	-- Laplacian8
    {{1/9,1/9,1/9},{1/9,1/9,1/9},{1/9,1/9,1/9}}, -- blur
    {{-2,0,0},{0,0,0},{0,2,0}},		-- gradian
    }
kernal:send( 'ker', ker[sel] )
Would apprectate it if you look and see if there isn't a better way as I really don't have a good grasp of GLSL.

Re: Share a Shader!

Posted: Wed Jul 25, 2012 3:49 pm
by Ref
Just another (not to complicated) shader.
Thought it might be useful for a lead-in screen to a game (if you had a more inspired image with a transparent background.)
Edit: title2.love is essentially the same as title_screen.love with keyboard control over effect - so you can see if there is a combination of interest. I didn't put any constraints on the keyboard entries and left it to you to find out which one really gives a strange effect. Have fun.

Re: Share a Shader!

Posted: Tue Jul 31, 2012 10:41 am
by dreadkillz
Shader utilizing grayscale images as transitions. Can be used to do scene transitions ala RPG Maker style. Use your own gradient grayscale for cool transitions!

Code: Select all

function love.load()
	lg = love.graphics
	li = love.image
	lf = love.filesystem
	w,h = lg.getWidth(),lg.getHeight()
	
	transitions = lf.enumerate('transitions')
	
	transIndex = 1
	transition = lg.newImage('transitions/' .. transitions[transIndex])
	
	image = lg.newImage('test.jpg')	
	
	effect = lg.newPixelEffect [[
		extern Image trans;
		extern number time;
		extern number duration;
		vec4 effect(vec4 color,Image tex,vec2 tc,vec2 pc)
		{
			vec4 img_color = Texel(tex,tc);
			vec4 trans_color = Texel(trans,tc);
			number white_level	= (trans_color.r + trans_color.b + trans_color.b)/3;
			number max_white	= time/duration;
			
			if (white_level <= max_white)
			{
				return img_color;
			}
			
			img_color.a = 0;
			return img_color;
		}
	]]
	
	t = 0
	duration = 1
	effect:send("duration",duration)
	effect:send("trans",transition)
	
	canvas = lg.newCanvas(lg.getWidth(),lg.getHeight())
	canvas:renderTo(function() lg.draw(image) end)
end
function love.update(dt)
	t = t + dt
	effect:send("time",t)
end

function love.keypressed(key)
	if key == 'r' then
		t = 0
	end
	
	if key == 'left' or key == 'right' then
		if key == 'left' then
			if transIndex >=2 then
				transIndex = transIndex - 1
			end
		elseif key == 'right' then
			if transIndex <= #transitions-1 then
				transIndex = transIndex + 1
			end
		end
		transition = lg.newImage('transitions/' .. transitions[transIndex])
		effect:send("trans",transition)
		t = 0
	end
end

function love.draw()
	lg.setPixelEffect(effect)
	lg.draw(image)
	lg.setPixelEffect()
	lg.print(love.timer.getFPS(),lg.getWidth()-30,10)
	lg.print(transitions[transIndex],10,10)
end
Left or right arrow to change transitions. R to reload transition.

EDIT: Fixed, Thanks Ref
EDIT2: My initial idea came from this, and I used to play around with RPG Maker XP and wanted to implement their transition systems in LOVE.

Re: Share a Shader!

Posted: Tue Jul 31, 2012 6:10 pm
by Ref
Ohps!
drearkilz, the Love errors.
Problem is extraneous ';' at end of effect.

Code: Select all

canv_color.a = 0;
return canv_color;
};    // unneeded semicolon
]]
should be

Code: Select all

canv_color.a = 0;
return canv_color;
}    // no semicolon
]]
Then all's well.
Nice shader.

Re: Share a Shader!

Posted: Wed Aug 01, 2012 1:06 am
by Ref
Hi dreadkillz!
I'm sure mickeyim will catch this is a prime example of where you don't need canvases.
You can remove all references to canvas and do gr.draw( image ) to get the effect you want.
Thanks again for the shader.

Re: Share a Shader!

Posted: Wed Aug 01, 2012 3:38 pm
by Ref
fasilkj wrote:I can't understand this code.Can someone explain me.please
Hi fasikj!
In case you haven't figured it out, what dreadkillz is doing is useing a 2nd (B&W) image as a filter.
He selects a brightness level (time/duration) and the shader replaces any pixel in the 2nd image who's brightness is less than the selected brightness with a pixel from the 1st image. As a function of time, the selected brightness is increases (t = t + dt) and more of the 1st image is revealed.
Dreadkillz doesn't say whether he's a genius or just a good hacker of someone else's shader.
Fun to play with.
Attached is a slightly modified version of dreadkillz's shader which transitions from a B&W image to a colored image.
Note: This doesn't use canvases but I'm not sure whether canvas impaired systems can do pixelEffects.

Re: Share a Shader!

Posted: Thu Aug 02, 2012 1:26 am
by Ref
Just another boring shader.