#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Noise ?

Posts: 2,268

Hi All,

I have dabbled with noise - Perlin, simplex etc and used a few methods to design heightmap. With the arrival of Craft the noise functions have been significantly improved with lots of options to play with. Another star for Craft. But, unfortunately I’m not a mathematician and my early attempts are very crude. What I’m looking for is how to use coherent noise - example calls and the noisegradients you can generate.

Anyone got any ideas ?

• Posts: 9,287

@Bri_G The different noise functions just return different values for the same input values. The example below shows the same input x,y,z values for 3 different noise functions. The output results from them are different. To see a better representation, a 3 dimensional grid should be used.

``````function setup()
x,y,z=.1,.2,.3

n = craft.noise.perlin()
value = n:getValue(x,y,z)
print(value)

n = craft.noise.rigidMulti()
value = n:getValue(x,y,z)
print(value)

n = craft.noise.billow()
value = n:getValue(x,y,z)
print(value)
end
``````
• edited November 2017 Posts: 9,287

@Bri_G I thru together this 3D graph of some noise functions. When you run this, it takes a few seconds before the graph displays. To see the different noise results, uncomment each noise function in the for loops. The grid calculations are from x -1 To 1, y -1 To 1, and z -1 to 1 in steps of .2 . The y value is replaced with the calculation from the noise function to show the different noise values.

``````I deleted the code because of some mistakes I made.
An updated version is shown below.
``````
• Posts: 2,268

@dave1707 - thanks for that. Tried those out but ran into a problem when I tried to use craft.noise.constant() which threw up an error even with a value in the parentheses a la reference. Tried n:getValue(x,y,z) as against n(x,y,z) and the output noise.constant printed.

Being naive I thought noise was just another random function and expected to get random output. But that’s not the case - you get the same output every time from the same input. They are just mathematical functions that give different output from different input, but reproducible. Just need to bend them to our needs.

Trying to apply the features of lib.noise a la their website

Libnoise

What I’m trying to get my head round is coherent-noise.

• edited November 2017 Posts: 9,287

@Bri_G From what I know about coherent noise is:

1. It returns the same output for the same input.
2. A small input change results in a small output change
3. A large input change results in a different output change.

It’s like playing a CD. If you play the same CD, you get the same songs. If you turn up the volume a little, all the songs are the same but a little louder. If you turn up the volume a lot, it’s the same songs but distorted. Might not be a good example.

• edited November 2017 Posts: 9,287

Here’s an updated 3D graphic of some Craft noise functions. Change the noise slider, then press calc to show the noise results.

``````Removed the code.
See the updated version below.
``````
• edited November 2017 Posts: 2,268
@dave1707 - pretty awesome and prime candidate for a Craft example. Could improve slightly if you can switch off the ground or make it transparent then viewed from above you can see the 2 dimensional spread of the data ie a rectangle.
• Posts: 9,287

@Bri_G I have other changes I’m going to make to the code, so I can add a switch that shows/hides the ground.

• Posts: 9,287

@Bri_G I added your suggestion in the code below. There’s a slider to show/hide the ground. I also added a slider to allow the noise function to use a value other than 0 for the y axis. That way you can see the differences with different starting y values.

``````supportedOrientations(LANDSCAPE_ANY)

function setup()
assert(craft, "Please include Craft as a dependency")
assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
craft.noise.billow(),craft.noise.const(),craft.noise.rigidMulti()}
tab={}

