噪波纹理分析(2):分形函数
分形函数
1.1 分形噪波函数
fbm、Multi-fractal、Hetero Terrain、Hybrid Multi-fractal和Ridged Multi-fractal是五种基于分形噪声的算法类型,每种通过不同的方式叠加噪声的“八度”(octaves)来生成不同特性的纹理。他们有一些共同的控制参数如下。
- 八度数(Detail):控制噪声的层级细节,增加八度会提升复杂度但降低性能。
- 粗糙度(Roughness):调整噪声的锐利度,值越大峰值越尖锐。
- 维度(Dimensions):1D/2D/3D/4D影响噪声的空间特性,更高维度计算成本更高。
- 间隙度(Lacunarity):控制分形噪声中连续八度之间的频率倍增比例。数值越大,高频细节的尺度差异越明显,生成的结构越粗糙。
- 最大距离(Max_distance):定义距离衰减效应的最大范围,超出此距离后声音或噪声的强度不再衰减(用于空间音频或体积效果)。
1.1.1 Fractal Brownian Motion 噪波函数
-
算法原理:通过线性叠加多个Perlin噪声的八度(octaves),每个八度的频率倍增(如2倍、4倍等),振幅递减(如1/2、1/4等)。最终结果是所有八度的加权和。
-
数学表达:
\[\text{fBM}(x) = \sum_{i=0}^{n} \frac{\text{Noise}(2^i x)}{2^i} \]其中 n是八度数。
-
特性:生成均匀且各向同性的噪声,适合模拟自然现象如云层、平滑地形。
-
应用场景:基础地形、云层纹理或通用随机图案。
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define int2 ivec2
#define int3 ivec3
#define FLT_MAX 1e20
#define FLOORFRAC(x, x_int, x_fract) { float x_floor = floor(x); x_int = int(x_floor); x_fract = x - x_floor; }
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
#define mix(a, b, c) \
{ \
a -= c; \
a ^= rot(c, 4); \
c += b; \
b -= a; \
b ^= rot(a, 6); \
a += c; \
c -= b; \
c ^= rot(b, 8); \
b += a; \
a -= c; \
a ^= rot(c, 16); \
c += b; \
b -= a; \
b ^= rot(a, 19); \
a += c; \
c -= b; \
c ^= rot(b, 4); \
b += a; \
}
#define final(a, b, c) \
{ \
c ^= b; \
c -= rot(b, 14); \
a ^= c; \
a -= rot(c, 11); \
b ^= a; \
b -= rot(a, 25); \
c ^= b; \
c -= rot(b, 16); \
a ^= c; \
a -= rot(c, 4); \
b ^= a; \
b -= rot(a, 14); \
c ^= b; \
c -= rot(b, 24); \
}
uint hash_uint2(uint kx, uint ky)
{
uint a, b, c;
a = b = c = 0xdeadbeefu + (2u << 2u) + 13u;
b += ky;
a += kx;
final(a, b, c);
return c;
}
uint hash_int2(int kx, int ky)
{
return hash_uint2(uint(kx), uint(ky));
}
float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
{
float x1 = 1.0f - x;
return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
}
float fade(float t)
{
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}
float negate_if(float value, uint condition)
{
return (condition != 0u) ? -value : value;
}
float noise_grad(uint hash, float x, float y)
{
uint h = hash & 7u;
float u = h < 4u ? x : y;
float v = 2.0f * (h < 4u ? y : x);
return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
float noise_perlin(float2 vec)
{
int X, Y;
float fx, fy;
FLOORFRAC(vec.x, X, fx);
FLOORFRAC(vec.y, Y, fy);
float u = fade(fx);
float v = fade(fy);
float r = bi_mix(noise_grad(hash_int2(X, Y), fx, fy),
noise_grad(hash_int2(X + 1, Y), fx - 1.0f, fy),
noise_grad(hash_int2(X, Y + 1), fx, fy - 1.0f),
noise_grad(hash_int2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f),
u,
v);
return r;
}
float noise_scale2(float result)
{
return 0.6616f * result;
}
float snoise(float2 p)
{
return noise_scale2(noise_perlin(p));
}
float noise_fbm(vec2 co,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
bool normalize)
{
vec2 p = co;
float fscale = 1.0f;
float amp = 1.0f;
float maxamp = 0.0f;
float sum = 0.0f;
for (int i = 0; i <= int(detail); i++) {
float t = snoise(fscale * p);
sum += t * amp;
maxamp += amp;
amp *= roughness;
fscale *= lacunarity;
}
float rmd = detail - floor(detail);
if (rmd != 0.0f) {
float t = snoise(fscale * p);
float sum2 = sum + t * amp;
if(normalize)
{
float a=0.5f * sum / maxamp + 0.5f;
float b=0.5f * sum2 / (maxamp + amp) + 0.5f;
return (1.0-rmd)*a+rmd*b;
}
else {
return (1.0-rmd)*sum+rmd*sum2;
}
}
else {
return normalize ? 0.5f * sum / maxamp + 0.5f : sum;
}
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy;
float col=noise_fbm(uv*10.0,2.0,0.5,2.0,0.0,0.0,true);
// Output to screen
fragColor = vec4(vec3(col),1.0);
}

1.1.2 Multi-fractal 噪波函数
-
算法原理:与fBM不同,Multi-fractal通过乘法叠加噪声八度,而非加法。每个八度的噪声值相乘,导致结果更不均匀,局部可能出现极值。
-
数学表达:
\[\text{Multi-fractal}(x) = \prod_{i=0}^{n} \text{Noise}(2^i x) \] -
特性:产生非均匀分布的噪声,类似真实地形的起伏变化,适合模拟崎岖地貌或复杂表面。
-
应用场景:山地、岩石表面等细节丰富的自然纹理。
float noise_multi_fractal(vec2 co,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
bool normalize)
{
vec2 p = co;
float value = 1.0f;
float pwr = 1.0f;
for (int i = 0; i <= int(detail); i++) {
value *= (pwr * snoise(p) + 1.0f);
pwr *= roughness;
p *= lacunarity;
}
float rmd = detail - floor(detail);
if (rmd != 0.0f) {
value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */
}
return value;
}

1.1.3 Hybrid Multi-fractal 噪波函数
-
算法原理:结合加法和乘法叠加。首个八度使用加法,后续八度通过乘法调整,形成既有平滑基底又有尖锐峰值的混合效果。
-
数学表达:
\[\text{Hybrid}(x) = \text{Noise}(x) + \sum_{i=1}^{n} \text{Noise}(2^i x) \cdot \prod_{j=1}^{i} \text{Noise}(2^j x) \] -
特性:生成多尺度细节,如山脉从平原中隆起的效果,兼具平滑区域和陡峭变化。
-
应用场景:复杂地形(如山脉与平原过渡)。
float noise_hybrid_multi_fractal(vec2 co,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
bool normalize)
{
vec2 p = co;
float pwr = 1.0f;
float value = 0.0f;
float weight = 1.0f;
for (int i = 0; (weight > 0.001f) && (i <= int(detail)); i++) {
if (weight > 1.0f) {
weight = 1.0f;
}
float signal = (snoise(p) + offset) * pwr;
pwr *= roughness;
value += weight * signal;
weight *= gain * signal;
p *= lacunarity;
}
float rmd = detail - floor(detail);
if ((rmd != 0.0f) && (weight > 0.001f)) {
if (weight > 1.0f) {
weight = 1.0f;
}
float signal = (snoise(p) + offset) * pwr;
value += rmd * weight * signal;
}
return value;
}

1.1.4 Ridged Multi-fractal 噪波函数
-
算法原理:对每个八度的噪声取绝对值,再通过反转(如 1−Noise)生成尖锐的“脊状”结构。后续八度叠加时保留这一特征。
-
数学表达:
\[\text{Ridged}(x) = \sum_{i=0}^{n} \frac{| \text{Noise}(2^i x) |}{2^i} \]通常结合反转操作。
-
特性:产生尖锐的峰谷结构,类似峡谷或熔岩地形的裂缝。
-
应用场景:极端地貌(如峡谷、冰川裂隙)。
float noise_ridged_multi_fractal(vec2 co,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
bool normalize)
{
vec2 p = co;
float pwr = roughness;
float signal = offset - abs(snoise(p));
signal *= signal;
float value = signal;
float weight = 1.0f;
for (int i = 1; i <= int(detail); i++) {
p *= lacunarity;
weight = clamp(signal * gain, 0.0f, 1.0f);
signal = offset - abs(snoise(p));
signal *= signal;
signal *= weight;
value += signal * pwr;
pwr *= roughness;
}
return value;
}

1.1.5 Hetero Terrain 噪波函数
- 算法原理:类似Hybrid Multi-fractal,但通过调整八度的权重和偏移量,模拟河流侵蚀或异质地貌。噪声值可能被偏移(如 Noise+offset)以形成通道状结构。
- 特性:生成非均匀侵蚀效果,如河道或风蚀地形,局部细节更复杂。
- 应用场景:河流网络、风蚀岩石等。
float noise_hetero_terrain(vec2 co,
float detail,
float roughness,
float lacunarity,
float offset,
float gain,
bool normalize)
{
vec2 p = co;
float pwr = roughness;
/* first unscaled octave of function; later octaves are scaled */
float value = offset + snoise(p);
p *= lacunarity;
for (int i = 1; i <= int(detail); i++) {
float increment = (snoise(p) + offset) * pwr * value;
value += increment;
pwr *= roughness;
p *= lacunarity;
}
float rmd = detail - floor(detail);
if (rmd != 0.0f) {
float increment = (snoise(p) + offset) * pwr * value;
value += rmd * increment;
}
return value;
}

1.2 分形Voronoi函数
1.2.1 F1模式
VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float2 coord)
{
float amplitude = 1.0f;
float max_amplitude = 0.0f;
float scale = 1.0f;
VoronoiOutput Output;
Output.Distance = 0.0f;
Output.Color = float3(0.0f, 0.0f, 0.0f);
Output.Position = float4(0.0f, 0.0f, 0.0f, 0.0f);
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (float i = 0.0; i <= ceil(params.detail); ++i) {
VoronoiOutput octave;
octave = voronoi_f1(params, coord * scale);
if (zero_input) {
max_amplitude = 1.0f;
Output = octave;
break;
}
else if (i <= params.detail) {
max_amplitude += amplitude;
Output.Distance += octave.Distance * amplitude;
Output.Color += octave.Color * amplitude;
Output.Position = mix(Output.Position, octave.Position / scale, amplitude);
scale *= params.lacunarity;
amplitude *= params.roughness;
}
else {
float remainder = params.detail - floor(params.detail);
if (remainder != 0.0f) {
max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder);
Output.Distance = mix(
Output.Distance, Output.Distance + octave.Distance * amplitude, remainder);
Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder);
Output.Position = mix(
Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder);
}
}
}
if (params.normalize) {
Output.Distance /= max_amplitude * params.max_distance;
Output.Color /= max_amplitude;
}
Output.Position = Output.Position/params.scale;
return Output;
}

1.2.2 Distance to Edge模式
float fractal_voronoi_distance_to_edge(VoronoiParams params, vec2 coord)
{
float amplitude = 1.0f;
float max_amplitude = params.max_distance;
float scale = 1.0f;
float distance = 8.0f;
bool zero_input = params.detail == 0.0f || params.roughness == 0.0f;
for (float i = 0.0; i <= ceil(params.detail); ++i) {
float octave_distance = voronoi_distance_to_edge(params, coord * scale);
if (zero_input) {
distance = octave_distance;
break;
}
else if (i <= params.detail) {
max_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
distance = mix(distance, min(distance, octave_distance / scale), amplitude);
scale *= params.lacunarity;
amplitude *= params.roughness;
}
else {
float remainder = params.detail - floor(params.detail);
if (remainder != 0.0f) {
float lerp_amplitude = mix(max_amplitude, params.max_distance / scale, amplitude);
max_amplitude = mix(max_amplitude, lerp_amplitude, remainder);
float lerp_distance = mix(distance, min(distance, octave_distance / scale), amplitude);
distance = mix(distance, min(distance, lerp_distance), remainder);
}
}
}
if (params.normalize) {
distance /= max_amplitude;
}
return distance;
}


浙公网安备 33010602011771号