我想模拟一个点,该点在平均位置附近随机振动(假设在[X,Y,Z] = [0,0,0]位置附近)。我发现的第一个解决方案是根据以下方程式为每个轴加两个正弦值:
<a href="https://www.codecogs.com/eqnedit.php?latex=\sum_{i&space;=&space;1}^n&space;A_i&space;\sin(\omega_i&space;t+\phi)" target="_blank"><img src="https://latex.codecogs.com/gif.latex?\sum_{i&space;=&space;1}^n&space;A_i&space;\sin(\omega_i&space;t+\phi)" title="\sum_{i = 1}^n A_i \sin(\omega_i t+\phi)" /></a>
其中A_i
是正常随机幅度,而omega_i
是正常随机频率。我尚未测试阶段,因此暂时将其保留为零。我使用以下approach生成了预期正态分布和方程结果的图形。我尝试了N
的多个值,但不确定该方程式给出的结果是否为正态分布。我的方法正确吗?有没有更好的方法来产生随机振动?
答案 0 :(得分:2)
对于此类任务,您可能会发现有用的佩林噪声,甚至是分形布朗运动噪声。在JavaScript中查看此实现:
class Utils {
static Lerp(a, b, t) {
return (1 - t) * a + t * b;
}
static Fade(t) {
return t * t * t * (t * (t * 6 - 15) + 10);
}
}
class Noise {
constructor() {
this.p = [];
this.permutationTable = [];
this.grad3 = [[1, 1, 0], [-1, 1, 0], [1, -1, 0],
[-1, -1, 0], [1, 0, 1], [-1, 0, 1],
[1, 0, -1], [-1, 0, -1], [0, 1, 1],
[0, -1, 1], [0, 1, -1], [0, -1, -1]];
for (let i = 0; i < 256; i++)
this.p[i] = Math.floor(Math.random() * 256);
for (let i = 0; i < 512; i++)
this.permutationTable[i] = this.p[i & 255];
}
PerlinDot(g, x, y, z) {
return g[0] * x + g[1] * y + g[2] * z;
}
PerlinNoise(x, y, z) {
let a = Math.floor(x);
let b = Math.floor(y);
let c = Math.floor(z);
x = x - a;
y = y - b;
z = z - c;
a &= 255;
b &= 255;
c &= 255;
let gi000 = this.permutationTable[a + this.permutationTable[b + this.permutationTable[c]]] % 12;
let gi001 = this.permutationTable[a + this.permutationTable[b + this.permutationTable[c + 1]]] % 12;
let gi010 = this.permutationTable[a + this.permutationTable[b + 1 + this.permutationTable[c]]] % 12;
let gi011 = this.permutationTable[a + this.permutationTable[b + 1 + this.permutationTable[c + 1]]] % 12;
let gi100 = this.permutationTable[a + 1 + this.permutationTable[b + this.permutationTable[c]]] % 12;
let gi101 = this.permutationTable[a + 1 + this.permutationTable[b + this.permutationTable[c + 1]]] % 12;
let gi110 = this.permutationTable[a + 1 + this.permutationTable[b + 1 + this.permutationTable[c]]] % 12;
let gi111 = this.permutationTable[a + 1 + this.permutationTable[b + 1 + this.permutationTable[c + 1]]] % 12;
let n000 = this.PerlinDot(this.grad3[gi000], x, y, z);
let n100 = this.PerlinDot(this.grad3[gi100], x - 1, y, z);
let n010 = this.PerlinDot(this.grad3[gi010], x, y - 1, z);
let n110 = this.PerlinDot(this.grad3[gi110], x - 1, y - 1, z);
let n001 = this.PerlinDot(this.grad3[gi001], x, y, z - 1);
let n101 = this.PerlinDot(this.grad3[gi101], x - 1, y, z - 1);
let n011 = this.PerlinDot(this.grad3[gi011], x, y - 1, z - 1);
let n111 = this.PerlinDot(this.grad3[gi111], x - 1, y - 1, z - 1);
let u = Utils.Fade(x);
let v = Utils.Fade(y);
let w = Utils.Fade(z);
let nx00 = Utils.Lerp(n000, n100, u);
let nx01 = Utils.Lerp(n001, n101, u);
let nx10 = Utils.Lerp(n010, n110, u);
let nx11 = Utils.Lerp(n011, n111, u);
let nxy0 = Utils.Lerp(nx00, nx10, v);
let nxy1 = Utils.Lerp(nx01, nx11, v);
return Utils.Lerp(nxy0, nxy1, w);
}
FractalBrownianMotion(x, y, z, octaves, persistence) {
let total = 0;
let frequency = 1;
let amplitude = 1;
let maxValue = 0;
for(let i = 0; i < octaves; i++) {
total = this.PerlinNoise(x * frequency, y * frequency, z * frequency) * amplitude;
maxValue += amplitude;
amplitude *= persistence;
frequency *= 2;
}
return total / maxValue;
}
}
借助分形布朗运动,可以对分布的随机性进行极大的控制。您可以为每个轴,倍频程和持久性设置比例,初始偏移及其增量。 。您可以通过增加偏移量生成任意数量的位置,如下所示:
const NUMBER_OF_POSITIONS = 1000;
const X_OFFSET = 0;
const Y_OFFSET = 0;
const Z_OFFSET = 0;
const X_SCALE = 0.01;
const Y_SCALE = 0.01;
const Z_SCALE = 0.01;
const OCTAVES = 8;
const PERSISTENCE = 2;
const T_INCREMENT = 0.1;
const U_INCREMENT = 0.01;
const V_INCREMENT = 1;
let noise = new Noise();
let positions = [];
let i = 0, t = 0, u = 0, v = 0;
while(i <= NUMBER_OF_POSITIONS) {
let position = {x:0, y:0, z:0};
position.x = noise.FractalBrownianMotion((X_OFFSET + t) * X_SCALE, (Y_OFFSET + t) * Y_SCALE, (Z_OFFSET + t) * Z_SCALE, OCTAVES, PERSISTENCE);
position.y = noise.FractalBrownianMotion((X_OFFSET + u) * X_SCALE, (Y_OFFSET + u) * Y_SCALE, (Z_OFFSET + u) * Z_SCALE, OCTAVES, PERSISTENCE);
position.z = noise.FractalBrownianMotion((X_OFFSET + v) * X_SCALE, (Y_OFFSET + v) * Y_SCALE, (Z_OFFSET + v) * Z_SCALE, OCTAVES, PERSISTENCE);
positions.push(position);
t += T_INCREMENT;
u += U_INCREMENT;
v += V_INCREMENT;
i++;
}
通过这些选项获得的位置看起来与以下类似:
...
501: {x: 0.0037344935483775883, y: 0.1477509219864437, z: 0.2434570202517206}
502: {x: -0.008955635460317357, y: 0.14436114483299245, z: -0.20921147024725012}
503: {x: -0.06021806450587406, y: 0.14101769272762685, z: 0.17093922757597568}
504: {x: -0.05796055906294283, y: 0.13772732578136435, z: 0.0018755951606465138}
505: {x: 0.02243901814464688, y: 0.13448621540816477, z: 0.013341084536334057}
506: {x: 0.05074194554980439, y: 0.1312810723109357, z: 0.15821600463130164}
507: {x: 0.011075140752144507, y: 0.12809058766450473, z: 0.04006055269090941}
508: {x: -0.0000031848272303249632, y: 0.12488712875549206, z: -0.003957905411646261}
509: {x: -0.0029798194097060307, y: 0.12163862278870072, z: -0.1988934273517602}
510: {x: -0.008762098499026483, y: 0.11831055728747841, z: 0.02222898347134993}
511: {x: 0.01980289423585394, y: 0.11486802263767962, z: -0.0792283303765883}
512: {x: 0.0776034130079849, y: 0.11127772191732693, z: -0.14141576745502138}
513: {x: 0.08695806478169149, y: 0.10750987521108693, z: 0.049654228704645}
514: {x: 0.036915612100698, y: 0.10353995005320946, z: 0.00033977899920740567}
515: {x: 0.0025923223158845687, y: 0.09935015632822117, z: -0.00952549797548823}
516: {x: 0.0015456084571764527, y: 0.09493065267319889, z: 0.12609905321632175}
517: {x: 0.0582996941155056, y: 0.09028042189611517, z: -0.27532974820612816}
518: {x: 0.19186052966982514, y: 0.08540778482478142, z: -0.00035058098387404606}
519: {x: 0.27063961068049447, y: 0.08033053495775729, z: -0.07737309686568927}
520: {x: 0.20318957178662056, y: 0.07507568989311474, z: -0.14633819135757353}
...
注意:为了提高效率,最好将所有位置生成一次(如本例所示)到一个位置数组中,然后在某些动画循环中,仅从该数组中为您的点逐个分配位置。 / em>
奖金:在这里,您可以通过使用实时响应控制面板来查看这些值如何影响多个点的分布: https://marianpekar.github.io/fbm-space/
参考文献: