Skip to content

Commit 2c87723

Browse files
committed
Fixes to hex mesh gen
1 parent 96e42c2 commit 2c87723

File tree

3 files changed

+301
-148
lines changed

3 files changed

+301
-148
lines changed

Runtime/Utility/HexMeshUtility.cs

Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace Gameframe.Procgen
6+
{
7+
public enum HexDirection
8+
{
9+
NE = 0,
10+
E = 1,
11+
SE = 2,
12+
SW = 3,
13+
W = 4,
14+
NW = 5
15+
}
16+
17+
public class HexMeshData
18+
{
19+
public float outerRadius;
20+
public float innerRadius;
21+
public List<Vector3> vertices;
22+
public List<int> triangles;
23+
public List<Color> colors;
24+
public Vector3[] corners;
25+
26+
private float border = 0.25f;
27+
28+
public float Border => border;
29+
public float Solid => 1 - border;
30+
31+
public HexMeshData()
32+
{
33+
}
34+
35+
public HexMeshData(float radius, float border = 0.2f)
36+
{
37+
this.border = Mathf.Clamp01(border);
38+
39+
outerRadius = radius;
40+
innerRadius = outerRadius * Mathf.Sqrt(3f) * 0.5f;
41+
vertices = new List<Vector3>();
42+
triangles = new List<int>();
43+
colors = new List<Color>();
44+
corners = new [] {
45+
new Vector3(0f, 0f, outerRadius),
46+
new Vector3(innerRadius, 0f, 0.5f * outerRadius),
47+
new Vector3(innerRadius, 0f, -0.5f * outerRadius),
48+
new Vector3(0f, 0f, -outerRadius),
49+
new Vector3(-innerRadius, 0f, -0.5f * outerRadius),
50+
new Vector3(-innerRadius, 0f, 0.5f * outerRadius),
51+
new Vector3(0f, 0f, outerRadius)
52+
};
53+
}
54+
55+
public Vector3 GetBridge(HexDirection direction)
56+
{
57+
return (corners[(int)direction] + corners[(int)direction + 1]) * 0.5f * border;
58+
}
59+
60+
public Vector3 GetFirstCorner(HexDirection direction)
61+
{
62+
return corners[(int) direction];
63+
}
64+
65+
public Vector3 GetSecondCorner(HexDirection direction)
66+
{
67+
return corners[(int) direction + 1];
68+
}
69+
70+
public Vector3 GetFirstSolidCorner(HexDirection direction)
71+
{
72+
return corners[(int) direction] * Solid;
73+
}
74+
75+
public Vector3 GetSecondSolidCorner(HexDirection direction)
76+
{
77+
return corners[(int) direction + 1] * Solid;
78+
}
79+
80+
public Mesh CreateMesh()
81+
{
82+
Mesh mesh = new Mesh();
83+
mesh.vertices = vertices.ToArray();
84+
mesh.triangles = triangles.ToArray();
85+
mesh.colors = colors.ToArray();
86+
mesh.RecalculateNormals();
87+
return mesh;
88+
}
89+
90+
}
91+
92+
public static class HexMeshUtility
93+
{
94+
public static HexDirection Previous(this HexDirection direction)
95+
{
96+
return direction == HexDirection.NE ? HexDirection.NW : (direction - 1);
97+
}
98+
99+
public static HexDirection Next(this HexDirection direction)
100+
{
101+
return direction == HexDirection.NW ? HexDirection.NE : (direction + 1);
102+
}
103+
104+
public static int GetNeighbor(int index, HexDirection hexDirection, int mapWidth, int mapHeight)
105+
{
106+
int y = index / mapWidth;
107+
int x = index - (y * mapWidth);
108+
109+
switch (hexDirection)
110+
{
111+
case HexDirection.NE:
112+
//Only odd numbered rows shift a column
113+
if ((y & 1) == 1)
114+
{
115+
x++;
116+
}
117+
y++;
118+
break;
119+
case HexDirection.E:
120+
x++;
121+
break;
122+
case HexDirection.SE:
123+
//Only odd numbered rows shift a column
124+
if ((y & 1) == 1)
125+
{
126+
x++;
127+
}
128+
y--;
129+
break;
130+
case HexDirection.SW:
131+
//Only even numbered rows shift a column
132+
if ((y & 1) == 0)
133+
{
134+
x--;
135+
}
136+
y--;
137+
break;
138+
case HexDirection.W:
139+
x--;
140+
break;
141+
case HexDirection.NW:
142+
//Only even numbered rows shift a column
143+
if ((y & 1) == 0)
144+
{
145+
x--;
146+
}
147+
y++;
148+
break;
149+
default:
150+
throw new ArgumentOutOfRangeException(nameof(hexDirection), hexDirection, null);
151+
}
152+
153+
if (x < 0 || x >= mapWidth)
154+
{
155+
return -1;
156+
}
157+
158+
if (y < 0 || y >= mapHeight)
159+
{
160+
return -1;
161+
}
162+
163+
return y * mapWidth + x;
164+
}
165+
166+
public static Mesh GenerateHexagonMesh(float radius, int startX, int startY, int chunkWidth, int chunkHeight, int mapWidth, int mapHeight, float[] heightMap, Func<float,Color> colorFunction, Func<float,float> elevationFunction)
167+
{
168+
var meshData = new HexMeshData(radius, 0.3f);
169+
170+
for (int dy = 0; dy < chunkHeight && (startY + dy) < mapHeight; dy++)
171+
{
172+
for (int dx = 0; dx < chunkWidth && (startX + dx) < mapWidth; dx++)
173+
{
174+
int x = startX + dx;
175+
int y = startY + dy;
176+
177+
var index = (y * mapWidth) + x;
178+
179+
var xOffset = x + y * 0.5f - (int)(y / 2);
180+
var center = new Vector3(xOffset*meshData.innerRadius*2,0,y*meshData.outerRadius*1.5f);
181+
182+
for (var direction = 0; direction < 6; direction++)
183+
{
184+
var elevation = elevationFunction?.Invoke(heightMap[index]) ?? 0;
185+
var previousNeighborElevation = elevation;
186+
var neighborElevation = elevation;
187+
var nextNeighborElevation = elevation;
188+
189+
var neighbor = GetNeighbor(index, (HexDirection)direction, mapWidth, mapHeight);
190+
if (neighbor != -1)
191+
{
192+
neighborElevation = Mathf.Min(elevation,elevationFunction?.Invoke(heightMap[neighbor]) ?? 0);
193+
}
194+
195+
neighbor = GetNeighbor(index, ((HexDirection)direction).Previous(), mapWidth, mapHeight);
196+
if (neighbor != -1)
197+
{
198+
previousNeighborElevation = Mathf.Min(elevation,elevationFunction?.Invoke(heightMap[neighbor]) ?? 0);
199+
}
200+
201+
neighbor = GetNeighbor(index, ((HexDirection)direction).Next(), mapWidth, mapHeight);
202+
if (neighbor != -1)
203+
{
204+
nextNeighborElevation = Mathf.Min(elevation,elevationFunction?.Invoke(heightMap[neighbor]) ?? 0);
205+
}
206+
207+
center.y = elevation;
208+
209+
var color = colorFunction?.Invoke(heightMap[index]) ?? Color.white;
210+
AddTriangle(meshData, center, neighborElevation, previousNeighborElevation, nextNeighborElevation, (HexDirection)direction, color);
211+
}
212+
213+
}
214+
}
215+
216+
return meshData.CreateMesh();
217+
}
218+
219+
private static void AddTriangle(HexMeshData meshData, Vector3 center, float neighborElevation, float previousElevation, float nextElevation, HexDirection direction, Color color)
220+
{
221+
var v1 = center;
222+
var v2 = center + meshData.GetFirstSolidCorner(direction);
223+
var v3 = center + meshData.GetSecondSolidCorner(direction);
224+
225+
//Add inner solid triangle
226+
AddTriangle(meshData, v1, v2, v3, color);
227+
228+
//Add Quad To Fill Border Gap
229+
var v4 = v2 + meshData.GetBridge(direction);
230+
v4.y = neighborElevation;
231+
var v5 = v3 + meshData.GetBridge(direction);
232+
v5.y = neighborElevation;
233+
AddQuad(meshData, v2, v3, v4, v5, color);
234+
235+
//Add Triangles to fill gap on sides of quad
236+
var v6 = center + meshData.GetFirstCorner(direction);
237+
v6.y = Mathf.Min(neighborElevation,previousElevation);
238+
AddTriangle(meshData,v2, v6, v4, color);
239+
240+
var v7 = center + meshData.GetSecondCorner(direction);
241+
v7.y = Mathf.Min(neighborElevation,nextElevation);
242+
AddTriangle(meshData,v3, v5, v7, color);
243+
}
244+
245+
private static void AddTriangle(HexMeshData meshData, Vector3 v1, Vector3 v2, Vector3 v3, Color color)
246+
{
247+
var vertexIndex = meshData.vertices.Count;
248+
249+
meshData.vertices.Add(v1);
250+
meshData.vertices.Add(v2);
251+
meshData.vertices.Add(v3);
252+
253+
meshData.colors.Add(color);
254+
meshData.colors.Add(color);
255+
meshData.colors.Add(color);
256+
257+
meshData.triangles.Add(vertexIndex);
258+
meshData.triangles.Add(vertexIndex + 1);
259+
meshData.triangles.Add(vertexIndex + 2);
260+
}
261+
262+
private static void AddQuad(HexMeshData meshData, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, Color color)
263+
{
264+
var vertexIndex = meshData.vertices.Count;
265+
266+
meshData.vertices.Add(v1);
267+
meshData.vertices.Add(v2);
268+
meshData.vertices.Add(v3);
269+
meshData.vertices.Add(v4);
270+
271+
meshData.colors.Add(color);
272+
meshData.colors.Add(color);
273+
meshData.colors.Add(color);
274+
meshData.colors.Add(color);
275+
276+
meshData.triangles.Add(vertexIndex);
277+
meshData.triangles.Add(vertexIndex + 2);
278+
meshData.triangles.Add(vertexIndex + 1);
279+
280+
meshData.triangles.Add(vertexIndex + 1);
281+
meshData.triangles.Add(vertexIndex + 2);
282+
meshData.triangles.Add(vertexIndex + 3);
283+
}
284+
285+
}
286+
}
287+
288+

Runtime/Utility/HexMeshUtility.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)