在 Julia 中插入梯度噪声
Interpolate Gradient noise in Julia
我正在尝试实施和学习 here 的代码,但我在插入它时遇到了问题。这是我在 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
这是结果:
我也试过使用这个双线性插值函数,但结果更差。
# 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
结果:
不知道是Noise
函数的问题还是其他什么问题。
更新
我使用双线性插值和下一个噪声生成器函数获得了最佳结果:
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
结果:
我在想问题是我如何 select 做双线性插值的点,不知道如何做对。
更新 2:
这是生成图像的代码:
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")
更新 3
感谢 的回答,我得到了更好的输出,但有些奇怪 "worms"
输出:
没有测试代码的能力,这应该需要验证。基本上,我认为您的直觉问题在于插值点的选择是正确的。这是修复它的尝试(另请参阅评论)。
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
备注:
q
s 重命名为 q00
等以指示偏移到 X(第一个数字)和 Y(第二个数字)的角。
- 相同的
q1
和 q4
已修复。
使用 floor
和 mod( ,1)
而不是 modf
因为它们选择一致的舍入方向(向下)而不考虑符号。
Noise
函数应该对其参数进行类型注释以限制为 Int32 值,并且此函数不需要行尾的 ;
。这是一个哈希函数,同样的效果可以很容易地用 Julia 哈希函数和一个小包装器来编码。
例如:
Noise(x,y) = 1.0-2.0*hash((x,y))/typemax(UInt)
是 Noise
的更具 Julia 风格的替代品。
如果您尝试此操作并评论错误,我们可以尝试修复功能。
我正在尝试实施和学习 here 的代码,但我在插入它时遇到了问题。这是我在 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
这是结果:
我也试过使用这个双线性插值函数,但结果更差。
# 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
结果:
不知道是Noise
函数的问题还是其他什么问题。
更新
我使用双线性插值和下一个噪声生成器函数获得了最佳结果:
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
结果:
我在想问题是我如何 select 做双线性插值的点,不知道如何做对。
更新 2:
这是生成图像的代码:
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")
更新 3
感谢
输出:
没有测试代码的能力,这应该需要验证。基本上,我认为您的直觉问题在于插值点的选择是正确的。这是修复它的尝试(另请参阅评论)。
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
备注:
q
s 重命名为q00
等以指示偏移到 X(第一个数字)和 Y(第二个数字)的角。- 相同的
q1
和q4
已修复。
使用 floor
和mod( ,1)
而不是modf
因为它们选择一致的舍入方向(向下)而不考虑符号。Noise
函数应该对其参数进行类型注释以限制为 Int32 值,并且此函数不需要行尾的;
。这是一个哈希函数,同样的效果可以很容易地用 Julia 哈希函数和一个小包装器来编码。
例如:
Noise(x,y) = 1.0-2.0*hash((x,y))/typemax(UInt)
是 Noise
的更具 Julia 风格的替代品。
如果您尝试此操作并评论错误,我们可以尝试修复功能。