Gunroar:Cannon() wrote: ↑Wed Apr 19, 2023 3:24 pm
A lot of light would appear white ( though wouldn't a lot of green light still appear green?).
With the additive method the sum of only two green lights will always appear green, for example:
Code: Select all
(0,1,0) + (0,1,0) = (0,2,0) -- Will always give the same green
(1,0,0) + (0,1,0) = (1,1,0) -- Red color plus green color will give yellow color
(1,1,0) + (0,0,1) = (1,1,1) -- Yellow color plus blue color will result in white color
But I tried to hack something with a linear function like this (where `t` is the intensity obtained via the distance from the light source):
Code: Select all
local function lerpColor(c1, c2, t)
c1[1] = c1[1] * (1 - t) + c2[1] * t
c1[2] = c1[2] * (1 - t) + c2[2] * t
c1[3] = c1[3] * (1 - t) + c2[3] * t
end
And here is what it gives:
However it should be noted that the color mixing behaves in a way that the last color of the table will have a greater weight than the others, besides this fact, the rendering may be a little more "realistic" in a way because what I mentioned before is an approximation. To be more precise, in real life light blends don't always produce white. There are many factors at play, such as the colors of the surfaces involved, their reflectivity and texture, etc. And in some of these cases one color could subtract another. The calculations necessary to obtain a 100% realistic result will be much more complex, and at this level the use of a shader would be better. I think that here, whatever solution you choose, you will have a good compromise.
But if you want to go even further, according to my research, we could consider a method of subtraction using
CMY colors that we convert back to RGB, or also by doing the work from
HSL colors and converting back to RGB, but it gets more computationally advanced and that's where a shader would be more appropriate.
But be sure that if I find a better solution not too cumbersome to implement to your problem I will share it because I am also interested.
However without going too far, the addition of color which gives white, for the management of 2D light is quite suitable, we are not in high-flying simulation and the end user should not ask too many questions.
You can see how other Löve libraries handle light:
https://github.com/dylhunn/simple-love-lights
https://github.com/xiejiangzhi/light
https://github.com/speakk/lighter
The full last try code:
Code: Select all
-- Initialize light colors --
local lightColors = {
{ -- yellow (player)
x = 1, y=1,
1, 1, 0
};
{ -- red
x = 5, y=5,
1, 0, 0
},
{ -- green
x = 15, y=10,
0, 1, 0
},
{ -- blue
x = 10, y=15,
0, 0, 1
},
}
local mapWidth = 100
local mapHeight = 75
local tileWidth = 8
local tileHeight = 8
-- Main functions --
local function lerpColor(c1, c2, t)
c1[1] = c1[1] * (1 - t) + c2[1] * t
c1[2] = c1[2] * (1 - t) + c2[2] * t
c1[3] = c1[3] * (1 - t) + c2[3] * t
end
local function drawMap()
for x = 1, mapWidth do
for y = 1, mapHeight do
local color = {0, 0, 0}
for i, lc in ipairs(lightColors) do
local distance = math.sqrt((x-lc.x)^2+(y-lc.y)^2)
local intensity = 1 / (distance + 1)
lerpColor(color, lc, intensity)
end
love.graphics.setColor(color)
love.graphics.rectangle("fill", (x-1)*tileWidth, (y-1)*tileHeight, tileWidth, tileHeight)
end
end
end
function love.keypressed(k)
local p = lightColors[1]
if k == "up" then
p.y = math.max(p.y - 1, 1)
elseif k == "down" then
p.y = math.min(p.y + 1, mapHeight)
elseif k == "left" then
p.x = math.max(p.x - 1, 1)
elseif k == "right" then
p.x = math.min(p.x + 1, mapWidth)
end
end
local scale = 1
function love.wheelmoved(x, y)
scale = scale + y
end
function love.draw()
love.graphics.push()
love.graphics.scale(scale)
drawMap()
love.graphics.pop()
end