Page 1 of 1

Palette Swap Shader: How to stop it mixing colors from neighboring pixel?

Posted: Sat Nov 03, 2018 8:10 am
by xThomas

Code: Select all

local shader = love.graphics.newShader("palette/shader.glsl")
local palette = love.graphics.newImage("palette/Palette.png")
local sprite = love.graphics.newImage("sprite.png")
sprite:setFilter("nearest", "nearest")

function love.load()
   row = 0.0
end


local w, h = love.graphics.getDimensions()
function love.draw()
   love.graphics.setColor(0,0,0,1)
   love.graphics.rectangle('fill',0,0,w,h)
   love.graphics.setColor(1,1,1,1)
   love.graphics.setShader(shader)
   shader:send("palette", palette)
   shader:send("row", row)
   love.graphics.draw(sprite, 20, 20, 0, 8, 8)
   love.graphics.setShader()
   love.graphics.setColor(1,1,1,1)
   love.graphics.print(" row :"..row, 0, 0)
end

function love.update(dt)
   if love.keyboard.isDown("=") then
      row = row + 0.005
   elseif love.keyboard.isDown("-") then
      row = row - 0.005
   end
end

-- function love.keypressed(key)
--   if key == '=' then
--     row = row + 0.01
--   elseif key == '-' then
--     row = row - 0.01
--   end
-- end

Code: Select all

uniform sampler2D palette;
extern float row;

vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
   vec2 u = Texel(texture, texture_coords).ra;
   vec4 pixel = Texel(palette, vec2(u.r, row));
   pixel.a = u.g;
   return pixel * color;
}
i couldn't include the palette and sprite here, so you'll have to download the attachment. but, based on my code, do you see any solutions right now to my problem? For example, I want to grab red from the 5th row of my texture, which is 4x16 pixels. i could divide 1/16 and then multiply by four, giving me .25, but that would give me purple by mixing red from the 5th row and blue from the 4th. To just get red I needed .28

The demo has a main.lua, and a folder called palette with glsl and sprite. Hold = or - to change the row of the texture. Note that there aren't any rows after a point and it's just blank.

note: love2d uses glsl 1.20, texelFetch was added in 1.30

Re: Palette Swap Shader: How to stop it mixing colors from neighboring pixel?

Posted: Sat Nov 03, 2018 9:07 am
by JoshGrams
Does palette:setFilter("nearest", "nearest") do what you want?

Re: Palette Swap Shader: How to stop it mixing colors from neighboring pixel?

Posted: Sat Nov 03, 2018 4:12 pm
by pgimeno
To grab the top edge of the top pixel, you use y=0/16. To grab the edge at the frontier between the top pixel and the next, you use y=1/16 etc. At the edges, with bilinear filtering active, the colour is a mix between the two pixels.

To avoid the effects of bilinear filtering, you have two options: either sample from pixel centres (the pixel centre is obtained by adding 0.5 to the row index: 0.5/16 is the centre of the top pixel, 1.5/16 is the centre of the second, and so on) or do as JoshGrams said.

For example, to sample from the 5th row without disabling bilinear filtering, the correct position to sample is 4.5/16 = 0.28125.

Sampling from pixel centres is safer even with filtering disabled, because then you're not exposed to rounding errors in corner cases.

Edit: Hopefully this image will make it clearer:
PaletteHalfPixels.png
PaletteHalfPixels.png (48.24 KiB) Viewed 4122 times

Re: Palette Swap Shader: How to stop it mixing colors from neighboring pixel?

Posted: Sat Nov 03, 2018 9:04 pm
by xThomas
informative thank you