love.graphics.rectangle pixel snapping

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
JayKyburz
Prole
Posts: 9
Joined: Wed May 19, 2021 10:47 pm

love.graphics.rectangle pixel snapping

Post by JayKyburz »

Hey, I've been prototyping a new game. I've noticed that when I draw rectangles to the screen the coordinates are snapped to the nearest whole pixel.

This causes slow animations to look jerky.

Is there a way to disable this behavior. The rects will have soft edges, but the animation should be smooth.
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: love.graphics.rectangle pixel snapping

Post by pgimeno »

No, but there are a few things you can do.
  1. Frame the rectangle with another rectangle in line mode, setting love.graphics.setLineWidth(2) so that there's one whole pixel to each side of the line. Reduce the inner rectangle by 2 pixels to compensate for the 2 added pixels (one at each border).
  2. Use an image with an alpha border instead of a rectangle. It doesn't need to be stored on disk, you can create it at load time.
  3. Use a shader to draw the rectangle borders. Draw the rectangle as an image.
Each method has its drawbacks.
  • Method 1 is a bit more expensive in terms of CPU.
  • Method 2 is a bit more expensive in terms of video memory. It needs one image per rectangle size.
  • Method 3 is a bit more expensive in terms of GPU and programmer effort, because it needs the size of the rectangle to be passed to the shader.
Here's a comparison. To me, method 3 looks best, but that's a subjective appreciation. Assumes 800x600, so if you try this on a mobile you may need to make adjustments.

Code: Select all

-- Size of all rectangles is 200x100.

-- line width for method 1
love.graphics.setLineWidth(2)

-- image for method 2
local rectimg200x100 = love.graphics.newImage(love.image.newImageData(202, 102,
  "rgba8", ("\0\0\0\0"):rep(202) 
        .. ("\0\0\0\0" .. ("\255\255\255\255"):rep(200) .. "\0\0\0\0"):rep(100)
        .. ("\0\0\0\0"):rep(202)))
rectimg200x100:setFilter("linear", "linear")

-- shader for method 3
local shaderect = love.graphics.newShader[[
  uniform float xsize;
  uniform float ysize;

  vec4 effect(vec4 clr, Image tex, vec2 texpos, vec2 scrpos)
  {
    float upixels = texpos.x * xsize;
    float vpixels = texpos.y * ysize;
    clr.a = min(min(upixels < 1.0 ? upixels : xsize - upixels,
                    vpixels < 1.0 ? vpixels : ysize - vpixels),
                1.0);
    return clr * Texel(tex, texpos);
  }
]]

-- image for method 3
local rectimg1x1 = love.graphics.newImage(love.image.newImageData(1, 1,
  "rgba8", "\255\255\255\255"))

local x = 5
local y = 0
local a = 0

function love.update(dt)
  x = x + dt / 2 -- 1 pixel every 2 seconds
  y = math.sin(a) * 10
  a = a + dt / 3 -- 1 radian every 3 seconds
  if a >= math.pi * 2 then a = a - math.pi * 2 end
end

function love.draw()
  -- method 1
  love.graphics.rectangle("line", x+1, 101 + y, 198, 98)
  love.graphics.rectangle("fill", x+1, 101 + y, 198, 98)
  -- method 2
  love.graphics.draw(rectimg200x100, x, 250 + y, 0, 1, 1, 1, 1)
  -- method 3
  love.graphics.setShader(shaderect)
  shaderect:send('xsize', 200)
  shaderect:send('ysize', 100)
  love.graphics.draw(rectimg1x1, x, 400 + y, 0, 200, 100)
  love.graphics.setShader()
end
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: love.graphics.rectangle pixel snapping

Post by grump »

The simplest solution that doesn't require any additional code or tricks and saves draw calls: enable MSAA with 2 or more samples, either for all rendering or just for a Canvas. See https://love2d.org/wiki/love.window.setMode or https://love2d.org/wiki/love.graphics.newCanvas
JayKyburz
Prole
Posts: 9
Joined: Wed May 19, 2021 10:47 pm

Re: love.graphics.rectangle pixel snapping

Post by JayKyburz »

Hey thanks to you both for taking the time to answer.

I have played around with all 4 methods you suggested above. I agree with pgimeno that the shader method does look best, even with msaa 4 I can see a slight jitter, but for the sake of simplicity, I'm just going to use msaa for now.

My game wont have lots of very slow animation, its just something I noticed and was bugging me.
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: love.graphics.rectangle pixel snapping

Post by grump »

The shader method is slow if you draw a lot of boxes, because sending uniforms for every box prevents batching. That can be avoided with instanced rendering, but it's quite a bit of code.
User avatar
pgimeno
Party member
Posts: 3551
Joined: Sun Oct 18, 2015 2:58 pm

Re: love.graphics.rectangle pixel snapping

Post by pgimeno »

MSAA didn't work for me. It's one thing I tried but since I didn't get any result, I didn't recommend it.
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 54 guests