Matlab 为三维空间中的点生成随机运动

Matlab 为三维空间中的点生成随机运动,matlab,random,game-physics,trigonometry,Matlab,Random,Game Physics,Trigonometry,我想模拟一个点,它在一个平均位置(比如在[X,Y,Z]=[0,0,0])周围随机振动。我发现的第一个解决方案是根据以下等式,对每个轴的两个正弦曲线求和: 对于这样的任务,您可能会发现有用的柏林噪声甚至分形布朗运动噪声。请参阅JavaScript中的此实现: class Utils { static Lerp(a, b, t) { return (1 - t) * a + t * b; } static Fade(t) { return

我想模拟一个点,它在一个平均位置(比如在[X,Y,Z]=[0,0,0])周围随机振动。我发现的第一个解决方案是根据以下等式,对每个轴的两个正弦曲线求和:


对于这样的任务,您可能会发现有用的柏林噪声甚至分形布朗运动噪声。请参阅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;
    }
} 
注意:为了提高效率,最好只将所有位置生成一次到一个位置数组中,如本例所示,然后在一些动画循环中,从该数组中逐个为点指定位置

奖励:在这里,您可以通过使用实时响应控制面板了解这些值如何影响多个点的分布:

参考资料:


对于这样的任务,您可能会发现有用的柏林噪声甚至分形布朗运动噪声。请参阅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;
    }
} 
注意:为了提高效率,最好只将所有位置生成一次到一个位置数组中,如本例所示,然后在一些动画循环中,从该数组中逐个为点指定位置

奖励:在这里,您可以通过使用实时响应控制面板了解这些值如何影响多个点的分布:

参考资料:


为什么需要正弦曲线?只需为每个振动在每个方向上添加一个随机偏移。如果使用正态分布的随机数,结果直方图将是正态分布的,并具有预期的高斯“钟形”curve@EliahuAaron我希望点有一个平滑的运动。随机运动不是“平滑”,而是“抖动”。也许你想在一条“平滑”的路径上移动点,给它添加一个小的随机振动。如果是这样,您可以在每个方向上选择一条正弦路径,并向其添加一些小的随机变量noise@EliahuAaron如果可以用正弦和(或其他东西)进行高斯近似,我可以创建平滑运动。@EliahuAaron,一个简单的例子就是海浪的高度。我猜高度会相对平滑(即,船上没有抖动),可以用一些随机分布来近似。为什么需要正弦曲线?只需为每个振动在每个方向上添加一个随机偏移。如果使用正态分布的随机数,结果直方图将是正态分布的,并具有预期的高斯“钟形”curve@EliahuAaron我希望点有一个平滑的运动。随机运动不是“平滑”,而是“抖动”。也许你想在一条“平滑”的路径上移动点,给它添加一个小的随机振动。如果是这样,您可以在每个方向上选择一条正弦路径,并向其添加一些小的随机变量noise@EliahuAaron如果可以用正弦和(或其他东西)进行高斯近似,我可以创建平滑运动。@EliahuAaron,一个简单的例子就是海浪的高度。我猜高度会相对平滑(即,船上没有抖动),并且可以通过一些随机分布来近似。谢谢你的详细回答,我会尝试实现,看看我是否可以实现。谢谢你的详细回答,我会尝试实现,看看我能不能实现。
...
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}
...