Share a Shader!
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Share a Shader!
Seeing as shaders are pretty new and there aren't many examples yet, I thought It'd be nice to pool together what we've come up with so far, so that people who're interested in checking them out before 0.8 is properly out can see what they can do and have a play.
I'll dump a few I've come up with so far in here, and if other people have some to share too, that'd be great!
This performs a simple box blur on boxes created by the mouse: This is an experiment attempting to simulate sand stacking purely using shaders, may appear upside down depending on which version of 0.8 you have:
From a previous thread by GijsB about images effects, this shows a few basic effects that shaders can perform on an image:
I'll dump a few I've come up with so far in here, and if other people have some to share too, that'd be great!
This performs a simple box blur on boxes created by the mouse: This is an experiment attempting to simulate sand stacking purely using shaders, may appear upside down depending on which version of 0.8 you have:
From a previous thread by GijsB about images effects, this shows a few basic effects that shaders can perform on an image:
Last edited by kraftman on Fri Apr 06, 2012 12:30 am, edited 3 times in total.
Re: Share a Shader!
Sorry for the double post, but it seems i cant attach more than 3 files.
This is a test drawing application with layers. It uses a shader to display the color picker (middle mouse button) since chosing colors needs to be fairly responsive: This is an accident while making the sand shader, dragging the mouse across the window creates a strange fractal effect: This is another side project for a gallery I'm making, I wanted the icons to have a mirrored effect. WASD controls the left image, arrows for the right:
Hopefully these will be of use to someone.
This is a test drawing application with layers. It uses a shader to display the color picker (middle mouse button) since chosing colors needs to be fairly responsive: This is an accident while making the sand shader, dragging the mouse across the window creates a strange fractal effect: This is another side project for a gallery I'm making, I wanted the icons to have a mirrored effect. WASD controls the left image, arrows for the right:
Hopefully these will be of use to someone.
Last edited by kraftman on Fri Apr 06, 2012 12:35 am, edited 1 time in total.
- slime
- Solid Snayke
- Posts: 3156
- Joined: Mon Aug 23, 2010 6:45 am
- Location: Nova Scotia, Canada
- Contact:
Re: Share a Shader!
Instead of posting a .love file, I'll post code. ![Wink ;)](./images/smilies/ms-wink.png)
This is a very highly unoptimized version of my dynamic lighting + normal mapping shader as seen here. I also just changed it from the ugly to the unoptimized version right now, so it may not work correctly.![Razz :P](./images/smilies/ms-razz.png)
Also it's the version without the matrix multiplication for proper lighting when the image is rotated. Maybe I'll add that to this later.
EDIT: For reference, here is the optimized file I made for my space game. It's not very easy to understand.
This is a passthrough shader for graphics primitives (untextured things)
This is a passthrough shader for images
This is one way to turn a square image into a rotating sphere (both ways are shown here)
Here is the other way shown in the video
There are a bunch of post-processing GLSL shaders available here which can be ported to the LÖVE pixeleffect syntax pretty easily.
![Wink ;)](./images/smilies/ms-wink.png)
This is a very highly unoptimized version of my dynamic lighting + normal mapping shader as seen here. I also just changed it from the ugly to the unoptimized version right now, so it may not work correctly.
![Razz :P](./images/smilies/ms-razz.png)
Also it's the version without the matrix multiplication for proper lighting when the image is rotated. Maybe I'll add that to this later.
Code: Select all
const int numlights = 3;
const vec3 gamma = vec3(2.2);
const vec3 invgamma = 1.0/gamma;
const vec3 viewdir = vec3(0.0, 0.0, 1.0);
extern vec4 Lights[6]; // max n / 2 lights
extern Image normaltexture;
extern number specpower = 25.0;
extern number yres;
extern number z = 0.0;
vec4 pow(vec4 color, vec3 exp)
{
color.rgb = pow(color.rgb, exp);
return color;
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
vec3 coords = vec3(pixel_coords.x, yres - pixel_coords.y, z);
vec4 texcolor = pow(Texel(texture, texture_coords), gamma);
vec4 finalcolor = pow(vec4(0.0), gamma) * texcolor;
vec4 normal = Texel(normaltexture, texture_coords);
vec3 N = normalize(normal.xyz * 2.0 - 1.0);
float specvalue = normal.a; // the normal texture has the specular texture inside its alpha component
for (int i = 0; i < numlights * 2; i += 2)
{
vec3 L = normalize(Lights[i].xyz - coords);
number NdotL = max(dot(N, L), 0.0);
vec3 R = normalize(reflect(-L, N));
number specular = pow(max(dot(viewdir, R), 0.0), specpower);
finalcolor += (texcolor * Lights[i+1] * NdotL) + (Lights[i+1] * specvalue * specular);
}
finalcolor.a = texcolor.a;
return pow(finalcolor, invgamma);
}
Code: Select all
Effects.Lighting = class("Effects.Lighting")
function Effects.Lighting:initialize()
local mt = {
__index = function(self, k)
if type(k) == "number" then self[k] = {} return self[k] end
end,
}
self.shaders = setmetatable({numdirlights=0, numpointlights=0}, mt)
self.lights = {
point = {num=0},
dir = {num=0},
}
self.ambientcolor = {0, 0, 0, 0}
self.current = {
angle = 0,
specpower = 25,
rotationmatrix = RotationMatrix(0),
z = 0,
}
end
function Effects.Lighting:GetCurrentShaders()
return self.shaders[self.lights.point.num][self.lights.dir.num]
end
function Effects.Lighting:AddLight(lighttype, pos, color, radius)
local light = {
pos = pos or {0, 0, 0, radius or 0},
radius = radius or pos[4] or 0,
color = color or {1, 1, 1, 1},
type = lighttype,
}
pos[4] = radius or pos[4]
self.lights[lighttype][light] = true
self.lights[lighttype].num = self.lights[lighttype].num + 1
self:UpdateInfo()
return light
end
function Effects.Lighting:UpdateInfo()
local curshaders = self:GetCurrentShaders() or {}
local numpointlights = self.lights.point.num
local numdirlights = self.lights.dir.num
-- debug.debug()
if not next(curshaders) then
curshaders = {
standard = self:GenerateShader(false, false, numpointlights, numdirlights),
normals = self:GenerateShader(true, false, numpointlights, numdirlights),
specular = self:GenerateShader(true, true, numpointlights, numdirlights),
}
--print(curshaders, numpointlights, numdirlights)
else
--print("no new light", numpointlights, numdirlights)
end
for k,v in pairs(curshaders) do
v:send("rotationmatrix", self.current.rotationmatrix)
if k == "normals" or k == "specular" then
if k == "specular" then
v:send("specpower", self.current.specpower)
end
if self.current.normaltexture then v:send("normaltexture", self.current.normaltexture) end
end
end
self.shaders[numpointlights][numdirlights] = curshaders
end
function Effects.Lighting:RemoveLight(light)
if not self.lights[light.type][light] then return end
self.lights[light.type][light] = nil
self.lights[light.type].num = self.lights[light.type].num - 1
self:UpdateInfo()
end
function Effects.Lighting:SetMaterialInfo(angle, z, normaltexture, specpower)
local rotationmatrix = RotationMatrix(angle or 0)
for k,v in pairs(self:GetCurrentShaders() or {}) do
if self.current.angle ~= angle then
v:send("rotationmatrix", rotationmatrix)
end
if self.current.z ~= z then
v:send("z", z)
end
if (k == "normals" or k == "specular") and normaltexture then
v:send("normaltexture", normaltexture)
end
if k == "specular" and specpower and self.current.specpower ~= specpower then
v:send("specpower", specpower)
end
end
self.current.angle = angle
self.current.z = z
self.current.rotationmatrix = rotationmatrix
self.current.specpower = specpower
self.current.normaltexture = normaltexture
end
function Effects.Lighting:SetEffectType(etype)
local cureffects = self:GetCurrentShaders()
love.graphics.setPixelEffect(cureffects and cureffects[etype] or nil)
end
function Effects.Lighting:update(dt)
local dirlights, pointlights = {}, {}
for k in pairs(self.lights.dir) do
if k ~= "num" then
dirlights[#dirlights+1] = k.pos
dirlights[#dirlights+1] = k.color
end
end
for k in pairs(self.lights.point) do
if k ~= "num" then
pointlights[#pointlights+1] = k.pos
pointlights[#pointlights+1] = k.color
end
end
local cureffects = self:GetCurrentShaders() or {}
for k, v in pairs(cureffects) do
-- send lights
if #pointlights > 0 then v:send("pointlights", unpack(pointlights)) end
if #dirlights > 0 then v:send("dirlights", unpack(dirlights)) end
end
end
function Effects.Lighting:SetAmbientColor(r, g, b, a)
self.ambientcolor = {r, g, b, a}
for k,v in pairs(self:GetCurrentShaders()) do
v:send("ambientcolor", self.ambientcolor)
end
end
local phong_base = [[
const vec3 gamma = vec3(2.2);
const vec3 invgamma = 1.0/gamma;
vec3 viewdir = vec3(0.0, 0.0, 1.0);
/* pointlight_array */
/* dirlight_array */
/* normal_texture */
extern number yres = 720;
extern number z = 0.0;
extern number specpower = 25.0;
extern mat2 rotationmatrix;
extern vec4 ambientcolor = vec4(0.5);
vec4 pow(vec4 color, vec3 exp)
{
color.rgb = pow(color.rgb, exp);
return color;
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
viewdir.xy = rotationmatrix * viewdir.xy; // TODO: only do this if specular is on
vec3 coords = vec3(pixel_coords.x, yres - pixel_coords.y, z);
vec4 texcolor = pow(Texel(texture, texture_coords), gamma);
vec4 finalcolor = pow(ambientcolor, gamma) * texcolor;
// get normal
/* normal_texture_access */
// calculate point lights (if any)
/* pointlight_calc */
// calculate directional lights (if any)
/* dirlight_calc */
finalcolor.a = texcolor.a;
return pow(finalcolor, invgamma) * color;
}
]]
function Effects.Lighting:GenerateShader(use_normalmap, use_specularmap, num_pointlights, num_dirlights)
local str = string.format("%d;%d;%d;%d", use_normalmap and 1 or 0, use_specularmap and 1 or 0, num_pointlights, num_dirlights)
if self.shaders[str] then return self.shaders[str] end
use_specularmap = use_normalmap and use_specularmap or false
local shadertext = phong_base
local formats = {
pointlight_array = "extern vec4 pointlights[%d];",
dirlight_array = "extern vec4 dirlights[%d];",
normal_texture = "extern Image normaltexture;",
normal_texture_access = [[
vec4 normal = Texel(normaltexture, texture_coords);
vec3 N = normalize(normal.xyz * 2.0 - 1.0);
%s
]],
pointlight_calc = [[
number radius_PN_ = pointlights[_PN2_].w;
vec3 lightdir_PN_ = (pointlights[_PN2_].xyz - coords) / radius_PN_;
lightdir_PN_.xy = rotationmatrix * lightdir_PN_.xy;
vec3 L_PN_ = normalize(lightdir_PN_);
number atten_PN_ = clamp(1.0 - dot(lightdir_PN_, lightdir_PN_), 0.0, 1.0);
number NdotL_PN_ = max(dot(N, L_PN_), 0.0);
%s
finalcolor += (texcolor * pointlights[_PN3_] * NdotL_PN_ * atten_PN_)%s;
]],
}
local pointlight_specular = {[[
vec3 R_PN_ = normalize(reflect(-L_PN_, N));
number specular_PN_ = pow(max(dot(viewdir, R_PN_), 0.0), specpower);]],
[[ + (pointlights[_PN3_] * specvalue * specular_PN_ * atten_PN_)]],
}
formats.dirlight_calc = [[
vec3 lightdir_DN_ = dirlights[_DN2_].xyz;
lightdir_DN_.xy = rotationmatrix * lightdir_DN_.xy;
vec3 L_DN_ = normalize(lightdir_DN_);
number NdotL_DN_ = max(dot(N, L_DN_), 0.0);
%s
finalcolor += (texcolor * dirlights[_DN3_] * NdotL_DN_)%s;
]]
local dirlight_specular = {}
for i,v in ipairs(pointlight_specular) do
v = v:gsub("pointlights", "dirlights")
v = v:gsub("_PN", "_DN")
dirlight_specular[i] = v:gsub(" %* atten_DN_", "")
end
local t = {}
for k,v in pairs(formats) do t[k] = "" end
if use_normalmap then
t.normal_texture = formats.normal_texture
if use_specularmap then
t.normal_texture_access = formats.normal_texture_access:format("number specvalue = normal.a;")
t.pointlight_calc = formats.pointlight_calc:format(unpack(pointlight_specular))
t.dirlight_calc = formats.dirlight_calc:format(unpack(dirlight_specular))
else
t.normal_texture_access = formats.normal_texture_access:format("")
t.pointlight_calc = formats.pointlight_calc:format("", "")
t.dirlight_calc = formats.dirlight_calc:format("", "")
end
else
t.normal_texture_access = "vec3 N = vec3(0.0, 0.0, 1.0);"
t.pointlight_calc = formats.pointlight_calc:format("", "")
t.dirlight_calc = formats.dirlight_calc:format("", "")
end
local function add_lights(basestr, numlights)
local str = ""
for i=1, numlights do
local f = basestr
f = f:gsub("_(%a)N_", "_%1"..i.."_")
f = f:gsub("_(%a)N2_", (i-1)*2)
f = f:gsub("_(%a)N3_", (i-1)*2 + 1)
str = str..f
end
return str
end
t.pointlight_array = num_pointlights > 0 and formats.pointlight_array:format(num_pointlights * 2) or ""
t.pointlight_calc = add_lights(t.pointlight_calc, num_pointlights)
num_dlights = num_dirlights
-- debug.debug()
t.dirlight_array = num_dirlights > 0 and formats.dirlight_array:format(num_dirlights * 2) or ""
t.dirlight_calc = add_lights(t.dirlight_calc, num_dirlights)
shadertext = shadertext:gsub("\t*/%* (.-) %*/", t)
shadertext = shadertext:gsub("\n\t\t", "\n")
-- print(shadertext)
self.shaders[str] = love.graphics.newPixelEffect(shadertext)
return self.shaders[str]
end
This is a passthrough shader for graphics primitives (untextured things)
Code: Select all
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
return color;
}
Code: Select all
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords)
{
return color * Texel(texture, texture_coords);
}
This is one way to turn a square image into a rotating sphere (both ways are shown here)
Code: Select all
extern number time; // time in seconds
vec4 effect(vec4 color, Image texture, vec2 tc, vec2 pixel_coords)
{
vec2 p = -1.0 + 2.0 * tc;
number r = dot(p, p);
if (r > 1.0) discard;
number f = (1.0 - sqrt(1.0 - r)) / (r);
vec2 uv;
uv.x = 1.0*p.x*f + time;
uv.y = 1.0*p.y*f;
return vec4(Texel(texture, uv).xyz, 1.0) * color;
}
Code: Select all
const number pi = 3.14159265;
const number pi2 = 2.0 * pi;
extern number time;
vec4 effect(vec4 color, Image texture, vec2 tc, vec2 pixel_coords)
{
vec2 p = 2.0 * (tc - 0.5);
number r = sqrt(p.x*p.x + p.y*p.y);
if (r > 1.0) discard;
number d = r != 0.0 ? asin(r) / r : 0.0;
vec2 p2 = d * p;
number x3 = mod(p2.x / (pi2) + 0.5 + time, 1.0);
number y3 = p2.y / (pi2) + 0.5;
vec2 newCoord = vec2(x3, y3);
vec4 sphereColor = color * Texel(texture, newCoord);
return sphereColor;
}
There are a bunch of post-processing GLSL shaders available here which can be ported to the LÖVE pixeleffect syntax pretty easily.
Re: Share a Shader!
The effects used to make this thing:
Distortion:
Chroma shift (splitting the RGB channels):
Caleidoscope:
Combine them to get this thing:
Distortion:
Code: Select all
extern number time;
extern number distortion;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc)
{
// play with parameters here:
tc.x += sin(tc.y * 100 + time * 10.0) * .03 * distortion;
return Texel(tex,tc);
}
Code: Select all
extern vec2 chroma;
extern vec2 imageSize;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc)
{
vec2 shift = chroma / imageSize;
return vec4(Texel(tex, tc+shift).r, Texel(tex,tc).g, Texel(tex,tc-shift).b, 1.0);
}
Code: Select all
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc)
{
tc = vec2(1.0,1.0) - abs(2.0 * tc - vec2(1.0,1.0)); // tc.x = 0 ... 1 ... 0
return vec4(Texel(tex, tc));
}
Re: Share a Shader!
adrix89 wrote:caleidoscope.loveImage buffer does not compile
It doesn't like the word buffer, here's a quick fix:
Re: Share a Shader!
Awesome!kraftman wrote:adrix89 wrote:caleidoscope.loveImage buffer does not compile
It doesn't like the word buffer, here's a quick fix:
Re: Share a Shader!
I like the chroma thing a lot, had a play around with adding it to particle systems:
Last edited by kraftman on Fri Apr 06, 2012 12:38 am, edited 1 time in total.
Re: Share a Shader!
Metaball shader:
Code: Select all
extern vec2[3] balls;
float metaball(vec2 x, vec2 c)
{
return 1.0 / dot(x-c, x-c);
}
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc)
{
float d = metaball(pc, balls[0]) + metaball(pc, balls[1]) + metaball(pc, balls[2]);
if (d <= .0007)
return vec4(1.0);
return vec4(0.0);
}
- Attachments
-
metaballs.love
- (581 Bytes) Downloaded 5079 times
- TechnoCat
- Inner party member
- Posts: 1611
- Joined: Thu Jul 30, 2009 12:31 am
- Location: Milwaukee, WI
- Contact:
Re: Share a Shader!
How would I go about parameterizing this? I can't seem to get the balls to stretch further.vrld wrote:Metaball shader:Code: Select all
extern vec2[3] balls; float metaball(vec2 x, vec2 c) { return 1.0 / dot(x-c, x-c); } vec4 effect(vec4 color, Image tex, vec2 tc, vec2 pc) { float d = metaball(pc, balls[0]) + metaball(pc, balls[1]) + metaball(pc, balls[2]); if (d <= .0007) return vec4(1.0); return vec4(0.0); }
Who is online
Users browsing this forum: Google [Bot] and 3 guests