无缝 1-D SImplex 噪声问题
Issue with seamless 1-D SImplex noise
通常在生成无缝单纯形噪声时,策略是转到 4 维(过去在使用 2-D 单纯形时这种策略对我来说效果很好),但是我正在尝试生成无缝 GIF 循环使用一维单纯形噪声(只对线图中指定 Y 值的噪声感兴趣)。
我很好奇我是否误解了如何在 1-D 中使事物无缝,或者我是否可能在此处出现逻辑错误。基本上,我正在生成一个二维数组,其中第一维是 Z 轴,第二维是该 Z 的点列表(x-y 值)。我遍历每个 z 并简单地依次绘制每个顶点.
我注意到,当我达到最大 Z 值时,有一个明显的跳跃表明我做错了什么(不是无缝的)。
我正在使用 fast-simplex-noise
库(我喜欢它胜过 P5 的内置 noise
函数)并指定为:
function setup() {
let freq = 0.005;
let octaves = 14;
_noise = new FastSimplexNoise({ frequency: freq, octaves: octaves });
// specify the points:
points = [];
step = 0;
maxSteps = 150;
let r = 1.0;
for (let z = 0; z < maxSteps; z++) {
let t = (1.0 * z) / maxSteps;
points[z] = [];
for (let x = o + 10; x < width - o - 10; x++) {
let _n = _noise.get4DNoise(x, z, r*cos(TWO_PI*t), r*sin(TWO_PI*t));
let _y = height/2 + 250*_n;
points[i].push({ x: x, y: _y });
}
}
}
在 draw
函数中,我简单地遍历 points
列表中的每个顶点,并跟踪每次绘制迭代的当前 z
值。
听起来您期望从 z = maxSteps - 1
跳到 z = 0
时噪声值的变化很小。但是,当您将 z
指定为 get4DNoise
的第二个参数时,情况就不一样了,因为对于 [=14= 的这两个值,第三维和第四维彼此非常接近](由于使用了正弦和余弦),第二个将相差 maxSteps - 1
。这就引出了一个问题:你为什么要使用 4D 噪声?您正在尝试随机改变 y
,以便它随着 z
或 x
的变化而平滑变化,并循环返回。为了实现这一点,您只需要在 3d space 围绕圆柱体移动时沿直线采样噪声值。
这是您的噪声算法的可视化效果,与仅使用 3d 噪声的算法非常相似。注意左边的圆柱体有接缝,而右边的圆柱体没有接缝:
const maxSteps = 100;
const scaleFactor = 20;
let texture1;
let texture2;
let _noise;
let cam;
function setup() {
let size = Math.min(windowWidth, windowHeight);
createCanvas(size, size, WEBGL);
noStroke();
cam = createCamera();
cam.setPosition(0, 0, 500);
cam.lookAt(0, 0, 0);
_noise = new FastSimplexNoise({
frequency: 0.005,
octaves: 14
});
texture1 = makeTexture(true);
texture2 = makeTexture(false);
}
function doubleClicked() {
console.log(cam);
}
function makeTexture(use4d) {
let points = [];
// Using an r of 1.0 covers a very small and unchanging region of noise space
let r = use4d ? 1.0 : maxSteps / 2;
for (let z = 0; z < maxSteps; z++) {
let t = z / maxSteps;
points[z] = [];
for (let x = 0; x < maxSteps; x++) {
let _n =
use4d ?
_noise.get4DNoise(x, z, r * cos(TWO_PI * t), r * sin(TWO_PI * t)) :
_noise.get3DNoise(x, r * cos(TWO_PI * t), r * sin(TWO_PI * t));
let _y = 250 * _n;
points[z].push({
x: x,
y: _y
});
}
}
let g = createGraphics(maxSteps, maxSteps);
for (let z = 0; z < maxSteps; z++) {
for (let x = 0; x < maxSteps; x++) {
// x == points[z][x].x
// Using z as x and x as y because of the texture coordinate layout for cylinders
g.set(
z, x,
// Shifting y values upward because they tend to be small resulting in a dark texture
map(points[z][x].y, 0, 250, 100, 300)
);
}
}
// required after set()?
g.updatePixels();
return g;
}
function draw() {
background(255);
orbitControl(2, 1, 0.1);
push();
translate(-150, 0, 0);
texture(texture1);
cylinder(100, 200);
pop();
push();
translate(150, 0, 0);
texture(texture2);
cylinder(100, 200);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fast-simplex-noise@1.0.0/fast-simplex-noise.js"></script>
通常在生成无缝单纯形噪声时,策略是转到 4 维(过去在使用 2-D 单纯形时这种策略对我来说效果很好),但是我正在尝试生成无缝 GIF 循环使用一维单纯形噪声(只对线图中指定 Y 值的噪声感兴趣)。
我很好奇我是否误解了如何在 1-D 中使事物无缝,或者我是否可能在此处出现逻辑错误。基本上,我正在生成一个二维数组,其中第一维是 Z 轴,第二维是该 Z 的点列表(x-y 值)。我遍历每个 z 并简单地依次绘制每个顶点.
我注意到,当我达到最大 Z 值时,有一个明显的跳跃表明我做错了什么(不是无缝的)。
我正在使用 fast-simplex-noise
库(我喜欢它胜过 P5 的内置 noise
函数)并指定为:
function setup() {
let freq = 0.005;
let octaves = 14;
_noise = new FastSimplexNoise({ frequency: freq, octaves: octaves });
// specify the points:
points = [];
step = 0;
maxSteps = 150;
let r = 1.0;
for (let z = 0; z < maxSteps; z++) {
let t = (1.0 * z) / maxSteps;
points[z] = [];
for (let x = o + 10; x < width - o - 10; x++) {
let _n = _noise.get4DNoise(x, z, r*cos(TWO_PI*t), r*sin(TWO_PI*t));
let _y = height/2 + 250*_n;
points[i].push({ x: x, y: _y });
}
}
}
在 draw
函数中,我简单地遍历 points
列表中的每个顶点,并跟踪每次绘制迭代的当前 z
值。
听起来您期望从 z = maxSteps - 1
跳到 z = 0
时噪声值的变化很小。但是,当您将 z
指定为 get4DNoise
的第二个参数时,情况就不一样了,因为对于 [=14= 的这两个值,第三维和第四维彼此非常接近](由于使用了正弦和余弦),第二个将相差 maxSteps - 1
。这就引出了一个问题:你为什么要使用 4D 噪声?您正在尝试随机改变 y
,以便它随着 z
或 x
的变化而平滑变化,并循环返回。为了实现这一点,您只需要在 3d space 围绕圆柱体移动时沿直线采样噪声值。
这是您的噪声算法的可视化效果,与仅使用 3d 噪声的算法非常相似。注意左边的圆柱体有接缝,而右边的圆柱体没有接缝:
const maxSteps = 100;
const scaleFactor = 20;
let texture1;
let texture2;
let _noise;
let cam;
function setup() {
let size = Math.min(windowWidth, windowHeight);
createCanvas(size, size, WEBGL);
noStroke();
cam = createCamera();
cam.setPosition(0, 0, 500);
cam.lookAt(0, 0, 0);
_noise = new FastSimplexNoise({
frequency: 0.005,
octaves: 14
});
texture1 = makeTexture(true);
texture2 = makeTexture(false);
}
function doubleClicked() {
console.log(cam);
}
function makeTexture(use4d) {
let points = [];
// Using an r of 1.0 covers a very small and unchanging region of noise space
let r = use4d ? 1.0 : maxSteps / 2;
for (let z = 0; z < maxSteps; z++) {
let t = z / maxSteps;
points[z] = [];
for (let x = 0; x < maxSteps; x++) {
let _n =
use4d ?
_noise.get4DNoise(x, z, r * cos(TWO_PI * t), r * sin(TWO_PI * t)) :
_noise.get3DNoise(x, r * cos(TWO_PI * t), r * sin(TWO_PI * t));
let _y = 250 * _n;
points[z].push({
x: x,
y: _y
});
}
}
let g = createGraphics(maxSteps, maxSteps);
for (let z = 0; z < maxSteps; z++) {
for (let x = 0; x < maxSteps; x++) {
// x == points[z][x].x
// Using z as x and x as y because of the texture coordinate layout for cylinders
g.set(
z, x,
// Shifting y values upward because they tend to be small resulting in a dark texture
map(points[z][x].y, 0, 250, 100, 300)
);
}
}
// required after set()?
g.updatePixels();
return g;
}
function draw() {
background(255);
orbitControl(2, 1, 0.1);
push();
translate(-150, 0, 0);
texture(texture1);
cylinder(100, 200);
pop();
push();
translate(150, 0, 0);
texture(texture2);
cylinder(100, 200);
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fast-simplex-noise@1.0.0/fast-simplex-noise.js"></script>