hopefully some faster shadow calculations

This commit is contained in:
Tim Anema 2014-12-17 23:16:29 -05:00
parent 80a2d2e389
commit 8cbb10f80d
5 changed files with 96 additions and 95 deletions

View File

@ -3,7 +3,7 @@ local class = require(_PACKAGE.."/class")
local normal_map = require(_PACKAGE..'/normal_map') local normal_map = require(_PACKAGE..'/normal_map')
local util = require(_PACKAGE..'/util') local util = require(_PACKAGE..'/util')
local anim8 = require(_PACKAGE..'/anim8') local anim8 = require(_PACKAGE..'/anim8')
local vec2 = require(_PACKAGE..'/vec2') local vector = require(_PACKAGE..'/vector')
local body = class() local body = class()
body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl") body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl")
@ -626,85 +626,67 @@ function body:drawShadow(light)
end end
end end
local function isEdgeFacingLight(x1, y1, x2, y2, light)
return vec2(-y2 + y1, x2 - x1):dot(vec2(x1 - light.x, y1 - light.y)) > 0
end
--using shadow point calculations from this article --using shadow point calculations from this article
--http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html --http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html
function body:drawPolyShadow(light) function body:drawPolyShadow(light)
local curShadowGeometry = {} local lightPosition = vector(light.x, light.y)
local lxh = (light.x * self.zheight) local lh = lightPosition * self.zheight
local lyh = (light.y * self.zheight)
local height_diff = (self.zheight - light.z) local height_diff = (self.zheight - light.z)
if height_diff == 0 then -- prevent inf if height_diff == 0 then -- prevent inf
height_diff = -0.001 height_diff = -0.001
end end
local facingLight = {}
for i = 1, #self.data, 2 do for i = 1, #self.data, 2 do
local j, k = (i + 2) % #self.data, (i + 4) % #self.data local vertex = vector(self.data[i], self.data[i + 1])
local nextVertex = vector(self.data[(i + 2) % 8], self.data[(i + 2) % 8 + 1])
facingLight[i] = facingLight[i] ~= nil and facingLight[i] or isEdgeFacingLight(self.data[i], self.data[i+1], self.data[j], self.data[j+1], light) local startToEnd = nextVertex - vertex
facingLight[j] = facingLight[j] ~= nil and facingLight[j] or isEdgeFacingLight(self.data[j], self.data[j+1], self.data[k], self.data[k+1], light) if vector(startToEnd.y, -startToEnd.x) * (vertex - lightPosition) > 0 then
local point1 = (lh - (vertex * light.z))/height_diff
if facingLight[i] and not facingLight[j] then local point2 = (lh - (nextVertex * light.z))/height_diff
curShadowGeometry[#curShadowGeometry+1] = self.data[j] love.graphics.polygon("fill",
curShadowGeometry[#curShadowGeometry+1] = self.data[j+1] vertex.x, vertex.y, point1.x, point1.y,
curShadowGeometry[#curShadowGeometry+1] = (lxh - (self.data[j] * light.z))/height_diff point2.x, point2.y, nextVertex.x, nextVertex.y)
curShadowGeometry[#curShadowGeometry+1] = (lyh - (self.data[j+1] * light.z))/height_diff
elseif not facingLight[i] and not facingLight[j] then
curShadowGeometry[#curShadowGeometry+1] = (lxh - (self.data[j] * light.z))/height_diff
curShadowGeometry[#curShadowGeometry+1] = (lyh - (self.data[j+1] * light.z))/height_diff
elseif not facingLight[i] and facingLight[j] then
curShadowGeometry[#curShadowGeometry+1] = (lxh - (self.data[j] * light.z))/height_diff
curShadowGeometry[#curShadowGeometry+1] = (lyh - (self.data[j+1] * light.z))/height_diff
curShadowGeometry[#curShadowGeometry+1] = self.data[j]
curShadowGeometry[#curShadowGeometry+1] = self.data[j+1]
end end
end end
if #curShadowGeometry >= 6 then
love.graphics.polygon("fill", unpack(curShadowGeometry))
end
end end
--using shadow point calculations from this article --using shadow point calculations from this article
--http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html --http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html
function body:drawCircleShadow(light) function body:drawCircleShadow(light)
local curShadowGeometry = {} local selfPos = vector(self.x - self.ox, self.y - self.oy)
local angle = math.atan2(light.x - (self.x - self.ox), (self.y - self.oy) - light.y) + math.pi / 2 local lightPosition = vector(light.x, light.y)
local x1 = ((self.x - self.ox) + math.sin(angle) * self.radius) local lh = lightPosition * self.zheight
local y1 = ((self.y - self.oy) - math.cos(angle) * self.radius)
local x2 = ((self.x - self.ox) - math.sin(angle) * self.radius)
local y2 = ((self.y - self.oy) + math.cos(angle) * self.radius)
local lxh = (light.x * self.zheight)
local lyh = (light.y * self.zheight)
local height_diff = (self.zheight - light.z) local height_diff = (self.zheight - light.z)
if height_diff == 0 then -- prevent inf if height_diff == 0 then -- prevent inf
height_diff = -0.001 height_diff = -0.001
end end
local angle = math.atan2(light.x - selfPos.x, selfPos.y - light.y) + math.pi / 2
local point1 = vector(selfPos.x + math.sin(angle) * self.radius,
selfPos.y - math.cos(angle) * self.radius)
local point2 = vector(selfPos.x - math.sin(angle) * self.radius,
selfPos.y + math.cos(angle) * self.radius)
local point3 = (lh - (point1 * light.z))/height_diff
local point4 = (lh - (point2 * light.z))/height_diff
local x3 = (lxh - (x2 * light.z))/height_diff local radius = point3:dist(point4)/2
local y3 = (lyh - (y2 * light.z))/height_diff local circleCenter = (point3 + point4)/2
local x4 = (lxh - (x1 * light.z))/height_diff
local y4 = (lyh - (y1 * light.z))/height_diff
local radius = math.sqrt(math.pow(x4 - x3, 2) + math.pow(y4-y3, 2)) / 2 if lightPosition:dist(selfPos) <= self.radius then
local cx, cy = (x3 + x4)/2, (y3 + y4)/2 love.graphics.circle("fill", circleCenter.x, circleCenter.y, radius)
if math.sqrt(math.pow(light.x - self.x, 2) + math.pow(light.y - self.y, 2)) <= self.radius then
love.graphics.circle("fill", cx, cy, radius)
else else
love.graphics.polygon("fill", x1, y1, x2, y2, x3, y3, x4, y4) love.graphics.polygon("fill", point1.x, point1.y,
if math.sqrt(math.pow(light.x - cx, 2) + math.pow(light.y - cy, 2)) < light.range then -- dont draw circle if way off screen point2.x, point2.y,
local angle1 = math.atan2(y3 - cy, x3 - cx) point4.x, point4.y,
local angle2 = math.atan2(y4 - cy, x4 - cx) point3.x, point3.y)
if angle1 > angle2 then if lightPosition:dist(circleCenter) < light.range then -- dont draw circle if way off screen
love.graphics.arc("fill", cx, cy, radius, angle1, angle2) local angle1 = math.atan2(point3.y - circleCenter.y, point3.x - circleCenter.x)
local angle2 = math.atan2(point4.y - circleCenter.y, point4.x - circleCenter.x)
if angle1 < angle2 then
love.graphics.arc("fill", circleCenter.x, circleCenter.y, radius, angle1, angle2)
else else
love.graphics.arc("fill", cx, cy, radius, angle1 - math.pi, angle2 - math.pi) love.graphics.arc("fill", circleCenter.x, circleCenter.y, radius, angle1 - math.pi, angle2 - math.pi)
end end
end end
end end

View File

@ -19,17 +19,17 @@ local class = function(base, init)
-- expose a constructor which can be called by <classname>(<args>) -- expose a constructor which can be called by <classname>(<args>)
local mt = {} local mt = {}
mt.__call = function(class_tbl, ...) mt.__call = function(class_tbl, ...)
local obj = {} local obj = {}
setmetatable(obj,c) setmetatable(obj,c)
if class_tbl.init then if class_tbl.init then
class_tbl.init(obj,...) class_tbl.init(obj,...)
else else
-- make sure that any stuff from the base class is initialized! -- make sure that any stuff from the base class is initialized!
if base and base.init then if base and base.init then
base.init(obj, ...) base.init(obj, ...)
end end
end end
return obj return obj
end end
c.init = init c.init = init
c.is_a = function(self, klass) c.is_a = function(self, klass)

View File

@ -14,7 +14,7 @@ function util.drawCanvasToCanvas(canvas, other_canvas, options)
love.graphics.setInvertedStencil(options["stencil"]) love.graphics.setInvertedStencil(options["stencil"])
end end
if options["istencil"] then if options["istencil"] then
love.graphics.setInvertedStencil(options["stencil"]) love.graphics.setInvertedStencil(options["istencil"])
end end
if options["color"] then if options["color"] then
love.graphics.setColor(unpack(options["color"])) love.graphics.setColor(unpack(options["color"]))

View File

@ -1,27 +0,0 @@
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
local class = require(_PACKAGE.."/class")
local vec2 = class()
function vec2:init(x, y)
self.x, self.y = x, y
end
function vec2:normalize()
local len = self:length()
return vec2(self.x / len, self.y / len)
end
function vec2:dot(v2)
return (self.x * v2.x) + (self.y * v2.y)
end
function vec2:cross(v2)
return ((self.x * v2.y) - (self.y * v2.x))
end
function vec2:length()
return math.sqrt(self:dot(self))
end
return vec2

46
lib/vector.lua Normal file
View File

@ -0,0 +1,46 @@
local vector = {}
vector.__index = vector
local function new(x, y)
if type(x) == "table" then
return setmetatable({
x = x[1],
y = y[1]
}, vector)
else
return setmetatable({
x = x or 0,
y = y or 0
}, vector)
end
end
function vector.__add(a, b)
return new(a.x + b.x, a.y + b.y)
end
function vector.__sub(a, b)
return new(a.x - b.x, a.y - b.y)
end
function vector.__mul(a, b)
if type(b) == "number" then
return new(a.x * b, a.y * b)
else
return a.x * b.x + a.y * b.y
end
end
function vector.__div(a, b)
return new(a.x / b, a.y / b)
end
function vector.__eq(a, b)
return a.x == b.x and a.y == b.y
end
function vector:dist(b)
return math.sqrt(math.pow(b.x - self.x, 2) + math.pow(b.y-self.y, 2))
end
return setmetatable({new = new}, {__call = function(_, ...) return new(...) end})