fill(255, 0, 0, 255)
scene = craft.scene()
skyMaterial=scene.sky.material
skyMaterial.sky=color(0, 62, 255, 255)
skyMaterial.horizon=color(99, 255, 0, 255)
scene.sun.rotation=quat.eulerAngles(20,45,-30)
v.rx=10
v.ry=20
parameter.integer("noise",1,#nTab,1)
parameter.number("yVal",-1,2,0)
parameter.action("calc",calc)
parameter.boolean("hide ground",createGround)
calc()
end

function createSphere(x,y,z)
size=.12
sphere1=scene:entity()
sphere1.position=vec3(x,y,z)
sphere1.model = craft.model.icosphere(size,1)
sphere1.material = craft.material("Materials:Specular")
sphere1.material.diffuse=color(255,0,0)
table.insert(tab,sphere1)
end

function draw()
update(DeltaTime)
scene:draw()
text("Slide your finger to rotate image",WIDTH/2,HEIGHT-25)
text("Values from x =-1.4 to 1.4  and  z =-1.4 to 1.4    step size = .05",WIDTH/2,HEIGHT-50)
text("y = "..yVal,WIDTH/2,HEIGHT-75)
text("Noise function   =  "..name[noise],WIDTH/2,HEIGHT-100)
end

function update(dt)
scene:update(dt)
end

function createGround()
if hide_ground and ground then
ground:destroy()
ground=nil
elseif not ground then
ground = scene:entity()
ground.model = craft.model.cube(vec3(15,.05,15))
ground.material = craft.material("Materials:Specular")
end
end

function calc()
output.clear()
for z=1,#tab do
tab[z]:destroy()
end
collectgarbage()
tab={}
step=.05
n=nTab[noise]
for x=-1.4,1.4, step do
for z=-1.4,1.4,step do
value = n:getValue(x,yVal,z)
createSphere(x*5,value*5,z*5)
end
end
output.clear()
print("Change noise for another noise function then press calc.")
end
``````
• Posts: 2,268
@dave1707 - that's neat, gives the user the chance to modify the data and see it from all angles. Nice coding.
• Posts: 2,268

@John

You may be able to answer this - regarding libnoise. In the Tutorial series, tutorial 3 shows the generation of a greyscale tile. It also shows a graph of the 'bounding rectangle' used for the generation. I can generate grey scale tiles without problem but and, as in a later tutorial, can produce tiles which extend the first tile matched at the interface.

However the tutorial series suggested that the tiles will wrap so I was hoping the far right face on the second tile would wrap to match the first tile left face and bottom wraps with top faces. But that is not the case.

Could you explain what the dimensions used in the graphs are - they seem out of proportion to the scale of the images (ie 2 to 6 versus 1 to 256).

Also I am assuming I will have to write some blending routines too get the desired face overlaps - is that the case. You have already written some in the Planet generator example for Craft so I will base my routines on yours.

Could you also advise on the x,y,z parameter ranges for the calls to the noiselib. The tutorial looks like the x and z parameters are used - if so what is the y parameter. I've just fiddled with them to generate my maps and they seem to need low (<0.01) numbers.

Finally, some of the images I have generated seem to have colours in strange places. I have only used positive numbers in my coding - it looks like the craft.noise.perlin(x,y,z) call returns numbers between -1 and +1, is that the case. If so my code will need some adjustment.

By the way figured out the skybox now I can use it with obj models - looks awesome. Will post a vid later.

graph2.png 3.9K
• edited November 2017 Posts: 9,287

@Bri_G I went to the libnoise page and thought I’d write this. Here’s the prelim noise from -1 To 1 in steps of .0075. I’m changing the color based on a range of the results from the perlin noise function. Slide your finger up or down to change the z value into the perlin noise. When you lift your finger, it takes a few seconds to recalculate a new image.

``````Code removed.
An updated version is below.
``````
• edited November 2017 Posts: 2,268
@dave1707 - thanks for the code my pad battery flat and watching Peaky Blinders so will check it out tomorrow. Found some of other code in John's Voxel Terrain example. That will take a long time to digest but it answered my some of my needs with the frequency setting for the noise. Thanks again - respond again after a little rest and play.
• edited November 2017 Posts: 9,287

@Bri_G If you’re wondering about frequency, I modified my program to allow you to change the settings for the perlin noise function. Just make a slider change, tap the screen to re-calc. @John The lacunarity value doesn’t work, is it the correct spelling in the documentation.

EDIT: Changed noise.perlin() to noise.billow(). Lacunarity works for the noise function billow but not for perlin. The parameter slider for lacunarity was uncommented.

``````supportedOrientations(LANDSCAPE_ANY)

function setup()
parameter.integer("z_level",-50,50,0)
parameter.integer("octaves",1,12,6)
parameter.number("frequency",0,20,1)
parameter.number("persistence",0,2,.5)
parameter.number("lacunarity",0,10,2)
parameter.integer("seed",0,10,0)
rectMode(CENTER)
backingMode(RETAINED)
ee=true
calc()
end

function calc()
output.clear()
print("Calculating")
ee=true
tab={}
local v=craft.noise.billow()
v.octaves=octaves
v.frequency=frequency
v.persistence=persistence
v.lacunarity=lacunarity
v.seed=seed
local step=.0075
for x=-1,1,step do
for y=-1,1,step do
local z=v:getValue(x,y,z_level)
table.insert(tab,vec3(x,y,z))
end
end
output.clear()
print("Creating image")
end

function draw()
if ee then
fill(255,0,0)
text("Change a slider value then tap the screen to re-calc",WIDTH/2,HEIGHT-15)
for a,b in pairs(tab) do
setColor(b.z)
ellipse(WIDTH/2+b.x*350,HEIGHT/2+b.y*350,6)
end
ee=false
output.clear()
end
end

function touched(t)
if t.state==BEGAN then
calc()
end
end

function setColor(c)
if c<-.25 then
fill(0,0,128+c*50)
elseif c<0 then
fill(0,0,255-c*300)
elseif c<.0625 then
fill(0,128+c*500,255-c*500)
elseif c<.23 then
fill(250-c*400, 193-c*400, 64-c*400, 255)
elseif c<.4then
fill(32+c*250,160+c*250,0)
elseif c<.75 then
fill(224-c*250,244-c*150,0)
elseif c<.95 then
fill(128+c*100,128+c*100,128+c*100,128+c*100)
else
fill(255,255,255,c*300)
end
end
``````
• Posts: 9,287

@John The `lacunarity` works for noise.billow() and noise.rigidMulti() but not for noise.perlin() even though it’s listed for noise.perlin(). I don’t know if the documentation is wrong or perlin is wrong.

• Posts: 2,268
@dave1707- thanks for the update, interesting way of generating map what are the -1 to +1 scales? Is it the ouput range from the perlin noise generator.bswitched it to greyscale and saw some straight line features. Intrigued by the z_level and its range is that a feature of perlin noise?

Thanks again slowly making progress here. Do you know if you can enhance the tiles like the tutorials for lib noise by brightening and changing the contrast - thought there may be features within Craft to do it or some shaders.
• Posts: 2,268

Oops, meant say programmatically how do you adjust brightness and contrast in an image.

• Posts: 2,268

Looks like brightening is just multiplying each colour variable by a percentage. Contrast looks very similar. I thought you would graduate a change over selected ranges in the image for contrast. Think I’ll use Gimp or Affinity!!!

• Posts: 9,287

@Bri_G The -1 to +1 is just the x and y ranges. Think of graph paper where the x and y axis goes from -1 to +1. Then I just increment through all the x and y axis values by .0075 . Then think of the z level as some amount above or below the graph paper. Every point at an x,y,z value will get a number back from the noise.perlin function. So every point in a cube will get some value from noise.perlin.

• edited November 2017 Posts: 9,287

@Bri_G Here’s a cube where I calculate the perlin value for each value from -1.2 to 1.2 for x,y,z at increments of .2 . I then take the perlin value at those points and assign it a color value for each sphere. Use 2 fingers for pinch, expand, or move to zoom in, zoom out, or move the cube. It looks interesting to zoom in and rotate the cube. I also show color text that gives the color range of the spheres and the values. It takes several seconds for the color spheres to show.

``````supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)

