• Simplex Noise and Gaussian Blur
    9 replies, posted
Hey, I've recently been working on a module for Simplex Noise and Gaussian Bluring (so the noise looks a bit better), but aren't sure weather either of the two is actually working, since I've never seen either in such a raw unedited state before. My Module: [lua] ----------------------------------------------- ---Simplex Noise Module, Translated by Levybreak --Original Source: [url]http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf[/url] --(The code there is in java) --Just as a note, there's a fuckton of math in here. Don't try and calculate this shit real time. --Get lanes and prcess it in a seperate thread. Please. Really. ----------------------------------------------- local math = math local table = table local string = string local tonumber = tonumber local tostring = tostring local ipairs = ipairs --local print = print --local debug = debug module("SimplexNoise") local Gradients3D = {{1,1,0},{-1,1,0},{1,-1,0},{-1,-1,0}, {1,0,1},{-1,0,1},{1,0,-1},{-1,0,-1}, {0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1}}; local Gradients4D = {{0,1,1,1}, {0,1,1,-1}, {0,1,-1,1}, {0,1,-1,-1}, {0,-1,1,1}, {0,-1,1,-1}, {0,-1,-1,1}, {0,-1,-1,-1}, {1,0,1,1}, {1,0,1,-1}, {1,0,-1,1}, {1,0,-1,-1}, {-1,0,1,1}, {-1,0,1,-1}, {-1,0,-1,1}, {-1,0,-1,-1}, {1,1,0,1}, {1,1,0,-1}, {1,-1,0,1}, {1,-1,0,-1}, {-1,1,0,1}, {-1,1,0,-1}, {-1,-1,0,1}, {-1,-1,0,-1}, {1,1,1,0}, {1,1,-1,0}, {1,-1,1,0}, {1,-1,-1,0}, {-1,1,1,0}, {-1,1,-1,0}, {-1,-1,1,0}, {-1,-1,-1,0}}; local p = {151,160,137,91,90,15, 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180}; -- To remove the need for index wrapping, double the permutation table length for i=1,#p do p[i-1] = p[i] p[i] = nil end for i=1,#Gradients3D do Gradients3D[i-1] = Gradients3D[i] Gradients3D[i] = nil end for i=1,#Gradients4D do Gradients4D[i-1] = Gradients4D[i] Gradients4D[i] = nil end local perm = {} for i=0,255 do perm[i] = p[i] perm[i+256] = p[i] end -- A lookup table to traverse the simplex around a given point in 4D. -- Details can be found where this table is used, in the 4D noise method. local simplex = { {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0}, {0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0}, {1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0}, {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, {2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0}, {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0}}; local function Dot2D(tbl, x, y) return tbl[1]*x + tbl[2]*y; end local function Dot3D(tbl, x, y, z) return tbl[1]*x + tbl[2]*y + tbl[3]*z end local function Dot4D( tbl, x,y,z,w) return tbl[1]*x + tbl[2]*y + tbl[3]*z + tbl[3]*w; end local function SomeBitwiseShit(arg1,arg2) return arg1 & arg2 end local Prev2D = {} -- 2D simplex noise function Noise2D(xin, yin) if Prev2D[xin] and Prev2D[xin][yin] then return Prev2D[xin][yin] end local n0, n1, n2; -- Noise contributions from the three corners -- Skew the input space to determine which simplex cell we're in local F2 = 0.5*(math.sqrt(3.0)-1.0); local s = (xin+yin)*F2; -- Hairy factor for 2D local i = math.floor(xin+s); local j = math.floor(yin+s); local G2 = (3.0-math.sqrt(3.0))/6.0; local t = (i+j)*G2; local X0 = i-t; -- Unskew the cell origin back to (x,y) space local Y0 = j-t; local x0 = xin-X0; -- The x,y distances from the cell origin local y0 = yin-Y0; -- For the 2D case, the simplex shape is an equilateral triangle. -- Determine which simplex we are in. local i1, j1; -- Offsets for second (middle) corner of simplex in (i,j) coords if(x0>y0) then i1=1 j1=0 -- lower triangle, XY order: (0,0)->(1,0)->(1,1) else i1=0 j1=1 -- upper triangle, YX order: (0,0)->(0,1)->(1,1) end -- A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and -- a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where -- c = (3-sqrt(3))/6 local x1 = x0 - i1 + G2; -- Offsets for middle corner in (x,y) unskewed coords local y1 = y0 - j1 + G2; local x2 = x0 - 1.0 + 2.0 * G2; -- Offsets for last corner in (x,y) unskewed coords local y2 = y0 - 1.0 + 2.0 * G2; -- Work out the hashed gradient indices of the three simplex corners local ii = SomeBitwiseShit(i , 255) local jj = SomeBitwiseShit(j , 255) local gi0 = perm[ii+perm[jj]] % 12; local gi1 = perm[ii+i1+perm[jj+j1]] % 12; local gi2 = perm[ii+1+perm[jj+1]] % 12; -- Calculate the contribution from the three corners local t0 = 0.5 - x0*x0-y0*y0; if t0<0 then n0 = 0.0; else t0 = t0 * t0 n0 = t0 * t0 * Dot2D(Gradients3D[gi0], x0, y0); -- (x,y) of Gradients3D used for 2D gradient end local t1 = 0.5 - x1*x1-y1*y1; if (t1<0) then n1 = 0.0; else t1 = t1*t1 n1 = t1 * t1 * Dot2D(Gradients3D[gi1], x1, y1); end local t2 = 0.5 - x2*x2-y2*y2; if (t2<0) then n2 = 0.0; else t2 = t2*t2 n2 = t2 * t2 * Dot2D(Gradients3D[gi2], x2, y2); end -- Add contributions from each corner to get the final noise value. -- The result is scaled to return values in the localerval [-1,1]. local retval = 70.0 * (n0 + n1 + n2) if not Prev2D[xin] then Prev2D[xin] = {} end Prev2D[xin][yin] = retval return retval; end local Prev3D = {} -- 3D simplex noise function Noise3D(vecIn) local xin = vecIn.x local yin = vecIn.y local zin = vecIn.z if Prev3D[xin] and Prev3D[xin][yin] and Prev3D[xin][yin][zin] then return Prev3D[xin][yin][zin] end local n0, n1, n2, n3; -- Noise contributions from the four corners -- Skew the input space to determine which simplex cell we're in local F3 = 1.0/3.0; local s = (xin+yin+zin)*F3; -- Very nice and simple skew factor for 3D local i = math.floor(xin+s); local j = math.floor(yin+s); local k = math.floor(zin+s); local G3 = 1.0/6.0; -- Very nice and simple unskew factor, too local t = (i+j+k)*G3; local X0 = i-t; -- Unskew the cell origin back to (x,y,z) space local Y0 = j-t; local Z0 = k-t; local x0 = xin-X0; -- The x,y,z distances from the cell origin local y0 = yin-Y0; local z0 = zin-Z0; -- For the 3D case, the simplex shape is a slightly irregular tetrahedron. -- Determine which simplex we are in. local i1, j1, k1; -- Offsets for second corner of simplex in (i,j,k) coords local i2, j2, k2; -- Offsets for third corner of simplex in (i,j,k) coords if (x0>=y0) then if (y0>=z0) then i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; -- X Y Z order elseif (x0>=z0) then i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; -- X Z Y order else i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; -- Z X Y order end else -- x0<y0 if (y0<z0) then i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; -- Z Y X order elseif (x0<z0) then i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; -- Y Z X order else i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; -- Y X Z order end end -- A step of (1,0,0) in (i,
I'm blinded by code. Could you show us some actually working pictures? As much as I'd love to go though and read all this code...
Well, I think it'd be best If I took a video, probably, since some of my tests are animated.
[QUOTE=Levybreak;17887557]Well, I think it'd be best If I took a video, probably, since some of my tests are animated.[/QUOTE] Dying to see a video
[url]http://www.wegame.com/watch/Simplex_Noise_Test/[/url] I'm working on a second test with the noise at a different scale and in a larger area, but garry's infinite loop detection keeps going off because of the huge amount of math that needs to be done for each pixel. (Even if it is only done once) [editline]10:10PM[/editline] [url]http://www.wegame.com/watch/Simplex_Noise_Test_2/[/url] That took a fucking long ass time to be computed. [editline]11:16PM[/editline] [url]http://www.wegame.com/watch/Simplex_Noise_Test_3/[/url] Test number 3. Code used: [lua] require("SimplexNoise") concommand.Add("SimplexNoise2DTest",function(ply,cmd,arg) local tbl = {} local loopnum = -1 hook.Add("Think","MassivelyCool",function() loopnum = loopnum+1 for colum=1,32 do local i = (32*loopnum)+colum if not tbl[i] then tbl[i] = {} end for ii=1,256 do local num = SimplexNoise.Noise2D(i/10,ii/10) num = num+1 num = num*128 tbl[i][ii] = num end end if loopnum >= 8 then hook.Remove("Think","MassivelyCool") end end) hook.Add("HUDPaint","SimplexTest",function() for i=1,256 do if not tbl[i] then tbl[i] = {} end for ii=1,256 do if not tbl[i][ii] then tbl[i][ii] = 255 end local num = tbl[i][ii] surface.SetDrawColor(num,num,num,255) surface.DrawRect(i,ii,1,1) end end end) end) concommand.Add("SimplexNoise3DTest",function(ply,cmd,arg) --[[local frameNum = 0 local VecTbl = {} for i=1,64 do VecTbl[i] = {} for ii=1,64 do VecTbl[i][ii] = Vector(i/10,ii/10,0) end end]] local VecTbl = {} local frame = 0 local num = 0 local i = 1 hook.Add("Think","MassivelyCool",function() num = num + 1 i = math.ceil(num) frame = frame+1 if frame > 10 then frame = 1 end if not VecTbl[i] then VecTbl[i] = {} end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end frame = frame+1 if frame > 10 then frame = 1 end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end local num = SimplexNoise.Noise3D(Vector(i/10,ii/10,frame/10)) num = num+1 num = num*128 if not VecTbl[i][ii][frame] then VecTbl[i][ii][frame] = {} end VecTbl[i][ii][frame] = num end if num >= 256 then hook.Remove("Think","MassivelyCool") end end) local playFrame = 0 hook.Add("HUDPaint","SimplexTest",function() playFrame = playFrame + 1 if playFrame > 10 then playFrame = 1 end for i=1,256 do if not VecTbl[i] then VecTbl[i] = {} end for ii=1,256 do if not VecTbl[i][ii] then VecTbl[i][ii] = {} end if not VecTbl[i][ii][playFrame] then VecTbl[i][ii][playFrame] = 255 end local num = VecTbl[i][ii][playFrame] surface.SetDrawColor(num,num,num,255) surface.DrawRect(i,ii,1,1) end end end) end) concommand.Add("SimplexNoise4DTest",function(ply,cmd,arg) local VecTbl = {} for i=1,75 do VecTbl[i] = {} for ii=1,75 do VecTbl[i][ii] = Vector(i/20,ii/20,0) end end hook.Add("HUDPaint","SimplexTest",function() for i=1,75 do for ii=1,75 do VecTbl[i][ii].z = math.floor(ply:GetPos().x)/20 local num = SimplexNoise.Noise4D(VecTbl[i][ii],math.floor(ply:GetPos().y)/20) num = num+1 num = num*128 surface.SetDrawColor(num,num,num,255) surface.DrawRect(i,ii,1,1) end end end) end) --Blur Testing Stuff follows. I'm not sure as to weather it actually works or not......meh. local function Average(...) local ret = 0 for k,v in ipairs({...}) do ret = ret + v end return ret/#{...} end local function StandardDevitation(...) local ret = 0 local avg = Average(...) for k,v in ipairs({...}) do ret = ret + (v-avg)^2 end local maxs = #{...} return math.sqrt(ret/maxs) end local function GetValuesWithin(tbl,n,cx,cy,mins,maxs) local ret = {} local val = math.Round(n/2) for i=math.Clamp(cx-val,mins,maxs),math.Clamp(cx+val,mins,maxs) do for ii=math.Clamp(cy-val,mins,maxs),math.Clamp(cy+val,mins,maxs) do table.insert(ret,tbl[i][ii]) end end return unpack(ret) end local function DoThatShit(tbl,ntbl) local loopnum = -1 hook.Add("Think","AnotherOneRioght",function() loopnum = loopnum+1 for colum=1,32 do local i = (loopnum*32)+colum if not ntbl[i] then ntbl[i] = {} end for ii=1,256 do local dev = StandardDevitation(GetValuesWithin(tbl,4,i,ii,1,256)) ntbl[i][ii] = tbl[i][ii]-SimplexNoise.GBlur1D(i,dev) ntbl[i][ii] = ntbl[i][ii]-SimplexNoise.GBlur1D(ii,dev) end end if loopnum >= 8 then hook.Remove("Think","AnotherOneRioght") end end) end concommand.Add("SimplexNoise2DBlurTest",function(ply,cmd,arg) local tbl = {} local ntbl = {} local loopnum = -1 hook.Add("Think","MassivelyCool",function() loopnum = loopnum+1 for colum=1,32 do local i = (32*loopnum)+colum if not tbl[i] then tbl[i] = {} end for ii=1,256 do local num = SimplexNoise.Noise2D(i/10,ii/10) num = num+1 num = num*128 tbl[i][ii] = num end end if loopnum >= 8 then DoThatShit(tbl,ntbl) hook.Remove("Think","MassivelyCool") end end) hook.Add("HUDPaint","SimplexTest",function() for i=1,256 do if not ntbl[i] then ntbl[i] = {} end for ii=1,256 do if not ntbl[i][ii] then ntbl[i][ii] = 255 end local num = ntbl[i][ii] surface.SetDrawColor(num,num,num,255) surface.DrawRect(i,ii,1,1) end end end) end) [/lua]
When these types of things come out, I can not for the life of me conceptualize one practical usage for them. The only thing that comes to mind is TV static, in 2d3d space, but that's it. Can anyone beat me to a useful concept?
2-3 fps at the video? :l
[QUOTE=The-Stone;17895268]2-3 fps at the video? :l[/QUOTE] it's not much higher than that for me to begin with. Calculating the noise chops it in half, and then the recording doesn't help too much either. As I said, for the love of god, don't calculate this shit in the main thread unless you have to. [editline]11:02AM[/editline] [QUOTE=CptFuzzies;17892085]When these types of things come out, I can not for the life of me conceptualize one practical usage for them. The only thing that comes to mind is TV static, in 2d3d space, but that's it. Can anyone beat me to a useful concept?[/QUOTE] It can be useful for adding cohesive randomness to effects and such, and generating procedural textures. And adding random turbulence to something, once I add in the turbulence effect to the noise. [editline]11:05AM[/editline] I'd also like to add the the module itself is vanilla lua (aside form the bitwise &... you'd need to download LuaBit or the like for that), so it could be used for non-gmod purposes. [editline]11:32AM[/editline] [url]http://www.noisemachine.com/talk1/index.html[/url] Has alot of information on how noise ise useful, though. [editline]11:58AM[/editline] [url]http://www.wegame.com/watch/Turbulent_Simplex_Noise/[/url] Turbulence. :D
math.Rand and math.random are your friends, but I love Gaussian stuff. I'll ponder through the libraries within my mind and find some inspiration to use this.
The main point is that if you send it the same values, it produces the same output.
Sorry, you need to Log In to post a reply to this thread.