Post by shadow008 on May 29, 2013 15:06:13 GMT -5
From freespace.virgin.net/hugo.elias/models/m_perlin.htm I implemented perlin noise in b4gl.
Fairly simple, yet uncommented (sorry) code. This example REQUIRES THE TOOL BOX PLUGIN. At least for saving the image. You can comment out those parts if you so please.
Things to note: the "random" number generator is seeded. So the same seed = the same random number every time. Basically allows for seamlessness from one texture to another one generated with *size of texture* offset.
Plus, I got the code to finally work nice and fast, generating one 128x128 section about every second on my computer. (Pre-optimization, it was taking more than 10 seconds per section to produce a really grainy, uniformly torn, awful looking image)
Also, heightmaps.
Making larger images? Just bump up the integer in CreateLargePerlinMap (4 = 512x512 image). You can also play with line 115 "pNoise = PerlinNoise..." to see what kind of effects you can get.
Results:
...just kidding, no results.
Here's the link: dl.dropboxusercontent.com/u/5319168/Test%20seed%2077%20256x256.bmp
Fairly simple, yet uncommented (sorry) code. This example REQUIRES THE TOOL BOX PLUGIN. At least for saving the image. You can comment out those parts if you so please.
const NOISE_MAX as integer = 79
dim GLOBAL_SEED = 36
const MARBLE_EFFECT = TRUE
const WOOD_EFFECT = TRUE
type MARBLE_PARAMS
dim xPeriod as single
dim yPeriod as single
dim turbPower as single
dim cutoff as single
dim effect as single
end type
type WOOD_PARAMS
dim rings as single
dim turbPower as single
dim effect as single
end type
dim Marble as MARBLE_PARAMS
dim Wood as WOOD_PARAMS
function Noise(x as integer, y as integer) as integer
'Seeded "random" number generator
dim n as single = GLOBAL_SEED
n = (n + x) / ((n + y)) * 1103515245 * NOISE_MAX + n
return (int(n / 65535)) % NOISE_MAX
endfunction
function Cosine_Interpolation(a as single, b as single, x as single)
dim ft as single = x * 3.1415927
dim f as single = (1 - cos(ft)) * .5
return a*(1-f) + b*f
endfunction
function InterpolatedNoise(x as single, y as single)
dim integer_X as integer = x
dim fractional_X as single = x - integer_X
dim integer_Y as integer = y
dim fractional_Y as single = y - integer_Y
dim v1 as single = Noise(integer_X, integer_Y)
dim v2 as single = Noise(integer_X + 1, integer_Y)
dim v3 as single = Noise(integer_X , integer_Y + 1)
dim v4 as single = Noise(integer_X + 1, integer_Y + 1)
dim i1 as single = Cosine_Interpolation(v1 , v2 , fractional_X)
dim i2 as single = Cosine_Interpolation(v3 , v4 , fractional_X)
return Cosine_Interpolation(i1 , i2 , fractional_Y)
endfunction
function PerlinNoise_2D(x as single, y as single, persistance as single, octaves as integer) as single
dim total as single = 0
dim frequency as single
dim amplitude as single
dim i
x = x + RND_MAX * 2
frequency = pow(2, i)
amplitude = pow(persistance, octaves)
total = total + InterpolatedNoise(x / frequency , y / frequency) * amplitude
return total
endfunction
function PerlinNoise(x as single, y as single, p as single, iterations as integer, decStart as single) as single
dim total as single
dim decimator as single = decStart
dim i
total = PerlinNoise_2D(x / decimator, y / decimator, p, 0) / (NOISE_MAX * 1.0)
if iterations = 0 then return total : endif
decimator = decimator / 2.0
for i = 1 to iterations - 1
total = total + PerlinNoise_2D(x / decimator, y / decimator, p, i-2) / (NOISE_MAX * 1.0) * .5
decimator = decimator / 2.0
next
total = total / (iterations / 3.0)
return total
endfunction
sub SetMarbleParams(xPer as single, yPer as single, turb as single, cutoff as single)
Marble.xPeriod = xPer
Marble.yPeriod = yPer
Marble.turbPower = turb
Marble.cutoff = cutoff
endsub
sub SetWoodParams(rings as single, turb as single)
Wood.rings = rings
Wood.turbPower = turb
endsub
function CreateLargePerlinMap(size as single, TextureName as string)
dim x,y
dim pNoise as single
dim xyValue as single
dim sineVal as single
dim rings as single = 1.0
dim xVal as single
dim yVal as single
dim distVal as single
dim noiseBuffer as single
glReadBuffer(GL_FRONT)
glClear(GL_COLOR_BUFFER_BIT OR GL_DEPTH_BUFFER_BIT)
glPushMatrix()
glViewport(0, 0, size, size)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
glOrtho(0.0, size * 1.0, 0.0, size * 1.0, 0.1, 1000.0)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
gluLookAt(0,0,1, 0,0,0, 0,1,0)
for x = 0 to size
for y = 0 to size
glBegin(GL_POINTS)
pNoise = PerlinNoise(x, y, .5, 8, 32)
'pNoise = pNoise * pNoise
if MARBLE_EFFECT then
xyValue = (x * Marble.xPeriod / size) + (y * Marble.yPeriod / size) + (Marble.turbPower * pNoise)
sineVal = abs(sin(xyValue * 3.14159))
if sineVal < Marble.cutoff then
Marble.effect = sineVal
else
Marble.effect = pNoise
endif
endif
if WOOD_EFFECT then
xVal = (x - size / 2) / size
yVal = (y - size / 2) / size
distVal = (sqrt(xVal * xVal + yVal * yVal) + Wood.turbPower * pNoise) * 1.02
sineVal = abs(sin(2 * Wood.rings * distVal * 3.14159))
if distVal > .5 then
noiseBuffer = sineVal
else
noiseBuffer = 0
endif
noiseBuffer = 1 - noiseBuffer
Wood.effect = noiseBuffer
endif
if MARBLE_EFFECT then
if Marble.effect < Marble.cutoff and Marble.Effect > 0 then
pNoise = (pNoise + Marble.effect + .8) / 10.0
endif
endif
if WOOD_EFFECT then
pNoise = (pNoise + .15) * Wood.effect
endif
glColor3f ( pNoise, pNoise, pNoise)
glVertex2f( x, y)
glEnd()
WindowTitle( ((x / size) * 100) + "% Complete")
next
next
glPopMatrix()
SwapBuffers()
SaveBMP(0, 0, size, size, TextureName)
return 0
endfunction
SetMarbleParams(2, 1, .5, .15)
SetWoodParams(1.0, .2)
CreateLargePerlinMap(256.0, "Test seed 36 256x256.bmp")
WindowTitle("Done")
end
Things to note: the "random" number generator is seeded. So the same seed = the same random number every time. Basically allows for seamlessness from one texture to another one generated with *size of texture* offset.
Plus, I got the code to finally work nice and fast, generating one 128x128 section about every second on my computer. (Pre-optimization, it was taking more than 10 seconds per section to produce a really grainy, uniformly torn, awful looking image)
Also, heightmaps.
Making larger images? Just bump up the integer in CreateLargePerlinMap (4 = 512x512 image). You can also play with line 115 "pNoise = PerlinNoise..." to see what kind of effects you can get.
Results:
...just kidding, no results.
Here's the link: dl.dropboxusercontent.com/u/5319168/Test%20seed%2077%20256x256.bmp