Render wave via shader.

This commit is contained in:
yaw-man 2023-01-14 16:03:57 -04:00
parent c8fe7b7d36
commit f1873abed7
3 changed files with 58 additions and 34 deletions

View File

@ -4,7 +4,7 @@ function love.conf( t )
t.modules.touch = false
t.modules.video = false
t.window.title = "By Your Own Beat"
t.window.title = "Your Own Drum"
t.window.width = 600
t.window.height = 600
t.window.resizable = true

View File

@ -29,24 +29,6 @@ state = {
currentBeat = 1,
startTime = 0.0,
wave = {
x = { 1.0, 0.0, -0.5, 0.2, 0.4, 0.8, 0.3, 0.9, -0.4, 0.8, 0.5, 0.1, -0.9 },
dx = { 1.0, 0.0, -0.5, 0.2, 0.4, 0.8, 0.3, 0.9, -0.4, 0.8, 0.5, 0.1, -0.9 },
ddx = { 1.0, 0.0, -0.5, 0.2, 0.4, 0.8, 0.3, 0.9, -0.4, 0.8, 0.5, 0.1, -0.9 },
X = function(th) end,
DX = function(th) end,
DDX = function(th) end,
Draw = function() end,
AddImpulse = function( th, size ) end,
ImpactPoint = function( xi, yi, xf, yf )
local impact = { r = 0, th = 0, t = 0, x = 0, y = 0, dx = 0, dy = 0 }
return impact
end,
Update = function( dt ) end,
},
beat = {
t = nil,
mu = nil,

View File

@ -1,6 +1,6 @@
--Render and simulate 1D wave equation.
local love = love
local N = 15
local N = 33
local SOUNDSPEED = 0.5
local IMPULSESIZE = 20
local DAMPING = 0.01
@ -16,6 +16,41 @@ local Derivative
local SecondDerivative
local DFT
local shader = love.graphics.newShader([[
uniform float re[33];
uniform float im[33];
//Slow IDFT
float r( float x )
{
float r = re[0];
for( int k = 1; k < 17; k++ )
{
float c = cos( x * float( k ) );
float s = sin( x * float( k ) );
r +=
+ c * re[k]
- s * im[k]
+ c * re[33 - k]
+ s * im[33 - k];
}
return r;
}
vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords)
{
vec2 p = (3.0 * screen_coords - 1.5 * love_ScreenSize.xy ) / love_ScreenSize.y;
p.y = -p.y;
float r = r( atan(p.y, p.x) ) - length( p );
return vec4(color.x, color.y, color.z, (r > -0.01)) ;
}
]])
--Calculate discrete fourier transform of radius function.
do
@ -112,7 +147,7 @@ end
--Apply bandlimited impulse to wave.
local function OnImpact( impact )
local r = cur.radii
local theta = impact.th
local magnitude = IMPULSESIZE * impact.speed
@ -120,7 +155,7 @@ local function OnImpact( impact )
for i = 0, N - 1 do
r[ i + 1 ] = r[ i + 1 ] + dt * magnitude * AliasedSinc( theta, 2.0 * math.pi * i / N )
end
--We've updated the positions, now we need to take a DFT
--in order to get the bandlimited second spatial derivative.
cur:DFT()
@ -161,10 +196,16 @@ local function Draw()
-- Blue circle.
love.graphics.setColor( 91 / 255, 206 / 255, 250 / 255 )
love.graphics.circle("fill", 0, 0, 1)
shader:send( "re", unpack( cur.dftre ) )
shader:send( "im", unpack( cur.dftim ) )
love.graphics.setShader( shader )
love.graphics.circle("fill", 0, 0, 1.5)
local t = love.timer.getTime()
love.graphics.setShader( )
-- Debug dots.
--[[
for i = 1, N do
local th = ( i - 1 ) * 2.0 * math.pi / N
@ -172,9 +213,9 @@ local function Draw()
love.graphics.setCanvas()
love.graphics.setColor( 0, 0, 0, 0.5 )
love.graphics.circle( "fill", cx, cy, 0.02 )
for k = 0.1, 1.0, 0.1 do
--Interpolant.
love.graphics.setColor( 1.0, 0, 0, 0.7 )
@ -183,9 +224,9 @@ local function Draw()
local x, y = r * math.cos( th ), r * math.sin( th )
love.graphics.circle( "fill", x, y, 0.01 )
--love.graphics.circle( "fill", th / math.pi - 1.0 , r, 0.01)
--First derivative.
--[[love.graphics.setColor( 0, 1.0, 0, 0.7 )
--love.graphics.setColor( 0, 1.0, 0, 0.7 )
r = cur:Derivative( th )
x, y = r * math.cos( th ), r * math.sin( th )
--love.graphics.circle( "fill", x, y, 0.01 )
@ -199,15 +240,16 @@ local function Draw()
love.graphics.circle( "fill", th / math.pi - 1.0, r, 0.01)
love.graphics.setColor( 1.0, 1.0, 1.0, 0.2 )
love.graphics.circle( "fill", 2.0 * ( i + k ) / N - 1.2, 0, 0.02 )]]
love.graphics.circle( "fill", 2.0 * ( i + k ) / N - 1.2, 0, 0.02 )
end
end
love.graphics.setColor( 1, 1, 1, 0.5 )
local r = cur:Interpolate( t )
local x, y = r * math.cos( t ), r * math.sin( t )
love.graphics.circle( "fill", x, y, 0.02 )
love.graphics.circle( "fill", x, y, 0.02 )]]
end
@ -219,7 +261,7 @@ local function Update()
old[name][i] = t[i]
end
end
--Deep copy of new state to current state.
for name, t in pairs( new ) do
for i = 1, N do
@ -229,16 +271,16 @@ local function Update()
end
Integrate = function( step )
for i = 1, N do
local rxx = cur:SecondDerivative( math.pi * 2.0 * ( i - 1 ) / N )
local r = ( 1.0 - DAMPING ) * ( 2.0 * cur.radii[i] - old.radii[i] + step * step * SOUNDSPEED * rxx ) --Verlet
+ DAMPING --Damping: oscillate toward 1.
+ DAMPING --Damping: oscillate toward 1.
if r > 1.5 then r = 1.5 end
if r < 0.5 then r = 0.5 end
new.radii[i] = r
end
new:DFT( )
end