## Löve "Light vs. Shadow" Engine v2

szensk
Party member
Posts: 155
Joined: Sat Jan 19, 2013 3:57 am

### Re: Löve "Light vs. Shadow" Engine v2

PriorBlue wrote:I watched the last days over your code and i was surprised how much work do you put in the changes, i think the new direction of your system is very good, you have even added new postshader and improved the others like the scanline shader, awesome! I don't know, if you really need my help in the future, your changes look really great.

Oh and by the way, you can add your name in all files of the project or you can remove/change the MIT licence, if you want. The project is now officially yours .
I löve when there is a happy open-source fork
Jeeper
Party member
Posts: 588
Joined: Tue Mar 12, 2013 7:11 pm
Contact:

### Re: Löve "Light vs. Shadow" Engine v2

Just a PSA to anyone who intends to use this library and is using STI, the v2 of Shadow vs light changed the way it uses canvases and does not like STI for that reason. After struggling for a long time with trying to implement this updated version to my current project, I spoke to "drunken_thor" (Who manages the library) and he confirmed that it is not compatible with STI.

The old Shadow vs Light does not have this issue however, so If you intend to use STI then I would recommend using it. A few major improvements made in this version are missing though, but I have managed to fix most of them (Such as scaling and translation, removal of shadow and light bodies etc). So if you intend to do like me and use the older version, feel free to ask for help in case you run into any issues.
nfey
Citizen
Posts: 63
Joined: Tue Feb 18, 2014 9:50 am
Location: Romania

### Re: Löve "Light vs. Shadow" Engine v2

@drunken_thor : think you can post some info on the math used to calculate the shadows, per body? Specifically I am talking about body:calculatePolyShadow(). I'm looking at it and scratching my head and it's kinda hard to understand what it's doing with no comments and especially without being able to visualize what's happening.
I'm asking because I'm trying to reverse-engineer that part of the engine so that I can use it for other stuff, apart from lighting.

And of course, thanks a lot for your work on this.
drunken_thor
Citizen
Posts: 75
Joined: Wed Oct 01, 2014 12:14 am
Contact:

### Re: Löve "Light vs. Shadow" Engine v2

nfey wrote:@drunken_thor : think you can post some info on the math used to calculate the shadows, per body? Specifically I am talking about body:calculatePolyShadow(). I'm looking at it and scratching my head and it's kinda hard to understand what it's doing with no comments and especially without being able to visualize what's happening.
I'm asking because I'm trying to reverse-engineer that part of the engine so that I can use it for other stuff, apart from lighting.

And of course, thanks a lot for your work on this.
Yeah sure just give me a a little while because I was just working on that specific part to make the shadows actually end somewhere and have more of a 3D quality to them.

I can get you started on it though.

Code: Select all

function body:calculatePolyShadow(light)
return nil
end

local curPolygon = self.data
local edgeFacingTo = {}
-- for each edge check if the light strikes it
for k = 1, #curPolygon, 2 do
local indexOfNextVertex = (k + 2) % #curPolygon
-- get the unit vector of the edge
local normal = {-curPolygon[indexOfNextVertex+1] + curPolygon[k + 1], curPolygon[indexOfNextVertex] - curPolygon[k]}
normal = vector.normalize(normal)
-- get the unit vector of the light pointing at the current point we are examing
-- [hint] we are looking for the outter most edges of the polygon that the light hits
local lightToPoint = {curPolygon[k] - light.x, curPolygon[k + 1] - light.y}
lightToPoint = vector.normalize(lightToPoint)

--get the dot product of the two vectors to see if it faces the light
local dotProduct = vector.dot(normal, lightToPoint)
-- if the dot product is greater than 0 it faces the light
if dotProduct > 0 then
table.insert(edgeFacingTo, true)
-- if the dot product is 0 it is perpendicular
-- if it is less than 0 it faces away from the light
else
table.insert(edgeFacingTo, false)
end
end

--now we have a table that tells us which edges are hit by the light

