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

View File

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

View File

@ -14,7 +14,7 @@ function util.drawCanvasToCanvas(canvas, other_canvas, options)
love.graphics.setInvertedStencil(options["stencil"])
end
if options["istencil"] then
love.graphics.setInvertedStencil(options["stencil"])
love.graphics.setInvertedStencil(options["istencil"])
end
if options["color"] then
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})