WaveFunctionCollapse核心原理解密:从量子叠加到像素级模式匹配
WaveFunctionCollapse(WFC)是一种革命性的算法,它能从单个示例图像生成局部相似的位图和瓦片地图。其核心思想借鉴了量子力学中的叠加态和坍缩概念,通过概率约束和局部模式匹配,创造出看似复杂却内在一致的生成结果。本文将深入解析WFC的工作原理,从量子力学启发的概念模型到实际代码实现,带你揭开这一神奇算法的面纱。
算法概述:从量子力学到像素生成
WFC算法的核心灵感来源于量子力学中的波函数叠加(Wave Function Superposition)和坍缩(Collapse)概念。在量子力学中,粒子可以同时处于多个状态的叠加,直到被观测时才坍缩为一个确定状态。WFC算法巧妙地将这一思想应用于图像生成:
- 叠加态:算法开始时,每个像素或瓦片处于多种可能状态的叠加
- 观测:选择不确定性最低(熵最小)的位置进行状态坍缩
- 传播:将坍缩结果的约束传播到相邻区域,逐步减少整体不确定性
如上图所示,算法从完全不确定的灰色状态开始,通过不断选择熵最小的位置进行坍缩,并传播约束,最终生成完整图像。这种生成方式使得结果既具有局部多样性,又保持整体一致性。
WFC算法主要包含两种模型:重叠模型(Overlapping Model)和简单瓦片模型(Simple Tiled Model)。重叠模型直接从输入图像学习N×N像素块的模式,适用于生成类似纹理的位图;简单瓦片模型则基于预定义的瓦片集和邻接规则,适用于生成游戏地图等结构化内容。
核心原理:熵减驱动的生成过程
1. 波函数初始化
WFC算法首先构建一个"波函数"数组(wave),其中每个元素代表一个位置可能处于的状态集合。在Model.cs中,我们可以看到波函数被定义为一个二维布尔数组:
protected bool[][] wave; // 波函数数组,记录每个位置的可能状态
初始化时,所有位置都处于完全叠加态,即可能包含所有可能的瓦片或像素模式。算法同时计算每个状态的权重(weights),用于后续的概率选择:
for (int t = 0; t < T; t++)
{
weightLogWeights[t] = weights[t] * Math.Log(weights[t]);
sumOfWeights += weights[t];
sumOfWeightLogWeights += weightLogWeights[t];
}
2. 熵:不确定性的度量
WFC算法的关键创新在于使用熵(Entropy)作为选择下一个坍缩位置的依据。熵是信息论中的概念,表示系统的不确定性。在WFC中,熵的计算公式如下:
entropies[i] = Math.Log(sum) - sumsOfWeightLogWeights[i] / sum;
其中sum是该位置所有可能状态的权重之和。熵越低,表示该位置的不确定性越小,算法优先选择熵最小的位置进行坍缩。这种"最小熵启发式"(images/lowest-entropy-heuristic.gif)被证明能产生更自然、更符合人类直觉的生成结果。
3. 观测:状态坍缩
观测步骤是WFC算法的核心,对应量子力学中的"波函数坍缩"。算法根据当前的权重分布随机选择一个状态,将该位置的波函数坍缩为单一确定状态:
void Observe(int node, Random random)
{
bool[] w = wave[node];
for (int t = 0; t < T; t++) distribution[t] = w[t] ? weights[t] : 0.0;
int r = distribution.Random(random.NextDouble()); // 根据权重概率选择状态
for (int t = 0; t < T; t++) if (w[t] != (t == r)) Ban(node, t); // 禁用非选中状态
}
Ban方法用于从波函数中移除不可能的状态,这是通过将对应位置的布尔值设为false实现的。每次状态坍缩后,算法需要将这一变化传播到相邻位置。
4. 传播:约束的扩散
坍缩后的状态会对相邻位置产生约束,这一过程称为"传播"(Propagation)。WFC使用类似约束满足问题(CSP)中的弧一致性检查,确保所有相邻位置的状态都与当前状态兼容。
在Model.cs的传播实现中,算法使用一个栈(stack)记录需要更新的状态,并通过传播器(propagator)检查邻接兼容性:
bool Propagate()
{
while (stacksize > 0)
{
(int i1, int t1) = stack[stacksize - 1];
stacksize--;
// 检查四个方向的相邻位置
for (int d = 0; d < 4; d++)
{
int x2 = x1 + dx[d];
int y2 = y1 + dy[d];
// 检查边界条件和周期性...
int i2 = x2 + y2 * MX;
int[] p = propagator[d][t1]; // 获取方向d上与t1兼容的状态
for (int l = 0; l < p.Length; l++)
{
int t2 = p[l];
int[] comp = compatible[i2][t2];
comp[d]--;
if (comp[d] == 0) Ban(i2, t2); // 兼容性为0时禁用该状态
}
}
}
return sumsOfOnes[0] > 0;
}
传播器(propagator)是WFC算法的关键数据结构,它记录了不同状态在各个方向上的兼容性。在简单瓦片模型中,传播器基于预定义的邻接规则构建;在重叠模型中,则从输入图像自动学习。
5. 迭代直至完全坍缩
算法不断重复"选择-坍缩-传播"的循环,直到所有位置都坍缩为确定状态,或检测到矛盾(某个位置没有可能的状态)。这一过程在Model.cs的Run方法中实现:
public bool Run(int seed, int limit)
{
if (wave == null) Init();
Clear();
Random random = new(seed);
for (int l = 0; l < limit || limit < 0; l++)
{
int node = NextUnobservedNode(random); // 选择下一个要观测的节点
if (node >= 0)
{
Observe(node, random); // 坍缩状态
bool success = Propagate(); // 传播约束
if (!success) return false; // 检测到矛盾
}
else
{
// 所有节点都已观测,生成完成
for (int i = 0; i < wave.Length; i++)
for (int t = 0; t < T; t++)
if (wave[i][t]) { observed[i] = t; break; }
return true;
}
}
return true;
}
简单瓦片模型:从规则到地图
简单瓦片模型(Simple Tiled Model)是WFC算法在游戏地图生成等场景的典型应用。与直接从图像学习模式的重叠模型不同,简单瓦片模型基于预定义的瓦片集和邻接规则,具有更强的可控性。
瓦片集与对称性系统
简单瓦片模型使用XML文件定义瓦片集及其属性,如tilesets/Rooms.xml定义了房间生成的瓦片规则。每个瓦片可以指定对称性类型,以减少邻接规则的定义数量。WFC支持多种对称性类型,如旋转对称、反射对称等:
在SimpleTiledModel.cs中,我们可以看到瓦片对称性的实现。例如,对于'F'类型(完全对称),算法会自动生成所有8种可能的旋转和反射变体:
else if (sym == 'F') // 完全对称:8种变换(4种旋转×2种反射)
{
cardinality = 8;
a = i => i < 4 ? (i + 1) % 4 : 4 + (i - 1) % 4;
b = i => i < 4 ? i + 4 : i - 4;
}
邻接规则与传播器构建
简单瓦片模型的核心是定义瓦片之间的邻接规则。例如,在tilesets/Circuit.xml中,我们可以定义电路瓦片的连接规则:
<neighbors>
<neighbor left="Corner" right="Connection"/>
<neighbor left="Connection" right="Corner"/>
<!-- 更多邻接规则... -->
</neighbors>
算法解析这些规则,并构建传播器(propagator)数据结构,记录每个瓦片在四个方向上兼容的其他瓦片:
propagator = new int[4][][]; // 传播器:[方向][瓦片][兼容的瓦片列表]
for (int d = 0; d < 4; d++)
{
propagator[d] = new int[T][];
// 初始化传播器...
}
生成示例:从瓦片到地图
简单瓦片模型已被成功应用于多种场景,如城堡地图、电路布局、房间布局等:
上图展示了使用tilesets/Castle.xml瓦片集生成的城堡地图。算法从少量初始约束开始,逐步扩展为完整的城堡布局,包括道路、河流、塔楼等元素的合理分布。
类似地,tilesets/Circuit.xml瓦片集可用于生成逻辑电路布局:
这些示例展示了WFC算法如何通过局部约束传播,产生全局一致的复杂结构。
高级应用:高维生成与约束合成
WFC算法的思想可以扩展到三维空间,生成体素模型。通过将二维的波函数扩展到三维,算法可以生成城堡、地形等复杂的三维结构:
高维WFC的实现与二维版本类似,但需要考虑更多的邻接方向和更高的计算复杂度。在OverlappingModel.cs中,我们可以找到支持高维生成的代码框架。
此外,WFC支持与其他生成算法结合,形成混合生成 pipeline。例如,可以先用WFC生成地图布局,再用纹理合成算法添加细节;或者先用其他算法生成初始约束,再用WFC完成填充:
上图展示了WFC如何基于用户绘制的简单草图,自动补全生成完整的地图。这种交互式生成方式极大扩展了WFC的应用场景。
总结与展望
WaveFunctionCollapse算法通过巧妙借鉴量子力学中的概念,创造了一种全新的生成范式。其核心在于:
- 熵驱动的决策:总是选择不确定性最低的位置进行坍缩,确保生成过程的稳定性
- 局部约束传播:通过传播器高效传播状态约束,保证全局一致性
- 多模型支持:重叠模型和简单瓦片模型分别适用于纹理生成和结构化内容生成
WFC算法已被广泛应用于游戏开发、艺术创作、建筑设计等领域,如独立游戏《Bad North》和《Townscaper》都采用了WFC算法生成游戏关卡。随着研究的深入,WFC的变体和扩展不断涌现,如结合机器学习的WFC、支持全局约束的WFC等。
通过Model.cs、SimpleTiledModel.cs等核心文件,我们可以看到WFC算法的简洁实现。其核心代码不到1000行,却能产生令人惊叹的生成效果,展现了算法设计的精妙之处。
无论是作为开发者还是创作者,理解WFC的原理都将为你打开一扇通往生成式设计的新大门。不妨尝试修改tilesets/Rooms.xml中的瓦片规则,或调整Model.cs中的熵计算方式,探索属于你的独特生成效果!
想要深入了解更多细节,可以查阅项目中的README.md,其中包含完整的构建指南和更多高级应用示例。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考