-- for each point in the polygon again but referencing the edges
for k = 1, #edgeFacingTo do
local nextIndex = (k + 1) % #edgeFacingTo
if nextIndex == 0 then nextIndex = #edgeFacingTo end
-- if this edge is in the light but not the next
-- create the first 2 points of the polygon we have found an edge of the shadow
if edgeFacingTo[k] and not edgeFacingTo[nextIndex] then

--cast the edge beyond the shape in the direction of the vector from the light to the point
local lightVecFrontBack = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y})
-- if this edfe is not in the light but the next one is the we found the last 2 points of the shadow
elseif not edgeFacingTo[k] and edgeFacingTo[nextIndex] then

--cast the edge beyond the shape in the direction of the vector from the light to the point
local lightVecBackFront = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y})
end
end
--we only draw long rectangular shadows
--so they must have 4 points
then
else
return nil
end
end

Light_world.lua for all your lighting needs
Github
drunken_thor
Citizen
Posts: 75
Joined: Wed Oct 01, 2014 12:14 am
Contact:

### Re: Löve "Light vs. Shadow" Engine v2

nfey wrote:@drunken_thor : think you can post some info on the math used to calculate the shadows, per body? Specifically I am talking about body:calculatePolyShadow(). I'm looking at it and scratching my head and it's kinda hard to understand what it's doing with no comments and especially without being able to visualize what's happening.
I'm asking because I'm trying to reverse-engineer that part of the engine so that I can use it for other stuff, apart from lighting.

And of course, thanks a lot for your work on this.
@nfey okay so I improved the shadow body calculations in the library and really found this paper helpful when doing so http://web.cs.wpi.edu/~matt/courses/cs5 ... hadow.html
Light_world.lua for all your lighting needs
Github
nfey
Citizen
Posts: 63
Joined: Tue Feb 18, 2014 9:50 am
Location: Romania

### Re: Löve "Light vs. Shadow" Engine v2

@drunken_thor - thanks a lot, this really helps with understanding what's going on.
Relazy
Citizen
Posts: 51
Joined: Thu Jul 10, 2014 11:10 pm

### Re: Löve "Light vs. Shadow" Engine v2

Is there a way to make this work with Hump camera? I can't set the translation right. I can attach a light to the mouse co-ordinates on the camera but it fails when I want to set a fixed location for a shadow body on world co-ordinates. I tried to :setPosition() within camera attach and detach functions but it didn't make any difference.
drunken_thor
Citizen
Posts: 75
Joined: Wed Oct 01, 2014 12:14 am
Contact:

### Re: Löve "Light vs. Shadow" Engine v2

Relazy wrote:Is there a way to make this work with Hump camera? I can't set the translation right. I can attach a light to the mouse co-ordinates on the camera but it fails when I want to set a fixed location for a shadow body on world co-ordinates. I tried to :setPosition() within camera attach and detach functions but it didn't make any difference.
It should work with all translations done with love, are you passing in your translation and scale on the lightworld:draw() call? can I see your code?
Light_world.lua for all your lighting needs
Github
Relazy
Citizen
Posts: 51
Joined: Thu Jul 10, 2014 11:10 pm

### Re: Löve "Light vs. Shadow" Engine v2

drunken_thor wrote:
Relazy wrote:Is there a way to make this work with Hump camera? I can't set the translation right. I can attach a light to the mouse co-ordinates on the camera but it fails when I want to set a fixed location for a shadow body on world co-ordinates. I tried to :setPosition() within camera attach and detach functions but it didn't make any difference.
It should work with all translations done with love, are you passing in your translation and scale on the lightworld:draw() call? can I see your code?
I am not sure what translation to use because hump handles the camera with two sets of co-ordinates: one for camera:worldCoords() and one for camera:cameraCoords(), heres an example(use WSAD to move camera. up key + enter for selection of the translation):

Code: Select all

local LightWorld = require "lib"

local lightworld = LightWorld({
drawBackground = drawBackground,
drawForeground = drawForeground,
ambient = {50,50,50},
})

