diff --git a/gfx/refraction_height.png b/gfx/refraction_height.png new file mode 100644 index 0000000..b2c6490 Binary files /dev/null and b/gfx/refraction_height.png differ diff --git a/gfx/refraction_normal.png b/gfx/refraction_normal.png new file mode 100644 index 0000000..a129124 Binary files /dev/null and b/gfx/refraction_normal.png differ diff --git a/light.lua b/light.lua index 51c6a8d..73f471c 100644 --- a/light.lua +++ b/light.lua @@ -12,7 +12,7 @@ LOVE_LIGHT_TRANSLATE_X = 0 LOVE_LIGHT_TRANSLATE_Y = 0 LOVE_LIGHT_TRANSLATE_X_OLD = 0 LOVE_LIGHT_TRANSLATE_Y_OLD = 0 - +LOVE_LIGHT_DIRECTION = 0 love.light = {} -- light world @@ -26,6 +26,7 @@ function love.light.newWorld() o.shadow = love.graphics.newCanvas() o.shadow2 = love.graphics.newCanvas() o.shine = love.graphics.newCanvas() + o.shine2 = love.graphics.newCanvas() o.normalMap = love.graphics.newCanvas() o.glowMap = love.graphics.newCanvas() o.glowMap2 = love.graphics.newCanvas() @@ -68,10 +69,14 @@ function love.light.newWorld() then local lightposrange = {o.lights[i].x, love.graphics.getHeight() - o.lights[i].y, o.lights[i].range} LOVE_LIGHT_CURRENT = o.lights[i] - o.shader:send("lightPositionRange", {o.lights[i].x - LOVE_LIGHT_TRANSLATE_X, love.graphics.getHeight() - (o.lights[i].y - LOVE_LIGHT_TRANSLATE_Y), o.lights[i].range}) + LOVE_LIGHT_DIRECTION = LOVE_LIGHT_DIRECTION + 0.002 + o.shader:send("lightPosition", {o.lights[i].x - LOVE_LIGHT_TRANSLATE_X, love.graphics.getHeight() - (o.lights[i].y - LOVE_LIGHT_TRANSLATE_Y)}) + o.shader:send("lightRange", o.lights[i].range) o.shader:send("lightColor", {o.lights[i].red / 255.0, o.lights[i].green / 255.0, o.lights[i].blue / 255.0}) o.shader:send("lightSmooth", o.lights[i].smooth) o.shader:send("lightGlow", {1.0 - o.lights[i].glowSize, o.lights[i].glowStrength}) + o.shader:send("lightAngle", math.pi - o.lights[i].angle / 2.0) + o.shader:send("lightDirection", o.lights[i].direction) --if o.changed then --love.graphics.setCanvas(o.shadow) @@ -200,6 +205,8 @@ function love.light.newWorld() o.normalShader:send('lightPosition',{o.lights[i].x, love.graphics.getHeight() - o.lights[i].y, o.lights[i].z / 255.0}) o.normalShader:send('lightRange',{o.lights[i].range}) o.normalShader:send("lightSmooth", o.lights[i].smooth) + o.normalShader:send("lightAngle", math.pi - o.lights[i].angle / 2.0) + o.normalShader:send("lightDirection", o.lights[i].direction) love.graphics.setShader(o.normalShader) love.graphics.draw(o.normalMap, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) end @@ -285,10 +292,28 @@ function love.light.newWorld() -- draw shine o.drawShine = function() love.graphics.setColor(255, 255, 255) - love.graphics.setBlendMode("multiplicative") - love.graphics.setShader() - love.graphics.draw(o.shine, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) - love.graphics.setBlendMode("alpha") + if o.blur and false then + LOVE_LIGHT_LAST_BUFFER = love.graphics.getCanvas() + LOVE_LIGHT_BLURV:send("steps", o.blur) + LOVE_LIGHT_BLURH:send("steps", o.blur) + love.graphics.setBlendMode("alpha") + love.graphics.setCanvas(o.shine2) + love.graphics.setShader(LOVE_LIGHT_BLURV) + love.graphics.draw(o.shine, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) + love.graphics.setCanvas(o.shine) + love.graphics.setShader(LOVE_LIGHT_BLURH) + love.graphics.draw(o.shine2, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) + love.graphics.setCanvas(LOVE_LIGHT_LAST_BUFFER) + love.graphics.setBlendMode("multiplicative") + love.graphics.setShader() + love.graphics.draw(o.shine, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) + love.graphics.setBlendMode("alpha") + else + love.graphics.setBlendMode("multiplicative") + love.graphics.setShader() + love.graphics.draw(o.shine, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) + love.graphics.setBlendMode("alpha") + end end -- draw pixel shadow o.drawPixelShadow = function() @@ -424,6 +449,14 @@ function love.light.newWorld() o.setLightY = function(n, y) o.lights[n].setY(y) end + -- set light angle + o.setLightAngle = function(n, angle) + o.lights[n].setAngle(angle) + end + -- set light direction + o.setLightDirection = function(n, direction) + o.lights[n].setDirection(direction) + end -- get light count o.getLightCount = function() return #o.lights @@ -447,15 +480,18 @@ end -- light object function love.light.newLight(p, x, y, red, green, blue, range) local o = {} + o.direction = 0 + o.angle = math.pi * 2.0 + o.range = 0 o.shadow = love.graphics.newCanvas() o.shine = love.graphics.newCanvas() - o.x = x - o.y = y + o.x = x or 0 + o.y = y or 0 o.z = 15 - o.red = red - o.green = green - o.blue = blue - o.range = range + o.red = red or 255 + o.green = green or 255 + o.blue = blue or 255 + o.range = range or 300 o.smooth = 1.0 o.glowSize = 0.1 o.glowStrength = 0.0 @@ -505,6 +541,32 @@ function love.light.newLight(p, x, y, red, green, blue, range) o.changed = true end end + -- set direction + o.setDirection = function(direction) + if direction ~= o.direction then + if direction > math.pi * 2 then + o.direction = math.mod(direction, math.pi * 2) + elseif direction < 0.0 then + o.direction = math.pi * 2 - math.mod(math.abs(direction), math.pi * 2) + else + o.direction = direction + end + o.changed = true + end + end + -- set angle + o.setAngle = function(angle) + if angle ~= o.angle then + if angle > math.pi then + o.angle = math.mod(angle, math.pi) + elseif angle < 0.0 then + o.angle = math.pi - math.mod(math.abs(angle), math.pi) + else + o.angle = angle + end + o.changed = true + end + end -- set glow size o.setSmooth = function(smooth) o.smooth = smooth @@ -672,7 +734,7 @@ function love.light.newCircle(p, x, y, radius) o.id = #p.circle o.x = x or 0 o.y = y or 0 - o.radius = radius or 200 + o.radius = radius or 64 o.shine = true o.red = 255 o.green = 255 diff --git a/main.lua b/main.lua index f85c53a..6ad415b 100644 --- a/main.lua +++ b/main.lua @@ -45,22 +45,22 @@ function love.load() imgFloor:setWrap("repeat", "repeat") -- load image examples - circle = love.graphics.newImage "gfx/circle.png" - circle_normal = love.graphics.newImage "gfx/circle_normal.png" - cone = love.graphics.newImage "gfx/cone.png" - cone_normal = love.graphics.newImage "gfx/cone_normal.png" - chest = love.graphics.newImage "gfx/chest.png" - chest_normal = love.graphics.newImage "gfx/chest_normal.png" - machine = love.graphics.newImage "gfx/machine.png" - machine_normal = love.graphics.newImage "gfx/machine_normal.png" - machine_glow = love.graphics.newImage "gfx/machine_glow.png" - machine2 = love.graphics.newImage "gfx/machine2.png" - machine2_normal = love.graphics.newImage "gfx/machine2_normal.png" - machine2_glow = love.graphics.newImage "gfx/machine2_glow.png" - blopp = love.graphics.newImage "gfx/blopp.png" - tile = love.graphics.newImage "gfx/tile.png" - tile_normal = love.graphics.newImage "gfx/tile_normal.png" - tile_glow = love.graphics.newImage "gfx/tile_glow.png" + circle = love.graphics.newImage("gfx/circle.png") + circle_normal = love.graphics.newImage("gfx/circle_normal.png") + cone = love.graphics.newImage("gfx/cone.png") + cone_normal = love.graphics.newImage("gfx/cone_normal.png") + chest = love.graphics.newImage("gfx/chest.png") + chest_normal = love.graphics.newImage("gfx/chest_normal.png") + machine = love.graphics.newImage("gfx/machine.png") + machine_normal = love.graphics.newImage("gfx/machine_normal.png") + machine_glow = love.graphics.newImage("gfx/machine_glow.png") + machine2 = love.graphics.newImage("gfx/machine2.png") + machine2_normal = love.graphics.newImage("gfx/machine2_normal.png") + machine2_glow = love.graphics.newImage("gfx/machine2_glow.png") + blopp = love.graphics.newImage("gfx/blopp.png") + tile = love.graphics.newImage("gfx/tile.png") + tile_normal = love.graphics.newImage("gfx/tile_normal.png") + tile_glow = love.graphics.newImage("gfx/tile_glow.png") -- light world lightRange = 400 @@ -70,6 +70,7 @@ function love.load() mouseLight = lightWorld.newLight(0, 0, 255, 127, 63, lightRange) mouseLight.setGlowStrength(0.3) mouseLight.setSmooth(lightSmooth) + lightDirection = 0.0 -- init physic world initScene() @@ -96,6 +97,7 @@ function love.update(dt) mouseLight.setPosition(love.mouse.getX(), love.mouse.getY()) mx = love.mouse.getX() my = love.mouse.getY() + lightDirection = lightDirection + dt if love.keyboard.isDown("w") then for i = 1, phyCnt do @@ -138,6 +140,10 @@ function love.update(dt) offsetChanged = false end + for i = 1, lightWorld.getLightCount() do + lightWorld.setLightDirection(i, lightDirection) + end + for i = 1, phyCnt do if phyBody[i]:isAwake() or offsetChanged then if offsetChanged then @@ -499,16 +505,20 @@ function love.keypressed(k, u) phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) phyFixture[phyCnt]:setRestitution(0.5) elseif k == "0" then - -- add image - phyCnt = phyCnt + 1 - phyLight[phyCnt] = lightWorld.newImage(cone, mx, my, 24, 12, 12, 28) - phyLight[phyCnt].setNormalMap(cone_normal) - phyLight[phyCnt].setAlpha(0.0) - math.randomseed(phyCnt) - phyLight[phyCnt].setColor(math.random(0, 255), math.random(0, 255), math.random(0, 255)) - phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") - phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 24, 32) - phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) - phyFixture[phyCnt]:setRestitution(0.5) + -- add light + local r = lightWorld.getLightCount() % 3 + local light + + if r == 0 then + light = lightWorld.newLight(mx, my, 31, 127, 63, lightRange) + elseif r == 1 then + light = lightWorld.newLight(mx, my, 127, 63, 31, lightRange) + else + light = lightWorld.newLight(mx, my, 31, 63, 127, lightRange) + end + light.setSmooth(lightSmooth) + light.setGlowStrength(0.3) + math.randomseed(love.timer.getTime()) + light.setAngle(math.random(1, 5) * 0.1 * math.pi) end end \ No newline at end of file diff --git a/shader/normal.glsl b/shader/normal.glsl index c35cfc5..f73185c 100644 --- a/shader/normal.glsl +++ b/shader/normal.glsl @@ -1,18 +1,35 @@ +#define PI 3.1415926535897932384626433832795 + extern vec2 screenResolution; extern vec3 lightPosition; extern vec3 lightColor; extern float lightRange; extern float lightSmooth; +extern float lightDirection; +extern float lightAngle; -vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords) { +vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) { vec4 pixelColor = Texel(texture, texture_coords); if(pixelColor.a > 0.0) { + if(lightAngle > 0.0) { + float angle2 = atan(lightPosition.x - pixel_coords.x, pixel_coords.y - lightPosition.y) + PI; + if(lightDirection - lightAngle > 0 && lightDirection + lightAngle < PI * 2) { + if(angle2 < mod(lightDirection + lightAngle, PI * 2) && angle2 > mod(lightDirection - lightAngle, PI * 2)) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + } else { + if(angle2 < mod(lightDirection + lightAngle, PI * 2) || angle2 > mod(lightDirection - lightAngle, PI * 2)) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + } + } + vec3 normal = vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b); - float dist = distance(lightPosition, vec3(screen_coords, normal.b)); + float dist = distance(lightPosition, vec3(pixel_coords, normal.b)); if(dist < lightRange) { - vec3 dir = vec3((lightPosition.xy - screen_coords.xy) / screenResolution.xy, lightPosition.z); + vec3 dir = vec3((lightPosition.xy - pixel_coords.xy) / screenResolution.xy, lightPosition.z); dir.x *= screenResolution.x / screenResolution.y; diff --git a/shader/poly_shadow.glsl b/shader/poly_shadow.glsl index 4d53e7b..eb0947e 100644 --- a/shader/poly_shadow.glsl +++ b/shader/poly_shadow.glsl @@ -1,22 +1,40 @@ -extern vec3 lightPositionRange; +#define PI 3.1415926535897932384626433832795 + +extern vec2 lightPosition; extern vec3 lightColor; +extern float lightRange; extern float lightSmooth; extern vec2 lightGlow; +extern float lightDirection; +extern float lightAngle; vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords){ vec4 pixel = Texel(texture, texture_coords); - vec2 lightToPixel = pixel_coords - lightPositionRange.xy; + vec2 lightToPixel = pixel_coords - lightPosition; float distance = length(lightToPixel); - float att = 1 - distance / lightPositionRange.z; + float att = 1 - distance / lightRange; - if (distance <= lightPositionRange.z) { + if(lightAngle > 0.0) { + float angle2 = atan(lightPosition.x - pixel_coords.x, pixel_coords.y - lightPosition.y) + PI; + if(lightDirection - lightAngle > 0 && lightDirection + lightAngle < PI * 2) { + if(angle2 < mod(lightDirection + lightAngle, PI * 2) && angle2 > mod(lightDirection - lightAngle, PI * 2)) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + } else { + if(angle2 < mod(lightDirection + lightAngle, PI * 2) || angle2 > mod(lightDirection - lightAngle, PI * 2)) { + return vec4(0.0, 0.0, 0.0, 1.0); + } + } + } + + if (distance <= lightRange) { if (lightGlow.x < 1.0 && lightGlow.y > 0.0) { pixel.rgb = clamp(lightColor * pow(att, lightSmooth) + pow(smoothstep(lightGlow.x, 1.0, att), lightSmooth) * lightGlow.y, 0.0, 1.0); } else { pixel.rgb = lightColor * pow(att, lightSmooth); } } else { - pixel.rgb = vec3(0, 0, 0); + return vec4(0.0, 0.0, 0.0, 1.0); } return pixel;