在閱讀peachykeen的回答並在互聯網上做了一些(更多)自己的研究後,我發現了以下解決方案爲我工作。
我的執行Perlin雜的,使用的值的範圍[0.0 .. 1.0]雷電路徑節點工作最好,使數值(雙)M /(雙)N爲節點M到柏林噪聲函數。爲了使噪聲函數F'返回節點0和節點N-1的相同值,可以應用下面的公式:F'(M)=((M-N)* F(N)+ N * F(N - M))/ M。爲了使閃電路徑偏移以0開始和結束,您只需在計算路徑後從所有閃電路徑偏移中減去F'(0)。在計算每個路徑節點的偏移量之前,可以計算隨機偏移量R,並將其與傳遞給噪聲函數的值相加,以便節點的偏移量O = F'(N + 1) R)。爲了給閃電設置動畫,需要計算兩條閃電路徑(開始幀和結束幀),然後每個路徑頂點必須在其開始和結束位置之間放置。一旦到達結束幀,結束幀就成爲開始幀,並計算新的結束幀。對於3D路徑,對於每個路徑節點N,可以計算兩個垂直於節點N處的路徑和彼此的偏移矢量,並且可以利用兩個1D柏林噪聲值來縮放,以從節點位置開始到結束幀位置。這可能比3D Perlin噪音更便宜,而且在我的應用程序中效果很好。
這裏是我的執行標準一維Perlin雜點作爲基準(有些東西是虛擬的,因爲我用這作爲基地,爲改善柏林噪聲,從而在戰略格局的應用程序使用標準的或改進的柏林噪聲的。該代碼已經有所簡化,以及使它在這裏發佈吧)更簡潔:
頭文件
#ifndef __PERLIN_H
#define __PERLIN_H
class CPerlin {
private:
int m_randomize;
protected:
double m_amplitude;
double m_persistence;
int m_octaves;
public:
virtual void Setup (double amplitude, double persistence, int octaves, int randomize = -1);
double ComputeNoise (double x);
protected:
double LinearInterpolate (double a, double b, double x);
double CosineInterpolate (double a, double b, double x);
double CubicInterpolate (double v0, double v1, double v2, double v3, double x);
double Noise (int v);
double SmoothedNoise (int x);
virtual double InterpolatedNoise (double x);
};
#endif //__PERLIN_H
實現:
#include <math.h>
#include <stdlib.h>
#include "perlin.h"
#define INTERPOLATION_METHOD 1
#ifndef Pi
# define Pi 3.141592653589793240
#endif
inline double CPerlin::Noise (int n) {
n = (n << 13)^n;
return 1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff)/1073741824.0;
}
double CPerlin::LinearInterpolate (double a, double b, double x) {
return a * (1.0 - x) + b * x;
}
double CPerlin::CosineInterpolate (double a, double b, double x) {
double f = (1.0 - cos (x * Pi)) * 0.5;
return a * (1.0 - f) + b * f;
}
double CPerlin::CubicInterpolate (double v0, double v1, double v2, double v3, double x) {
double p = (v3 - v2) - (v0 - v1);
double x2 = x * x;
return v1 + (v2 - v0) * x + (v0 - v1 - p) * x2 + p * x2 * x;
}
double CPerlin::SmoothedNoise (int v) {
return Noise (v)/2 + Noise (v-1)/4 + Noise (v+1)/4;
}
int FastFloor (double v) { return (int) ((v < 0) ? v - 1 : v; }
double CPerlin::InterpolatedNoise (double v) {
int i = FastFloor (v);
double v1 = SmoothedNoise (i);
double v2 = SmoothedNoise (i + 1);
#if INTERPOLATION_METHOD == 2
double v0 = SmoothedNoise (i - 1);
double v3 = SmoothedNoise (i + 2);
return CubicInterpolate (v0, v1, v2, v3, v - i);
#elif INTERPOLATION_METHOD == 1
return CosineInterpolate (v1, v2, v - i);
#else
return LinearInterpolate (v1, v2, v - i);
#endif
}
double CPerlin::ComputeNoise (double v) {
double total = 0, amplitude = m_amplitude, frequency = 1.0;
v += m_randomize;
for (int i = 0; i < m_octaves; i++) {
total += InterpolatedNoise (v * frequency) * amplitude;
frequency *= 2.0;
amplitude *= m_persistence;
}
return total;
}
void CPerlin::Setup (double amplitude, double persistence, int octaves, int randomize) {
m_amplitude = (amplitude > 0.0) ? amplitude : 1.0;
m_persistence = (persistence > 0.0) ? persistence : 2.0/3.0;
m_octaves = (octaves > 0) ? octaves : 6;
m_randomize = (randomize < 0) ? (rand() * rand()) & 0xFFFF : randomize;
}
這個問題很好。 – sharptooth
http://www.noisemachine.com/talk1/23.html –