昨天在公司谈及关于动态云的模拟问题,这个东西以前大学时曾做过,利用Ken Perlin noise 来生成,只是没有生成连续变化的效果.
今天在家花了一个下午的时间去实现, 有参考 Gpu Gems 1 上的 improve perlin noise 论文, 但是最后发现,5次方插值根本就不适用于云层的模拟,不过倒是非常适合大连续体积,比如heigh map 中山体,凹地等的模拟.对于云层,我必须设计一个 小体积,更加分散,并且能在临界区连续的 noise 算法. 而且也有必要使连续云层的轮廓稍微尖锐.
时刻1
以上是同一次随机种子下连续4个不同时刻,云层的切片.
<download demo> : 点击下载演示程序.
我的噪音函数.
struct NoiseTable
{
NoiseTable() // 自动初始化
{
for (int i=0; i<256; i++ )
{
permutation[i] = noise_rand.Get() & 255;
}
for (int i=0; i < 256 ; i++)
{
gradTable[256+i] = gradTable[i] = permutation[i];
}
}
int permutation[256]; // 散列
int gradTable[512]; // 斜率矢量表
};
NoiseTable g_NoiseTable;
static inline float Curve_5(float t) // 5次方采样曲线
{
return t * t * t * (t * (t * 6 - 15) + 10);
}
static inline float Curve_3(float t) // 立方采样曲线 hermite
{
return t * t * (3 - 2 * t);
}
static inline float Curve_sin(float t)
{
return 0.0f;
}
// 插值函数
inline float Lerp(float t, float a, float b)
{
return a + t * (b - a);
}
typedef struct _float3
{
float r;
float s;
float t;
}float3;
typedef struct _float4
{
float x;
float y;
float z;
float w;
}float4;
inline float Grad(float c)
{
static int Y;
static int X;
static float c2;
X = floor(c);
c2 = c - X;
X = int(c) % 255;
Y = X+1;
if (Y>255)
{
Y = 0;
}
return (Lerp(c2,g_NoiseTable.permutation[X],g_NoiseTable.permutation[Y]));//1/256.0f
}
float NoiseCloud(float x, float y, float z/**//*, float w*/)
{
static int* pTable = g_NoiseTable.gradTable;
static float3 texCoord1;
static float3 texCoord2;
texCoord1.r = floor(x);
texCoord1.s = floor(y);
texCoord1.t = floor(z);
x -= texCoord1.r;
y -= texCoord1.s;
z -= texCoord1.t;
// next texel.
texCoord2.r = texCoord1.r+1.0f;
texCoord2.s = texCoord1.s+1.0f;
texCoord2.t = texCoord1.t+1.0f;
static float4 Texel1;
static float4 Texel2;
Texel1.x = Grad(Grad(Grad(texCoord1.r)+texCoord1.s)+texCoord1.t);
Texel2.x = Grad(Grad(Grad(texCoord2.r)+texCoord1.s)+texCoord1.t);
Texel1.y = Grad(Grad(Grad(texCoord1.r)+texCoord2.s)+texCoord1.t);
Texel2.y = Grad(Grad(Grad(texCoord2.r)+texCoord2.s)+texCoord1.t);
Texel1.z = Grad(Grad(Grad(texCoord1.r)+texCoord1.s)+texCoord2.t);
Texel2.z = Grad(Grad(Grad(texCoord2.r)+texCoord1.s)+texCoord2.t);
Texel1.w = Grad(Grad(Grad(texCoord1.r)+texCoord2.s)+texCoord2.t);
Texel2.w = Grad(Grad(Grad(texCoord2.r)+texCoord2.s)+texCoord2.t);
static float u;
static float v;
static float w;
u = Curve_3(x);
v = Curve_3(y);
w = Curve_3(z);
// x
Texel1.x = Lerp(u,Texel1.x,Texel2.x);
Texel1.y = Lerp(u,Texel1.y,Texel2.y);
Texel1.z = Lerp(u,Texel1.z,Texel2.z);
Texel1.w = Lerp(u,Texel1.w,Texel2.w);
// y
Texel2.x = Lerp(v,Texel1.x,Texel1.y);
Texel2.y = Lerp(v,Texel1.z,Texel1.w);
// z
return Lerp(w,Texel2.x,Texel2.y);
}
将来的工作:
1, 采用多线程,产生一个独立线程进行噪音计算,
2.使用程序纹理,利用GPU来计算.(Pixel Shader 可能会有很多条指令,导致低端硬件无法运行)