Camera = require "hump.camera"
fthis = 0
this2 = 0
cx = 360
cy = 350
px = 400
py = 300
camera = Camera(0,0)
a = lightworld:newLight(love.mouse.getX(),love.mouse.getY(),155,155,20,200)
b = lightworld:newRectangle(px,py,200,200)
end
function love.draw()
if this2 == 1 then
x,y = camera:worldCoords(10,10)
elseif this2 == 2 then
x,y = camera:cameraCoords(10,10)
elseif this2 == 3 then
local tx,ty = love.graphics.getWidth()/(2*camera.scale), love.graphics.getHeight()/(2*camera.scale)
--the previous method from old light v shadow
x = tx-10
y = ty-10
else
x = 0
y = 0
end
love.graphics.push()
love.graphics.translate(x,y)
-- I am currently on default scale which is 1 so I assume there isn't a need to translate by love.graphics.scale().
lightworld:draw(x,y,1)
love.graphics.pop()

love.graphics.setColor(126,85,98)
love.graphics.rectangle("fill",0,100,300,20)
if fthis == 1 then
love.graphics.setColor(240,200,200)
end
love.graphics.rectangle("fill",0,120,300,20)
love.graphics.setColor(126,85,98)
if fthis == 2 then
love.graphics.setColor(240,200,200)
end
love.graphics.rectangle("fill",0,140,300,20)
love.graphics.setColor(126,85,98)
if fthis == 3 then
love.graphics.setColor(240,200,200)
end
love.graphics.rectangle("fill",0,160,300,20)
love.graphics.setColor(126,85,98)

love.graphics.setColor(255,255,255)
love.graphics.print("The current translation is: "..this2,0,100)
love.graphics.print("1:Set translation to camera:worldCoords()",0,120)
love.graphics.print("2:Set translation to camera:camCoords()",0,140)
love.graphics.print("3:Set translation to light v shadow v1",0,160)
love.graphics.print("camera x:"..camera.x,0,180)
love.graphics.print("camera y:"..camera.y,0,190)
end
function love.keypressed(key)
-- movement and selection of translation
if key == "a" then
px = px + 40
elseif key == "d" then
px = px - 40
end
if key == "w" then
py = py + 40
elseif key == "s" then
py = py - 40
end
if fthis < 4 and fthis > 0 then
if key == "up" then
fthis = fthis + 1
end
if key == "return" then
this2 = fthis
end
else
fthis = 1
end
end
function love.update(dt)
a:setPosition(love.mouse.getX(),love.mouse.getY())
love.window.setTitle(""..love.timer.getFPS())
camera:lookAt(px,py)
end
function lightworld:drawBackground()
love.graphics.setColor(152,150,97)
love.graphics.rectangle("fill",0,0,800,600)
love.graphics.setColor(255,255,255)
camera:attach()
camera:detach()
end
function lightworld:drawForeground()
camera:attach()
--cx2,cy2 = camera:worldCoords(cx,cy)
--b:setPosition(cx2,cy2)
b:setPosition(cx,cy)
love.graphics.setColor(100,100,190)
love.graphics.rectangle("fill",cx,cy,200,200)
love.graphics.setColor(200,200,200)
love.graphics.rectangle("fill",px,py,20,20) -- illustrated the point at which camera looks at
love.graphics.setColor(255,255,255)
camera:detach()
end

Attachments
this.love
drunken_thor
Citizen
Posts: 75
Joined: Wed Oct 01, 2014 12:14 am
Contact:

### Re: Löve "Light vs. Shadow" Engine v2

@relazy I will be releasing a new, simpler, faster version of this library within a week. I will add example of both hump and gamera. I will let you know when I release it.

small teasers of what is to come to hopefully help the wait:
- much faster drawing (took out 3 separate shaders and integrated them all into one draw)
- single callback draw call (like gamera's draw call) to simplify use
- integrated animation using normal maps :O
- [and now] example for most used cameras
Light_world.lua for all your lighting needs
Github