不规则四边形填充平面 | 您所在的位置:网站首页 › unity平面网格线shader › 不规则四边形填充平面 |
不规则四边形填充平面 - Townscaper 网格生成算法复现
github.com/FutaAlice/OrganicQuadGrid 前言Townscaper,一款关于城镇建造的游戏。 游戏基于一张用不规则凸四边形拼接而成的平面地图,其中每个四边形虽不规则,但又“接近”正方形,适合用于城镇的搭建。 本文将用 Unity 和 C# 实现这个算法,并逐步骤解释。 算法概述算法分为如下三个步骤: 1. 把目标平面进行 Delaunay Triangulation泊松分布+Delaunay 是为了获取尽量规整的三角形, 考虑到拼接无限地图的需求,此处的代码实现我们将用将 “正六边形” 三角形化的方式替代。 2. 随机剔除三角形的边随机剔除三角形的边,使其和邻接三角形形成四边形。(本步骤不能保证所有三角形都被合并为四边形) 3. 将平面内的 “三角形” 和 “四边形” 细分为更小的四边形我们需要仅由具有四个边的面组成的网格。但是我们当前的网格中仍然存在一些三角形。 不过,三角形可以很容易地细分为三个较小的四边形。同样,现有的四边形也可以细分为四个较小的四边形。如下图所示: 通过这样做,我们最终得到一个仅由四边形组成的网格。 这一步被称为 Squaring 或 Relaxation。 目的是为了让网格看起来更加“美观”,评判标准比较主观,有多种实现方式。 我们将采用将不断迭代每个顶点,将其移向相邻顶点中心的方式实现。 代码实现 0. 基础代码新建一个 c# 脚本,派生于 MonoBehaviour,此处我们叫他 Hexagird.cs [ExecuteInEditMode] public class Hexagrid : MonoBehaviour { void Start() ... void Update() ... }点、三角形、四边形 的抽象,便于后续代码实现。 class Point // 点 { public Vector2 mPosition; public bool mSide; // 是否在六边形最外圈 }; class Triangle // 三角形 { public int mA, mB, mC; public bool mValid; // 用于剔除边的标记,剔除后赋值为 false }; class Quad // 四边形 { public int mA, mB, mC, mD; }; class Neighbours // “点” 所邻接的其他点 { public void Add(int i) ... // i 为邻接点索引 public int count { get { return mNeighbour.Count; } } public List mNeighbour; };最后给 Hexagrid 添加一些字段,用于控制生成参数,把脚本挂到场景内的一个空物体上。 [ExecuteInEditMode] public class Hexagrid : MonoBehaviour { [Range(2, 12)] public int mSideSize = 8; [Range(1, 20)] public int mSearchIterationCount = 12; [Range(0, 65535)] public int mSeed = 15911; private int mBaseQuadCount = 0; public bool bTriangulation = true; public bool bRemovingEdges = false; public bool bSubdivideFaces = false; public bool bRelax = false; public bool bReshape = false; public bool bDrawPositions = false; private List mPoints; private List mTriangles; private List mQuads; private Neighbours[] mNeighbours; // 分别对应算法的四个步骤,先留空实现,慢慢补全 void Triangulation() {} void RemovingEdges() {} void SubdivideFaces() {} void Relax() {} void Reshape() {} // 额外的轮廓相形 // 绘图函数,不重要,从github把代码复制过来就行 private void DrawLine(int a, int b) ... void OnDrawGizmos() ... // 当参数改变时,重新初始化 private void OnValidate() { mPoints = new List(); mTriangles = new List(); mQuads = new List(); mNeighbours = new Neighbours[0]; if (bTriangulation) { this.Triangulation(); } if (bTriangulation && bRemovingEdges) { this.RemovingEdges(); } if (bTriangulation && bRemovingEdges && bSubdivideFaces) { this.SubdivideFaces(); } } // 重写 Update(),逐帧 Relax,方便看效果 void Update() { if (bTriangulation && bRemovingEdges && bSubdivideFaces && bRelax) { if (bRelax) { this.Relax(); } if (bRelax && bReshape) { this.Reshape(); } } } } 1. 三角形化准备工作完成了,开始干正事: void Triangulation() { mPoints = new List(); mTriangles = new List(); mQuads = new List(); mNeighbours = new Neighbours[0]; // 将六边形内散点坐标塞进 mPoints float sideLength = 0.5f * Mathf.Tan(Mathf.Deg2Rad * 60); // 0.5f* tanf(60deg) for (int x = 0; x < mSideSize * 2 - 1; ++x) { int height = (x < mSideSize) ? (mSideSize + x) : (mSideSize * 3 - 2 - x); float deltaHeight = mSideSize - height * 0.5f; for (int y = 0; y < height; y++) { bool isSide = x == 0 || x == (mSideSize * 2 - 2) || y == 0 || y == height - 1; mPoints.Add(new Point((x - mSideSize + 1) * sideLength, y + deltaHeight, isSide)); } } // 分别给对称轴左右生成三角形(顶点顺序不同),塞进 mTriangles int offset = 0; for (int x = 0; x < (mSideSize * 2 - 2); x++) { int height = (x < mSideSize) ? (mSideSize + x) : (mSideSize * 3 - 2 - x); if (x < mSideSize - 1) { // left side for (int y = 0; y < height; y++) { mTriangles.Add(new Triangle(offset + y, offset + y + height, offset + y + height + 1)); if (y >= height - 1) { break; } mTriangles.Add(new Triangle(offset + y + height + 1, offset + y + 1, offset + y)); } } else { // right side for (int y = 0; y < height - 1; y++) { mTriangles.Add(new Triangle(offset + y, offset + y + height, offset + y + 1)); if (y >= height - 2) { break; } mTriangles.Add(new Triangle(offset + y + 1, offset + y + height, offset + y + height + 1)); } } offset += height; } }现在我们得到了存储在 mPoints 里的正六边形内顶点坐标, 以及存储在 mTriangles 里的三角形 index buffer. 随机选择三角形,获取一个与其相邻的三角形,剔除一条公用边,更新 mValid 标记。 拼接成的四边形塞进 mQuads |
CopyRight 2018-2019 实验室设备网 版权所有 |