Other ways than shaders for transparent color?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Eglaios
Prole
Posts: 36
Joined: Mon May 03, 2021 8:45 pm

Other ways than shaders for transparent color?

I'd want to make an overlay transition like this one :
(at 0:26)

Well that guy really seems to enjoy Pokémon...

Here's what I planned to do :
-Create a canvas with window dimensions, make it all black using love.graphics.clear
-Draw a white circle that'll shrink over time on this canvas
-Render the canvas with a shader to make the white area transparent.

I'd like to know if there'd be a way to do this while avoiding shaders...

Thank you!
Currently working on game music...
BrotSagtMist
Citizen
Posts: 64
Joined: Fri Aug 06, 2021 10:30 pm

Re: Other ways than shaders for transparent color?

You can just draw transparent as a normal colour.
TL:DR:
love.graphics.setBlendMode("replace")
love.graphics.setColor(0,0,0,0)
obey
Eglaios
Prole
Posts: 36
Joined: Mon May 03, 2021 8:45 pm

Re: Other ways than shaders for transparent color?

BrotSagtMist wrote: Thu Sep 23, 2021 10:11 pm It happens we just had that already too: https://love2d.org/forums/viewtopic.php?f=14&t=92033
Thank you for pointing it out, I didn't read that far into this...
Should I delete this topic, then?
Currently working on game music...
MrFariator
Party member
Posts: 282
Joined: Wed Oct 05, 2016 11:53 am

Re: Other ways than shaders for transparent color?

You can also use stencils to achieve this same effect, which may be useful for more complex shapes than simple circles. You'll just have to define a stencil function that draws a circle shape, shrink it over time, and everything this circle is not touching gets rendered. So when the rectangle is being drawn with the stencil function active, it'd punch a hole in it.

Here's some sample code that draws a rectangle with a hole in it (untested):

Code: Select all

local myStencilFunc = function ()
love.graphics.circle ( "fill", 100, 100, 50 ) -- shrink/increase these values over time to change the hole's size
end

function love.draw()
-- increment the stencil value of every pixel that touches the stencil function's circle
love.graphics.stencil(myStencilFunc, "increment", 1)

-- Only allow rendering of pixels which have a stencil value less than 1.
love.graphics.setStencilTest("less", 1)

-- for testing purposes, lets draw the rectangle with a hole in it red
love.graphics.setColor  (1, 0, 0, 1)
love.graphics.rectangle ("fill", 0, 0, 200, 200)

love.graphics.setColor  (1, 1, 1, 1)
love.graphics.setStencilTest()
end
The resulting output should look roughly like this (the black area should show whatever it is that's being rendered behind the red rect):
Last edited by MrFariator on Thu Sep 23, 2021 10:31 pm, edited 2 times in total.
pgimeno
Party member
Posts: 2825
Joined: Sun Oct 18, 2015 2:58 pm

Re: Other ways than shaders for transparent color?

Edit: Ninja'd by MrFariator but I think this post may still be useful.

A shader will work quite well; but if you really must avoid it, one alternative is a stencil.

Code: Select all

local totalTime = 2
local objects = {}
local speed = 600
local effect = false
local canvas = love.graphics.newCanvas()
local T = 0

local function newObject()
return {love.math.random(0, love.graphics.getWidth()-1),
love.math.random(0, love.graphics.getHeight()-1)}
end

for i = 1, 10 do
objects[i] = newObject()
end

function love.keypressed(k)
if k == "escape" then return love.event.quit() end
if k == "space" then T = totalTime; effect = true end
end

local function circle()
local hw, hh = love.graphics.getWidth()/2, love.graphics.getHeight()/2
if T > 0 then
love.graphics.circle("fill", hw, hh, T/totalTime*math.sqrt(hw*hw + hh*hh))
end
end

function love.update(dt)
if T > 0 then
T = T - dt
end
for i = 1, #objects do
local obj = objects[i]
obj[1] = obj[1] + (math.random() - 0.5) * dt * speed
obj[2] = obj[2] + (math.random() - 0.5) * dt * speed
end
end

function love.draw()
love.graphics.setCanvas(canvas)
love.graphics.clear(.5, .5, .5)
for i = 1, #objects do
local obj = objects[i]
love.graphics.rectangle("fill", obj[1], obj[2], 8, 8)
end
love.graphics.setCanvas()

if effect then
love.graphics.stencil(circle)
love.graphics.setStencilTest("gequal", 1)
end
love.graphics.draw(canvas)
love.graphics.print(T)
end

Edit: Another alternative is to use two canvases. This is better in that any antialiasing that the circle gets, goes to the final result; however I don't think there's any antialiasing for filled circles anyway. In the example above, modify the initialization to create two canvases instead of one:

Code: Select all

local canvasRender = love.graphics.newCanvas()
local canvasCrop = love.graphics.newCanvas()

then modify love.draw as follows:

Code: Select all

function love.draw()
love.graphics.setCanvas(canvasRender)
love.graphics.clear(.5, .5, .5)
for i = 1, #objects do
local obj = objects[i]
love.graphics.rectangle("fill", obj[1], obj[2], 8, 8)
end
love.graphics.setCanvas()

if effect then
love.graphics.setCanvas(canvasCrop)
love.graphics.clear(0,0,0,0)
circle()
love.graphics.setCanvas(canvasRender)
love.graphics.setBlendMode("multiply", "premultiplied")
love.graphics.draw(canvasCrop)
love.graphics.setCanvas()
love.graphics.setBlendMode("alpha", "alphamultiply")
end
love.graphics.draw(canvasRender)
love.graphics.print(T)
end

grump
Party member
Posts: 815
Joined: Sat Jul 22, 2017 7:43 pm

Re: Other ways than shaders for transparent color?

pgimeno wrote: Thu Sep 23, 2021 10:29 pm however I don't think there's any antialiasing for filled circles anyway
Draw a filled circle, then a line circle with the same radius. Or enable MSAA for the circle canvas.

Who is online

Users browsing this forum: No registered users and 60 guests