function setup()
assert(craft, "Please include Craft as a dependency")
assert(OrbitViewer, "Please include Cameras (not Camera) as a dependency")
tab={}
scene = craft.scene()
skyMaterial=scene.sky.material
skyMaterial.sky=color(0)
skyMaterial.horizon=color(0)
scene.sun.rotation=quat.eulerAngles(20,45,-30)
v.rx=10
v.ry=20
calc()
end

function createSphere(x,y,z,val)
size=.2
sphere1=scene:entity()
sphere1.position=vec3(x*2,y*2,z*2)
sphere1.model = craft.model.icosphere(size,3)
sphere1.material = craft.material("Materials:Specular")
setColor(val)
sphere1.material.diffuse=color(r,g,b)
table.insert(tab,sphere1)
end

function setColor(v)
if v<-.9 then
r,g,b=0,0,0
elseif v<-.6 then
r,g,b=0,0,255
elseif v<-.3 then
r,g,b=0,255,0
elseif v<0 then
r,g,b=0,255,255
elseif v>.9 then
r,g,b=255,255,255
elseif v>.6 then
r,g,b=255,255,0
elseif v>.3 then
r,g,b=255,0,255
elseif v>=0 then
r,g,b=255,0,0
end
end

function draw()
update(DeltaTime)
scene:draw()
text("Slide your finger to rotate image",WIDTH/2,HEIGHT-25)
text("Two finger pinch or expand or move to zoom in or out or move.",WIDTH/2,HEIGHT-50)
fill(94, 182, 229, 255)
rect(0,425,80,200)
fill(0,0,0)
text("-1 to -.9",40,600)
fill(0,0,255)
text("-.9 to -.6",40,580)
fill(0,255,0)
text("-.6 to -.3",40,560)
fill(0,255,255)
text("-.3 to   0",40,540)
fill(255,0,0)
text("  0 to  .3",40,520)
fill(255,0,255)
text(" .3 to  .6",40,500)
fill(255,255,0)
text(" .6 to  .9",40,480)
fill(255,255,255)
text(" .9 to   1",40,460)
end

function update(dt)
scene:update(dt)
end

function calc()
tab={}
step=.2
n=craft.noise.perlin()
--n=craft.noise.billow()
for x=-1.2,1.2, step do
for y=-1.2,1.2,step do
for z=-1.2,1.2,step do
value = n:getValue(x,y,z)
createSphere(x*5,y*5,z*5,value)
end
end
end
end
``````
• Posts: 2,268

@dave1707 - aha so the value range of the noise.perlin output is used (your first/second examples) as the axes for x and y and your using the single output of the as the z value. My problem - not thinking in maths mode just thinking of a semi random value for the height in a heightmap for each x and y point.

Your third example is quite spectacular especially when you consider the array can be moved and expanded in real time and space - when you zoom into the array and move it around. Thanks again, time for me to try to use this.

• Posts: 9,287

@Bri_G All of the noise functions use x,y,z values as input and output a single value for that position. So any point in 3D space (x,y,z) has a noise value. By plotting the x,y values as a flat surface and the value returned by noise as the height, you can create unlimited landscapes.