Page 1 of 1
Shader questions
Posted: Sun Apr 02, 2023 4:41 pm
by darkfrei
Hi all!
Why this code makes just blue, nothing red?
Code: Select all
-- main.lua
shader2 = love.graphics.newShader([[
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
if(texture_coords.x > 0.5){
return vec4(1.0,0.0,0.0,1.0);//red
}
else
{
return vec4(0.0,0.0,1.0,1.0);//blue
}
}
]])
function love.draw()
love.graphics.setShader(shader2)
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
love.graphics.setShader()
end
(the code from
https://blogs.love2d.org/content/beginn ... de-shaders)
Re: Shader questions
Posted: Sun Apr 02, 2023 4:43 pm
by slime
The code in the link doesn't use love.graphics.rectangle. Primitive shapes (like rectangles) don't have texture coordinates.
Re: Shader questions
Posted: Sun Apr 02, 2023 5:00 pm
by darkfrei
Thanks! Now it works:
Code: Select all
shader2 = love.graphics.newShader([[
extern number screenWidth;
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
if(screen_coords.x/screenWidth > 0.5){
return vec4(1.0,0.0,0.0,1.0);//red
}
else
{
return vec4(0.0,0.0,1.0,1.0);//blue
}
}
]])
shader2:send("screenWidth", love.graphics.getWidth())
function love.draw()
love.graphics.setShader(shader2)
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
love.graphics.setShader()
end
Re: Shader questions
Posted: Mon Apr 03, 2023 3:07 pm
by darkfrei
Is here a way to take neighbor pixels easier?
Code: Select all
shader = love.graphics.newShader([[
vec4 Laplacian(Image texture, vec2 texture_coords) {
vec4 left = Texel(texture, texture_coords + vec2(-1.0 / love_ScreenSize.x, 0.0));
vec4 right = Texel(texture, texture_coords + vec2(1.0 / love_ScreenSize.x, 0.0));
vec4 top = Texel(texture, texture_coords + vec2(0.0, -1.0 / love_ScreenSize.y));
vec4 bottom = Texel(texture, texture_coords + vec2(0.0, 1.0 / love_ScreenSize.y));
vec4 center = Texel(texture, texture_coords);
center = center - (left + right + top + bottom)/4.0;
return 100.0*center;
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
vec4 laplacian = Laplacian(texture, texture_coords);
return laplacian;
}
]])
Re: Shader questions
Posted: Mon Apr 03, 2023 3:26 pm
by marclurr
How you've done it is pretty much how I'd have done it. That said, according to the GLSL documentation you can do a component-wise division on two vectors, so you can make it very slightly neater with a wrapper function, perhaps something like this (untested):
Code: Select all
vec2 toUV(float x, float y) {
return vec2(x, y) / love_ScreenSize;
}
....
vec4 left = Texel(texture, texture_coords + toUV(-1.0,0));
Or just forgo the wrapper and inline the division whenever you need to.
Edit: Just realised love_ScreenSize is a vec4, so that would need modifying slightly. Something like:
Re: Shader questions
Posted: Mon Apr 03, 2023 5:57 pm
by pgimeno
Re: Shader questions
Posted: Tue Apr 04, 2023 2:23 pm
by darkfrei
How to convert grayscale picture to the gradient palette?
For example
Code: Select all
function getColor (t) -- from 0 to 1
local delta = 2*math.pi/6 -- 60 degrees
local angle = t * 5*delta -- 1 is 300 degrees
local r = 0.5 + math.cos (angle + 1*delta)
local g = 0.5 + math.cos (angle + 3*delta)
local b = 0.5 + math.cos (angle + 5*delta)
r = math.min(1, math.max(0, r))
g = math.min(1, math.max(0, g))
b = math.min(1, math.max(0, b))
return 0.45+r*0.5, 0.45+g*0.5, 0.45+b*0.5
end
And the color palette with 12 colors:
Code: Select all
palette = {}
for i = 0, 11 do
table.insert(palette, {getColor(i/11)})
end
Re: Shader questions
Posted: Tue Apr 04, 2023 5:38 pm
by pgimeno
Shaders work with one pixel at a time (conceptually). You can sample the texture with Texel, read one of the components (for example R, which is compatible with most texture formats) as grayscale value, apply the formula you want and then return an RGBA vector with the values.
For example, your code would be:
Code: Select all
local shader = love.graphics.newShader[[
vec4 effect(vec4 tint, Image tex, vec2 texpos, vec2 scrpos)
{
vec2 grey_and_alpha = Texel(tex, texpos).ra;
float delta = 2.0*3.14159265/6.0;
float angle = grey_and_alpha.x * 5.0 * delta;
vec3 result;
result.r = 0.5 + cos(angle + delta);
result.g = 0.5 + cos(angle + 3.0*delta);
result.b = 0.5 + cos(angle + 5.0*delta);
result = max(result, vec3(0.0, 0.0, 0.0));
result = min(result, vec3(1.0, 1.0, 1.0));
return vec4(result * 0.5 + 0.45, grey_and_alpha.y) * tint;
}
]]
local img = love.graphics.newImage('grey.png')
function love.draw()
love.graphics.setShader(shader)
love.graphics.draw(img)
love.graphics.setShader()
end
Or make an image with the palette and use the R component as the coordinate:
Code: Select all
local shader = love.graphics.newShader[[
extern Image palette;
const float width = 3.0; // width of the palette texture; can be extern
const float multiplier = (width - 1.0);
const float divisor = 1.0 / width;
vec4 effect(vec4 tint, Image tex, vec2 texpos, vec2 scrpos)
{
float grey = Texel(tex, texpos).r;
vec4 result = Texel(palette, vec2((grey*multiplier+0.5)*divisor, 0.5));
return result * tint;
}
]]
local img = love.graphics.newImage('grey.png')
local palette = love.graphics.newImage(
love.image.newImageData(3, 1, 'rgba8', '\255\0\0\255\0\255\0\255\0\0\255\255')
)
shader:send('palette', palette)
function love.draw()
love.graphics.setShader(shader)
love.graphics.draw(img)
love.graphics.setShader()
end
Re: Shader questions
Posted: Fri Sep 08, 2023 7:51 pm
by darkfrei
Hi all!
I really need your help! I am making the shader for System Reaction-Diffusion, but something goes wrong:
Code: Select all
local canvasWidth, canvasHeight = 600, 600
local shaderCode = [[
float feed_rate = 0.162; // Feed rate (F)
float kill_rate = 0.155; // Kill rate (K)
float diffusion_rate_red = 0.06; // Diffusion rate for U
float diffusion_rate_green = 0.025; // Diffusion rate for V
float dt = 0.05; // Time step (dt)
vec4 calculateLaplacian(Image texture, vec2 texture_coords) {
vec2 offsetH = vec2(1.0 / love_ScreenSize.x, 0.0);
vec2 offsetV = vec2(0.0, 1.0 / love_ScreenSize.y);
vec4 colorCenter = Texel(texture, texture_coords);
vec4 colorLeft = Texel(texture, texture_coords - offsetH);
vec4 colorRight = Texel(texture, texture_coords + offsetH);
vec4 colorUp = Texel(texture, texture_coords - offsetV);
vec4 colorDown = Texel(texture, texture_coords + offsetV);
vec4 colorUpLeft = Texel(texture, texture_coords - offsetV - offsetH);
vec4 colorUpRight = Texel(texture, texture_coords - offsetV + offsetH);
vec4 colorDownLeft = Texel(texture, texture_coords + offsetV - offsetH);
vec4 colorDownRight = Texel(texture, texture_coords + offsetV + offsetH);
vec4 laplacian = - 1.0 * colorCenter +
// 0.14645 * (colorLeft + colorRight + colorUp + colorDown) +
// 0.10355 * (colorUpLeft + colorUpRight + colorDownLeft + colorDownRight);
0.2 * (colorLeft + colorRight + colorUp + colorDown) +
0.05 * (colorUpLeft + colorUpRight + colorDownLeft + colorDownRight);
return laplacian;
}
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
vec4 current = Texel(texture, texture_coords);
vec4 laplacian = calculateLaplacian(texture, texture_coords);
float triangleR = laplacian.r;
float triangleG = laplacian.g;
float cR = current.r; // current U
float cG = current.g;
float newU = cR + (diffusion_rate_red * triangleR - cR * cG * cG + feed_rate * (1.0 - cR)) * dt;
float newV = cG + (diffusion_rate_green * triangleG + cR * cG * cG - (kill_rate + feed_rate) * cG) * dt;
vec4 new = vec4 (newU, newV, 0, 1);
return new;
}
]]
shader = love.graphics.newShader(shaderCode)
local canvases = {
love.graphics.newCanvas(canvasWidth, canvasHeight),
love.graphics.newCanvas(canvasWidth, canvasHeight)
}
local iCanvas = 1
function love.load()
love.window.setTitle("Reaction Diffusion Simulation")
love.window.setMode(canvasWidth, canvasHeight)
love.graphics.setCanvas(canvases[1])
love.graphics.setColor (1,0,0)
for i = 1, 10 do
love.graphics.rectangle ('fill', math.random (canvasWidth-50), math.random (canvasHeight-50), 50, 50)
end
-- love.graphics.setCanvas(canvases[2])
love.graphics.setColor (0,1,0)
for i = 1, 10 do
love.graphics.rectangle ('fill', math.random (canvasWidth-50), math.random (canvasHeight-50), 50, 50)
end
love.graphics.setColor (1,1,0)
for i = 1, 10 do
love.graphics.rectangle ('fill', math.random (canvasWidth-40), math.random (canvasHeight-40), 40, 40)
end
love.graphics.setCanvas()
end
function love.update(dt)
local iPrevCanvas = iCanvas
iCanvas = iCanvas %2 +1
love.window.setTitle (iCanvas)
love.graphics.setCanvas(canvases[iCanvas])
love.graphics.setShader(shader)
love.graphics.setColor (1,1,1)
love.graphics.draw (canvases[iPrevCanvas])
love.graphics.setShader()
love.graphics.setCanvas()
end
function love.draw()
love.graphics.setColor (1,1,1)
love.graphics.draw (canvases[iCanvas])
end