Hi, so I need a dithering shader and I understand I need to use a mask/pattern along with it. I've been playing around with this one here but no luck so far. Any ideas on this? I also tried to port this one but I'm not really good at shaders.
Thanks a lot.
Looking for a dithering shader
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- alberto_lara
- Party member
- Posts: 372
- Joined: Wed Oct 30, 2013 8:59 pm
Re: Looking for a dithering shader
That shader quantizes to an 8 colour palette (all combinations of R=0 or 1, G=0 or 1, B=0 or 1). Is that what you want?
- alberto_lara
- Party member
- Posts: 372
- Joined: Wed Oct 30, 2013 8:59 pm
Re: Looking for a dithering shader
Yes, but I also want to apply the dithering effect, not just reduce the colors, this is what I have so far (based on pseudo code here)
but I'm sure doing something wrong because I just get a dark and weird image:
Code: Select all
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
vec4 pixel = Texel(texture, vec2(texture_coords.x, texture_coords.y));
vec4 oldPixel = Texel(texture, vec2(texture_coords.x, texture_coords.y));
vec4 newPixel = floor(oldPixel.rgba * 8 + vec4(0.5)) / 8;
vec4 error = oldPixel - newPixel;
newPixel = Texel(texture, vec2(texture_coords.x + 1, texture_coords.y )) + error * 7 / 2;
newPixel = Texel(texture, vec2(texture_coords.x - 1, texture_coords.y + 1)) + error * 3 / 2;
newPixel = Texel(texture, vec2(texture_coords.x, texture_coords.y + 1)) + error * 5 / 2;
newPixel = Texel(texture, vec2(texture_coords.x + 1, texture_coords.y + 2)) + error * 1 / 2;
return newPixel;
}
Re: Looking for a dithering shader
Ok then.
There are two ways of applying the dithering pattern: relative to the image and relative to the screen.
Relative to the image is more complicated, in that you need to send the dimensions of the image being drawn to the shader. Relative to the screen does not need that. But if you have moving images, you may need to choose one of them.
The dithering pattern image is attached below.
Edit: No, pure Floyd-Steinberg won't work with a shader: shaders work locally, that is, they only care about the current pixel, but they can't hold state or do things in a pre-determined order; however, that pseudocode requires propagating the error values from the top left all the way to the bottom right, line by line (notice how they add to the pixel that will be evaluated next). That is, in a way the bottom right pixel depends on the top left pixel. A shader can't do that, or at least not efficiently.
The ShaderToy algorithm, on the other hand, which is the one I've implemented, has the advantage of being local, that is, it only needs to examine the current pixel and apply the threshold in the matrix to it.
There are two ways of applying the dithering pattern: relative to the image and relative to the screen.
Relative to the image is more complicated, in that you need to send the dimensions of the image being drawn to the shader. Relative to the screen does not need that. But if you have moving images, you may need to choose one of them.
Code: Select all
local shader = love.graphics.newShader[[
uniform Image pattern;
//uniform vec2 dim; // dimensions of the texture to draw (only if rel. to img)
vec4 effect(vec4 colour, Image tex, vec2 texpos, vec2 scrpos)
{
return step(Texel(pattern,
//texpos*dim/8 // uncomment if relative to the image
scrpos/8 // comment this line out if relative to the image
), Texel(tex, texpos));
}
]]
local pat = love.graphics.newImage('OrderedDitheringPattern.png')
pat:setWrap('repeat')
pat:setFilter('nearest', 'nearest')
shader:send('pattern', pat)
local img = love.graphics.newImage('image.jpg')
--local vec2 = {0, 0} -- uncomment if rel. to image
-- this is NOT for the shader, just to move the image around
local imgSizeX, imgSizeY = img:getDimensions()
local xRange = love.graphics.getWidth() - imgSizeX
local yRange = love.graphics.getHeight() - imgSizeY
local t = 0
function love.update(dt)
t = t + dt
end
function love.draw()
love.graphics.setShader(shader);
--[[ --uncomment if relative to the image
vec2[1] = img:getWidth()
vec2[2] = img:getHeight()
shader:send('dim', vec2)
--]]
-- if relative to the image, apply math.floor to the coordinates
-- love.graphics.draw(img, math.floor((math.cos(t*9/7)/2+0.5)*xRange), math.floor((math.sin(t)/2+0.5)*yRange))
love.graphics.draw(img, (math.cos(t*9/7)/2+0.5)*xRange, (math.sin(t)/2+0.5)*yRange)
end
function love.keypressed(k)
return k == "escape" and love.event.quit()
end
The dithering pattern image is attached below.
Edit: No, pure Floyd-Steinberg won't work with a shader: shaders work locally, that is, they only care about the current pixel, but they can't hold state or do things in a pre-determined order; however, that pseudocode requires propagating the error values from the top left all the way to the bottom right, line by line (notice how they add to the pixel that will be evaluated next). That is, in a way the bottom right pixel depends on the top left pixel. A shader can't do that, or at least not efficiently.
The ShaderToy algorithm, on the other hand, which is the one I've implemented, has the advantage of being local, that is, it only needs to examine the current pixel and apply the threshold in the matrix to it.
- alberto_lara
- Party member
- Posts: 372
- Joined: Wed Oct 30, 2013 8:59 pm
Re: Looking for a dithering shader
That works great! what if I want to have more colors? does that mean more gray tones in the pattern?
Re: Looking for a dithering shader
Hi alberto_lara,
I tried to play arround with the shaders you mentioned. What kind of effect are you looking for exactly? I think it might be easier to work with pre-defined patterns rather than trying to implement it in the shader:
EDIT: I got ninja'd haha
I tried to play arround with the shaders you mentioned. What kind of effect are you looking for exactly? I think it might be easier to work with pre-defined patterns rather than trying to implement it in the shader:
EDIT: I got ninja'd haha
- Attachments
-
- dither.zip
- (479.24 KiB) Downloaded 344 times
- alberto_lara
- Party member
- Posts: 372
- Joined: Wed Oct 30, 2013 8:59 pm
Re: Looking for a dithering shader
To be precise, what I need it's a shader to take an image and apply an 8 bit color (so I need 256 colors) dithering (either Floyd–Steinberg or positioned). Edit: actually, I'd like to implement the Floyd–Steinberg method in the shader logic.
Edit 2: I'm currently looking at this to see if I can pull it https://medium.com/100-days-of-algorith ... 5b25ee0a65
Edit 2: I'm currently looking at this to see if I can pull it https://medium.com/100-days-of-algorith ... 5b25ee0a65
Re: Looking for a dithering shader
As I said, that's not possible because shaders do not work like that. Since a shader can't hold state, the only way to do it would be to process the whole image up to the current pixel for each pixel, which would be extremely slow to the point of being impractical.alberto_lara wrote: ↑Thu May 07, 2020 10:52 pm To be precise, what I need it's a shader to take an image and apply an 8 bit color (so I need 256 colors) dithering (either Floyd–Steinberg or positioned). Edit: actually, I'd like to implement the Floyd–Steinberg method in the shader logic.
The method both Ulydev and I used basically consists in applying a 0-1 dither to every component in the image: first take the R image and generate a dithered one with just two quantization levels, 0 and 1, then do the same with the G one and then with the B one, then put all of them together. I think it would not be too difficult to quantize each component to more levels, e.g. 0, 0.33, 0.67, 1 for 4 levels, though the shader wouldn't be so fast.
If you want 256 colours, it could be done with 8 levels for green, 8 for red and 4 for blue (giving 8*8*4=256 colours). But making it adapt to a predetermined palette is more difficult, and I can't think right away of a strategy that would work in a shader.
Edit: It can be done in Lua, though. I can't vouch for the speed.
- alberto_lara
- Party member
- Posts: 372
- Joined: Wed Oct 30, 2013 8:59 pm
Re: Looking for a dithering shader
Ah, right, I missed that! I guess I'll have to apply the dithering in the file image then and just draw it without shaders. Thanks a lot.
Who is online
Users browsing this forum: No registered users and 6 guests