Ok so I'm starting a new thread for this to keep it separate from the thread I made in Games and Creations, even though there were some suggestions there. (viewtopic.php?f=14&t=94562)
So in my game, there are these polygons that make up the bulk of the level. However, it is clear that these aren't working well on a lot of people's computers, so I'm looking for a way to improve performance without sacrificing the way they look.
Requirements:
- Must have pixelated edges (not just the texture itself)
- Must be able to rotate
My current way of doing this is as follows:
1) Polygon vertices are loaded or drawn
2) A lower resolution canvas is created
3) The image is then drawn on to the canvas (how isn't really important)
4) The resulting canvas is stored
5) The stored canvas is then scaled up and drawn, resulting in the pixellated look
This method seriously seems to be causing some slowdown for some people, and I knew from the start it wasn't ideal. Is there a better way of acheiving this? Using a textured mesh directly loses the pixellated edges, so I tried generating more points using the Bresenham Line-Drawing Algorithm to pixellate it, but I've been unsuccessful in getting it to work properly, and I'm worried the number of triangles needed to be drawn for this could be worse. I'm not a very experienced developer, so any ideas will be appreciated.
Need a better way of drawing pixellated polygons
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Re: Need a better way of drawing pixellated polygons
1) We have vertices of polygon, also dimensions of it.
2) Create canvas with size of polygon and dpi = 1/scaleSize https://love2d.org/wiki/love.graphics.newCanvas
3) Draw polygon on this canvas
4) Use stencil to draw texture with stencil https://love2d.org/wiki/love.graphics.stencil
2) Create canvas with size of polygon and dpi = 1/scaleSize https://love2d.org/wiki/love.graphics.newCanvas
3) Draw polygon on this canvas
4) Use stencil to draw texture with stencil https://love2d.org/wiki/love.graphics.stencil
Re: Need a better way of drawing pixellated polygons
Ah this is what I'm already doing - the idea is to not do this because some of the polygons are too big.darkfrei wrote: ↑Fri May 19, 2023 8:43 pm 1) We have vertices of polygon, also dimensions of it.
2) Create canvas with size of polygon and dpi = 1/scaleSize https://love2d.org/wiki/love.graphics.newCanvas
3) Draw polygon on this canvas
4) Use stencil to draw texture with stencil https://love2d.org/wiki/love.graphics.stencil
One of the best suggestions I've had so far is to divide them up into chunks so that not the whole thing needs to drawn at any given time, but that'll increase the loading time due to needing to call newCanvas more times
Dragon
Re: Need a better way of drawing pixellated polygons
You are right, we are need the canvas with the size of screen and low-dpi, all polygons that are not on the screen changes nothing.Bobble68 wrote: ↑Fri May 19, 2023 8:51 pmAh this is what I'm already doing - the idea is to not do this because some of the polygons are too big.darkfrei wrote: ↑Fri May 19, 2023 8:43 pm 1) We have vertices of polygon, also dimensions of it.
2) Create canvas with size of polygon and dpi = 1/scaleSize https://love2d.org/wiki/love.graphics.newCanvas
3) Draw polygon on this canvas
4) Use stencil to draw texture with stencil https://love2d.org/wiki/love.graphics.stencil
One of the best suggestions I've had so far is to divide them up into chunks so that not the whole thing needs to drawn at any given time, but that'll increase the loading time due to needing to call newCanvas more times
Re: Need a better way of drawing pixellated polygons
A mesh made of long rectangles with one rectangle per pixel row?
Re: Need a better way of drawing pixellated polygons
For example the checkered texture with white polygon:
-------------------------------
And the pixelated polygon (move mouse to change geometry) with texture on it (of coarse here can be any texture, not checkered or low-dpi):
-------------------------------------------------
And the version with rotating polygon:
Code: Select all
Width, Height = love.graphics.getDimensions ()
PixelSize = 16
love.graphics.setDefaultFilter ('nearest', 'nearest')
-- prepare checker texture
local checker = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas (checker)
for y = 0, Height-1*PixelSize, PixelSize do
for x = 0, Width-1*PixelSize, PixelSize do
if (x/PixelSize+y/PixelSize)%(2) == 0 then
love.graphics.setColor (0.2,0.2,0.2)
else
love.graphics.setColor (0.4,0.4,0.4)
end
love.graphics.rectangle ('fill', x,y, PixelSize, PixelSize)
end
end
Polygon = {10, 300, 400,30, 700,200, 200,500}
love.graphics.setColor (1,1,1)
love.graphics.polygon ('fill', Polygon)
love.graphics.setCanvas ()
function love.draw()
love.graphics.draw (checker)
end
And the pixelated polygon (move mouse to change geometry) with texture on it (of coarse here can be any texture, not checkered or low-dpi):
Code: Select all
Width, Height = love.graphics.getDimensions ()
PixelSize = 16
love.graphics.setDefaultFilter ('nearest', 'nearest')
-- prepare checker texture
local checker = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas (checker)
for y = 0, Height-1*PixelSize, PixelSize do
for x = 0, Width-1*PixelSize, PixelSize do
if (x/PixelSize+y/PixelSize)%(2) == 0 then
love.graphics.setColor (0.2,0.2,0.2)
else
love.graphics.setColor (0.4,0.4,0.4)
end
love.graphics.rectangle ('fill', x,y, PixelSize, PixelSize)
end
end
love.graphics.setCanvas ()
local function getMask (polygon)
local mask = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas (mask)
love.graphics.setColor (1,1,1)
love.graphics.polygon ('fill', polygon)
love.graphics.setCanvas ()
return mask
end
local mask_shader = love.graphics.newShader[[
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
if (Texel(texture, texture_coords).rgb == vec3(0.0)) {
// a discarded pixel wont be applied as the stencil.
discard;
}
return vec4(1.0);
}
]]
local function myStencilFunction()
love.graphics.setShader(mask_shader)
love.graphics.draw(Mask, 0, 0)
love.graphics.setShader()
end
function love.load()
Polygon = {10, 300, 400,30, 700,200, 200,500}
Mask = getMask (Polygon)
ResultCanvas = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas ({ResultCanvas, stencil=true})
love.graphics.stencil(myStencilFunction, "replace", 1)
love.graphics.setStencilTest("greater", 0)
love.graphics.draw(checker)
love.graphics.setStencilTest()
love.graphics.setCanvas ()
end
function love.draw()
-- love.graphics.draw (checker)
love.graphics.draw (ResultCanvas)
end
function love.mousemoved (x, y)
Polygon[#Polygon-1], Polygon[#Polygon] = x, y
Mask = getMask (Polygon)
ResultCanvas = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas ({ResultCanvas, stencil=true})
love.graphics.stencil(myStencilFunction, "replace", 1)
love.graphics.setStencilTest("greater", 0)
love.graphics.draw(checker)
love.graphics.setStencilTest()
love.graphics.setCanvas ()
end
And the version with rotating polygon:
Code: Select all
Width, Height = love.graphics.getDimensions ()
PixelSize = 16
love.graphics.setDefaultFilter ('nearest', 'nearest')
-- prepare checker texture
local checker = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas (checker)
for y = 0, Height-1*PixelSize, PixelSize do
for x = 0, Width-1*PixelSize, PixelSize do
if (x/PixelSize+y/PixelSize)%(2) == 0 then
love.graphics.setColor (0.2,0.2,0.2)
else
love.graphics.setColor (0.4,0.4,0.4)
end
love.graphics.rectangle ('fill', x,y, PixelSize, PixelSize)
end
end
love.graphics.setCanvas ()
local function getMask (polygon)
local cx, cy, angle = polygon.cx, polygon.cy, polygon.angle
local mask = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize}) -- change this solution to not create new canvas on each frame! :x
love.graphics.setCanvas (mask)
love.graphics.setColor (1,1,1)
love.graphics.push ()
love.graphics.translate (cx, cy)
love.graphics.rotate (angle)
love.graphics.translate (-cx, -cy)
love.graphics.polygon ('fill', polygon)
love.graphics.pop ()
love.graphics.setCanvas ()
return mask
end
local mask_shader = love.graphics.newShader[[
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
if (Texel(texture, texture_coords).rgb == vec3(0.0)) {
// a discarded pixel wont be applied as the stencil.
discard;
}
return vec4(1.0);
}
]]
local function myStencilFunction()
love.graphics.setShader(mask_shader)
love.graphics.draw(Mask, 0, 0)
love.graphics.setShader()
end
function love.load()
Polygon = {10, 300, 400,30, 700,200, 200,500}
Polygon.cx, Polygon.cy = 400, 250
Polygon.angle, Polygon.omega = 0, 0.3
end
function love.update(dt)
Polygon.angle = Polygon.angle + dt*Polygon.omega
Mask = getMask (Polygon)
ResultCanvas = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
love.graphics.setCanvas ({ResultCanvas, stencil=true})
love.graphics.stencil(myStencilFunction, "replace", 1)
love.graphics.setStencilTest("greater", 0)
love.graphics.draw(checker)
love.graphics.setStencilTest()
love.graphics.setCanvas ()
end
function love.draw()
-- love.graphics.draw (checker)
love.graphics.draw (ResultCanvas)
end
function love.mousemoved (x, y)
Polygon[#Polygon-1], Polygon[#Polygon] = x, y
end
- Attachments
-
- pixelated-polygons-02.love
- (936 Bytes) Downloaded 92 times
Last edited by darkfrei on Sat May 20, 2023 8:13 am, edited 2 times in total.
- zorg
- Party member
- Posts: 3470
- Joined: Thu Dec 13, 2012 2:55 pm
- Location: Absurdistan, Hungary
- Contact:
Re: Need a better way of drawing pixellated polygons
I hope you didn't forget to read the wiki's warning about creating stuff, like canvases for example.Bobble68 wrote: ↑Fri May 19, 2023 6:40 pm My current way of doing this is as follows:
1) Polygon vertices are loaded or drawn
2) A lower resolution canvas is created
3) The image is then drawn on to the canvas (how isn't really important)
4) The resulting canvas is stored
5) The stored canvas is then scaled up and drawn, resulting in the pixellated look
This method seriously seems to be causing some slowdown for some people, and I knew from the start it wasn't ideal.
You are not creating a new canvas every frame, right?
If you are, that might be your issue, considering none of the other things seem too bad on performance.
Me and my stuff True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Re: Need a better way of drawing pixellated polygons
This isn't what I need though - I don't just need it to rotate, I need the pixel grid itself to rotate, as I already have in the game.
Yeah I have, that's why I specified that the canvas is stored. The thing is it runs fine on my own computer, but a lot of people are complaining about poor performance, and I know the islands take around 50% of the rendering time so I'm looking for a way to improve them.
Dragon
Re: Need a better way of drawing pixellated polygons
OK, I thought that you want to go from smooth pixels to pixel perfect solution, that looks like the old game.
But you can draw the polygon without inclination, but use the tilted mask for it.
Code: Select all
Width, Height = love.graphics.getDimensions ()
PixelSize = 8
love.graphics.setDefaultFilter ('nearest', 'nearest')
-- prepare checker texture
local checker = love.graphics.newCanvas ()
love.graphics.setCanvas (checker)
for y = 0, Height-1*PixelSize, PixelSize do
for x = 0, Width-1*PixelSize, PixelSize do
if (x/PixelSize+y/PixelSize)%(2) == 0 then
love.graphics.setColor (0.6,0.6,0.6)
else
love.graphics.setColor (0.4,0.4,0.4)
end
love.graphics.rectangle ('fill', x,y, PixelSize, PixelSize)
end
end
love.graphics.setCanvas ()
-- low-res mask canvas
Mask = love.graphics.newCanvas (Width, Height, {dpiscale=1/PixelSize})
ResultCanvas = love.graphics.newCanvas ()
local mask_shader = love.graphics.newShader[[
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) {
if (Texel(texture, texture_coords).rgb == vec3(0.0)) {
// a discarded pixel wont be applied as the stencil.
discard;
}
return vec4(1.0);
}
]]
local function myStencilFunction()
love.graphics.setShader(mask_shader)
love.graphics.draw(Mask, Polygon.cx, Polygon.cy, Polygon.angle, 1,1, Polygon.cx, Polygon.cy)
love.graphics.setShader()
end
function love.load()
Polygon = {10, 300, 400,30, 700,200, 200,500}
Polygon.cx, Polygon.cy = 400, 250
Polygon.angle, Polygon.omega = 0, 0.3
-- setup mask
love.graphics.setCanvas (Mask)
love.graphics.setColor (1,1,1)
love.graphics.polygon ('fill', Polygon)
love.graphics.setCanvas ()
end
function love.update(dt)
Polygon.angle = Polygon.angle + dt*Polygon.omega
-- update result
love.graphics.setCanvas ({ResultCanvas, stencil=true})
love.graphics.clear ()
love.graphics.stencil(myStencilFunction, "replace", 1)
love.graphics.setStencilTest("greater", 0)
love.graphics.draw(checker)
love.graphics.setStencilTest()
love.graphics.setCanvas ()
end
function love.draw()
love.graphics.draw (ResultCanvas)
end
Re: Need a better way of drawing pixellated polygons
Here's a proof of concept for that. I took the liberty of extracting stone.png from your game for this demo, I hope you don't mind.
As I commented in the other thread, the texture is first drawn to a canvas in nearest neighbour mode with a floor(magnification factor) zoom factor, then the canvas interpolation mode is set to linear filtering. That canvas is then used as the mesh texture.
- Attachments
-
- texturedPolyPOC.love
- (3.72 KiB) Downloaded 56 times
Who is online
Users browsing this forum: Ahrefs [Bot], CutePenguin and 5 guests