window without blendmode or shadow canvas drawn: (its just a scene from the game)
window with the shadows drawn but blendMode is still 'alpha' :
window with the shadow draw and blandMode set to 'multiplied, 'premultiplied' : (just a black screen)
the shadow is claculated with polygons and is drawn to a canvas, the canvas is then drawn to another canvas (combine all lights to one screen), then this canvas is draw atop the already rendered window after everything has been draw.
love.draw function() looks like the following:
simplified version :
Code: Select all
function love.draw()
walls:sendDrawToRend()
entities:sendDrawToRend()
player:sendDrawToRend()
UI:sendDrawToRend()
-- all viewable items are sent to one script to be drawn with shaders
betterRender:drawAll()
--combine all drawables into a canvases, apply shaders, and draw to screen
stats:draw()
--draw debug info (cpu time, gpu time, texture memory on screen)
geometryShadows:drawLights()
--draw shadows (problem)
end
Code: Select all
function love.draw()
local startTime = love.timer.getTime()
Walls:draw()
BetterEntity:draw()
Player:draw()
UserInterface:draw()
Camera:draw()
Blood:update(dt)
Gore:draw()
AnimatedNonentity:draw()
ps3d:draw('foreGround')
if paused then
Settings:draw()
end
BetterRender:draw()
local poses = Camera:getPos()
for i = 1, #splines do
splines[i]:draw(poses.x, poses.y, poses.zoom)
end
if debugmode then
love.graphics.print('cpu run time. ms : ' .. math.floor((cpuTime) * 1000000) / 1000, 30, 0)
love.graphics.print('gpu run time. ms : ' .. math.floor((gpuTime) * 1000000) / 1000, 30, 20)
love.graphics.print('total run time. ms : ' .. math.floor((totalTime) * 1000000) / 1000, 30, 40)
love.graphics.print(string.format("%.2f MB texture memory", love.graphics.getStats().texturememory / 1000 / 1000), 30, 60)
love.graphics.print('FPS : ' .. love.timer.getFPS(), CommonVars.screenWidth - 250, 0)
for i = 1, #totalTimeGraph - 1 do
love.graphics.line(350 + i, 60 - totalTimeGraph[i], 350 + (i + 1), 60 - totalTimeGraph[i + 1])
end
love.graphics.print('screen refresh : ' .. screenItems.refreshrate, CommonVars.screenWidth - 250, 20)
end
love.graphics.setBlendMode("alpha")
BetterGeometryShadow:drawLights()
-- draw lights and shadows
gpuTime = love.timer.getTime() - startTime
totalTime = love.timer.getTime() - totalStart
table.insert(totalTimeGraph, totalTime * 1000000 / 1000)
table.remove(totalTimeGraph, 1)
local curTime = love.timer.getTime()
if nextTime <= curTime then
nextTime = curTime
return
end
love.timer.sleep(nextTime - curTime)
end
simplified version :
Code: Select all
function geometryShadows:drawLights()
love.graphics.setShader(inverseSquareRootShader)
for i = 1, #allLights do
allLights[i]:drawAsLight() -- each light calculates shadows and draws them to its canvas
end
love.graphics.setCanvas(finalCanvas)
love.graphics.setShader()
for i = 1, #allLights do
love.graphics.draw(allLights[i].canvas) -- draw lights canvases to one canvas to draw on screen
end
love.graphics.setCanvas()
love.graphics.setBlendMode("multiply", "premultiplied") -- blend mode
love.graphics.draw(finalCanv) -- draw shadows
end
Code: Select all
function BetterGeometryShadow:drawLights()
love.graphics.setShader(BetterShaders:getShader("betterGeometryShadowInvSqroot"))
love.graphics.setBlendMode('replace')
for i = 1, #allLights do
allLights[i]:drawAsLight()
end
love.graphics.setCanvas(finalCanv)
love.graphics.clear()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setBlendMode('alpha')
love.graphics.setShader()
local camPos = Camera:getPos()
for i = 1, #allLights do
love.graphics.draw(allLights[i].canv, -allLights[i].power + (allLights[i].x - camPos.x + CommonVars.screenWidth / camPos.zoom - CommonVars.screenWidth) * camPos.zoom, -allLights[i].power + (allLights[i].y - camPos.y + CommonVars.screenHeight / camPos.zoom - CommonVars.screenHeight) * camPos.zoom, 0, camPos.zoom, camPos.zoom)
end
love.graphics.setCanvas()
love.graphics.setBlendMode("multiply", "premultiplied")
love.graphics.draw(finalCanv)
end
Code: Select all
function love.draw()
walls:sendDrawToRend()
entities:sendDrawToRend()
player:sendDrawToRend()
UI:sendDrawToRend()
-- all viewable items are sent to one script to be drawn with shaders
betterRender:drawAll()
--combine all drawables into a canvases, apply shaders, and draw to screen
local shadows = GeometryShadow:drawShadows() -- returns the fincal canvas
love.graphics.setShader(BetterShaders:getShader("geometryShadow")
-- set shader to a root function
-- lights were adding 0.1 to pixels they touched and this would make the lights additive but non-linear
-- shader turned lights from a / shaped graph 0-1 into a r shape graph 0-1
love.graphics.setBlendMode("multiply", "premultiplied") -- set blend mode
love.graphics.setCanvas() -- draw to window
love.graphics.draw(shadows) -- draw shadow canvas to canvas
stats:draw()
end
and I would like this to be an alteration of code (hopefully I just made a mistake somewhere in the drawing cast), making a new shader and redrawing the current screen and giving the shadow canvas as an extern Image may be a solution but I'm in testing phase for the feature so altering the betterRender:drawAll() code to have this would be more effort than its worth and would make it less efficient at larger drawing scales with many lights since it'd have to be before the ui is drawn so it would be applied to more than one canvas (just the way its worked out so far sadly)
here is code for individual lights making canvases before they are drawn to finalCanvas that is then to the screen:
simplified version :
Code: Select all
function geometryShadow:drawAsLight()
--shader is already inverse square root shader (was set before function is run)
love.graphics.setCanvas(self.canv)
love.graphics.clear(0, 0, 0, 1)
love.graphics.polygon('fill', self.lightVertices)
end
Code: Select all
function BetterGeometryShadow:drawAsLight()
-- shader was set to the inverse square root shader before this function was called
love.graphics.push()
love.graphics.setCanvas(self.canv) -- draw to its own canvas
love.graphics.clear(0, 0, 0, 1)
-- set screen to black
love.graphics.translate(-self.x + self.power, -self.y + self.power)
-- draw in the center of the canvas
for i = 2, #self.shadowVertices - 1, 2 do
local p1 = {x = self.shadowVertices[i].x, y = self.shadowVertices[i].y}
local p2 = {x = self.shadowVertices[i + 1].x, y = self.shadowVertices[i + 1].y}
if p1.x ~= p2.x or p1.y ~= p2.y then
love.graphics.polygon('fill', {p1.x, p1.y, p2.x, p2.y, self.x, self.y})
end
end
-- draws a triangle fan from the center of the light to all visible areas (draws the light not the shadow)
local p1 = {x = self.shadowVertices[#self.shadowVertices].x, y = self.shadowVertices[#self.shadowVertices].y}
local p2 = {x = self.shadowVertices[1].x, y = self.shadowVertices[1].y}
-- gets last and first point in the triangle fan (rendering issue fix)
if (math.atan2(p2.y - self.y, p2.x - self.x) - math.atan2(p1.y - self.y, p1.x - self.x) + math.pi) % (math.pi * 2) > math.pi then
love.graphics.polygon('fill', {p1.x, p1.y, p2.x, p2.y, self.x, self.y})
end
-- draws triangle between the last and first vertice only if it wont draw over the other triangles (defunct because of faux polygon at edge of light distance)
love.graphics.pop()
end