首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为3D空间中的点生成随机移动

为3D空间中的点生成随机移动
EN

Stack Overflow用户
提问于 2019-06-14 00:27:51
回答 1查看 172关注 0票数 0

我想模拟一个点,它以随机振动围绕平均位置移动(假设围绕位置X,Y,Z= 0,0,0)。我找到的第一个解决方案是根据下面的等式对每个轴的两个正弦进行求和:

代码语言:javascript
复制
<a href="https://www.codecogs.com/eqnedit.php?latex=\sum_{i&space;=&space;1}^n&space;A_i&space;\sin(\omega_i&space;t&plus;\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&plus;\phi)" title="\sum_{i = 1}^n A_i \sin(\omega_i t+\phi)" /></a>

其中A_i是一个正常的随机振幅,omega_i是一个正常的随机频率。我还没有测试这个阶段,所以我现在把它留为零。我用下面的approach生成了期望正态分布的图形和方程结果。我尝试了N的多个值,但我不确定方程是否给出了正态分布的结果。我的方法正确吗?有没有更好的方法来产生随机振动?

EN

回答 1

Stack Overflow用户

发布于 2019-06-24 00:54:44

对于这样的任务,您可能会发现有用的Perlin Noise,甚至Fractal Brownian noise。在JavaScript中查看此实现:

代码语言: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;
    }
} 

使用分形布朗运动可以对分布的随机性进行巨大的控制。您可以为每个轴设置scale、initial offset及其incrementoctaves和and您可以通过增加偏移量来生成任意数量的位置,如下所示:

代码语言:javascript
复制
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++;
}

使用这些选项获得的职位看起来类似于以下内容:

代码语言:javascript
复制
...
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}
...

注意:为了提高效率,一个好主意是只将所有位置生成一次位置数组,然后在一些动画循环中从这个数组中将位置逐个分配给您的点。

额外好处:在这里你可以看到这些值是如何影响多个点的分布的,方法是使用实时响应控制面板:https://marianpekar.github.io/fbm-space/

参考文献:

https://en.wikipedia.org/wiki/Fractional_Brownian_motion

https://en.wikipedia.org/wiki/Perlin_noise

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56584879

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档