Reputation: 1823
I'm trying to implement and learn the code from here but I'm having problems with interpolate it. This is my code from my implementation in Julia:
lerp(a, b, w) = a * (1 - w) + b * w
function Noise(x, y)
n = x + y * 53;
n = (n << 13) $ n;
return (1.0 - ( (n * ((n * n * 15731) + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
end
function coherentNoise(x,y)
x₁ = convert(Int64,modf(x)[2])
y₁ = convert(Int64,modf(y)[2])
xᵣ = x - x₁
yᵣ = y - y₁
q1 = Noise(x₁-1,y₁+1)
q2 = Noise(x₁+1,y₁+1)
q3 = Noise(x₁-1,y₁-1)
q4 = Noise(x₁-1,y₁+1)
v = lerp(q1,q2,xᵣ)
v1 = lerp(q3,q4,xᵣ)
return abs(lerp(v,v1,yᵣ))
#value = bilinear(q1,q2,q3,q4,x₁,x₁-1,x₁+1,y₁,y₁-1,y₁+1)
#return abs(value)
end
arr = Array{Float64}(height,width)
for x = 1:height
for y = 1:width
nx = x/60
ny = y/60
arr[x,y]=coherentNoise(nx,ny)
end
end
this is the result:
I tried also use this bilinear interpolation function but i get a worse result.
# bilinear interpolation
function bilinear(Q1,Q2,Q3,Q4,x,x1,x2,y,y1,y2)
R1 = ((x2-x)/(x2-x1))*Q3 + ((x-x1)/(x2-x1))*Q4
R2 = ((x2-x)/(x2-x1))*Q1 + ((x-x1)/(x2-x1))*Q2
P = ((y2-y)/(y2-y1))*R1 + ((y-y1)/(y2-y1))*R2
return P
end
the result:
I don't know if is a problem with theNoise
function or something else.
I'm obtaining best results using bilinear interpolation with the next noise generator function:
function coherentNoise(x,y,n::Int64)
#octa3e
o = 0.25
#octave x and y
x /=n
y /=n
#decimal value
x₁ = x < 0 ? x : x-o
y₁ = y < 0 ? y : y-o
x₂ = x+o
y₂ = y+o
#calculate corners data
q1 = abs(Noise(floor(Int64,x₁),floor(Int64,y₂)))
q2 = abs(Noise(floor(Int64,x₂),floor(Int64,y₂)))
q3 = abs(Noise(floor(Int64,x₁),floor(Int64,y₁)))
q4 = abs(Noise(floor(Int64,x₂),floor(Int64,y₁)))
#bilenear interpolation
value = bilinear(q2,q1,q4,q3,x,x₁,x₂,y,y₁,y₂)
return abs(value)
end
Result:
I'm thinking that the problem is how I select the points to do the bilinear interpolation, no idea how to do it right.
This is the code to generate the images:
for x = 1:height
for y = 1:width
arr[x,y]=coherentNoise(x,y,50)
end
end
imwrite(convert(Image,arr),"desktop/projects/julia/Noise/test2.png")
Thanks to the answer of Dan Getz I'm getting a better output but with some weird "worms"
output:
Upvotes: 2
Views: 620
Reputation: 18217
Without the ability to test the code, this should need verification. Basically, I think your intuition the problem is in the choice of interpolation points is right. This is an attempt to fix it (see also comments).
function coherentNoise(x,y)
x₁,xᵣ = floor(Int64,x),mod(x,1)
y₁,yᵣ = floor(Int64,y),mod(y,1)
q00 = Noise(x₁,y₁)
q10 = Noise(x₁+1,y₁)
q01 = Noise(x₁,y₁+1)
q11 = Noise(x₁+1,y₁+1)
v0 = lerp(q00,q10,xᵣ)
v1 = lerp(q01,q11,xᵣ)
noise = lerp(v0,v1,yᵣ)
return noise
end
Notes:
q
s renamed to q00
and such to indicate which corner by the offset to X (first number) and Y (second number). q1
and q4
fixed.floor
and mod( ,1)
used instead of modf
since they choose consistent rounding direction (downward) regardless of sign.Noise
function should type annotate its parameters to restrict to Int32 values, and the ;
at line ends in this function not needed. This is a hash function, and the same effect could be easily coded with Julia hash function and a little wrapper. For example:
Noise(x,y) = 1.0-2.0*hash((x,y))/typemax(UInt)
is a more Julia styled drop-in replacement for Noise
.
If you try this and comment on bugs, we can try to fixup function.
Upvotes: 2