130 lines
3 KiB
Lua
130 lines
3 KiB
Lua
|
--[[
|
||
|
Animated 2D Fog (procedural)
|
||
|
Originally for Godot Engine by Gonkee https://www.youtube.com/watch?v=QEaTsz_0o44&t=6s
|
||
|
|
||
|
Translated for löve by Brandon Blanker Lim-it @flamendless
|
||
|
]]--
|
||
|
|
||
|
--[[
|
||
|
SAMPLE USAGE:
|
||
|
local moonshine = require("moonshine")
|
||
|
local effect
|
||
|
|
||
|
local image, bg
|
||
|
local image_data
|
||
|
local shader_fog
|
||
|
local time = 0
|
||
|
|
||
|
function love.load()
|
||
|
image_data = love.image.newImageData(love.graphics.getWidth(), love.graphics.getHeight())
|
||
|
image = love.graphics.newImage(image_data)
|
||
|
bg = love.graphics.newImage("bg.png")
|
||
|
effect = moonshine(moonshine.effects.fog)
|
||
|
effect.fog.fog_color = {0.1, 0.0, 0.0}
|
||
|
effect.fog.speed = {0.2, 0.9}
|
||
|
end
|
||
|
|
||
|
function love.update(dt)
|
||
|
time = time + dt
|
||
|
effect.fog.time = time
|
||
|
end
|
||
|
|
||
|
function love.draw()
|
||
|
love.graphics.draw(bg)
|
||
|
effect(function()
|
||
|
love.graphics.draw(image)
|
||
|
end)
|
||
|
end
|
||
|
]]
|
||
|
|
||
|
return function(moonshine)
|
||
|
local fog_color
|
||
|
local octaves
|
||
|
local speed
|
||
|
local time
|
||
|
|
||
|
local shader = love.graphics.newShader([[
|
||
|
extern vec3 fog_color = vec3(0.35, 0.48, 0.95);
|
||
|
extern int octaves = 4;
|
||
|
extern vec2 speed = vec2(0.0, 1.0);
|
||
|
extern float time;
|
||
|
|
||
|
float rand(vec2 coord)
|
||
|
{
|
||
|
return fract(sin(dot(coord, vec2(56, 78)) * 1000.0) * 1000.0);
|
||
|
}
|
||
|
|
||
|
float noise(vec2 coord)
|
||
|
{
|
||
|
vec2 i = floor(coord); //get the whole number
|
||
|
vec2 f = fract(coord); //get the fraction number
|
||
|
float a = rand(i); //top-left
|
||
|
float b = rand(i + vec2(1.0, 0.0)); //top-right
|
||
|
float c = rand(i + vec2(0.0, 1.0)); //bottom-left
|
||
|
float d = rand(i + vec2(1.0, 1.0)); //bottom-right
|
||
|
vec2 cubic = f * f * (3.0 - 2.0 * f);
|
||
|
return mix(a, b, cubic.x) + (c - a) * cubic.y * (1.0 - cubic.x) + (d - b) * cubic.x * cubic.y; //interpolate
|
||
|
}
|
||
|
|
||
|
float fbm(vec2 coord) //fractal brownian motion
|
||
|
{
|
||
|
float value = 0.0;
|
||
|
float scale = 0.5;
|
||
|
for (int i = 0; i < octaves; i++)
|
||
|
{
|
||
|
value += noise(coord) * scale;
|
||
|
coord *= 2.0;
|
||
|
scale *= 0.5;
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
vec4 effect(vec4 color, Image texture, vec2 tc, vec2 sc)
|
||
|
{
|
||
|
vec2 coord = tc * 20.0;
|
||
|
vec2 motion = vec2(fbm(coord + vec2(time * speed.x, time * speed.y)));
|
||
|
float final = fbm(coord + motion);
|
||
|
return vec4(fog_color, final * 0.5);
|
||
|
}
|
||
|
]])
|
||
|
|
||
|
local setters = {}
|
||
|
|
||
|
setters.fog_color = function(t)
|
||
|
assert(type(t) == "table", "Passed argument to fog_color must be a table containing 3 color values")
|
||
|
fog_color = t
|
||
|
shader:send("fog_color", fog_color)
|
||
|
end
|
||
|
|
||
|
setters.octaves = function(i)
|
||
|
assert(type(i) == "number", "Passed argument to octaves must be an integer")
|
||
|
octaves = i
|
||
|
shader:send("octaves", octaves)
|
||
|
end
|
||
|
|
||
|
setters.speed = function(t)
|
||
|
assert(type(t) == "table", "Passed argument to speed must be a table containing 2 values")
|
||
|
speed = t
|
||
|
shader:send("speed", speed)
|
||
|
end
|
||
|
|
||
|
setters.time = function(n)
|
||
|
assert(type(n) == "number", "Passed argument to time must be a number")
|
||
|
time = n
|
||
|
shader:send("time", time)
|
||
|
end
|
||
|
|
||
|
local defaults = {
|
||
|
fog_color = {0.35, 0.48, 0.95},
|
||
|
octaves = 4,
|
||
|
speed = {0.5, 0.5},
|
||
|
}
|
||
|
|
||
|
return moonshine.Effect({
|
||
|
name = "fog",
|
||
|
shader = shader,
|
||
|
setters = setters,
|
||
|
defaults = defaults,
|
||
|
})
|
||
|
end
|