首页 > 其他分享 >Unity Hex Map技术测试

Unity Hex Map技术测试

时间:2022-12-13 14:34:21浏览次数:48  
标签:node Map Vector3 Hex Bounds bounds Unity new size


HexMap常用于战棋的地形,最近有这方面的需求,做一个简单的测试,从画一个正六边形开始。

0x00. 正六边形

Unity Hex Map技术测试_hexmap

  • 如上图所示,两个圆,可以很规范的画一个六变形。
  • 外圆半径定为:​​public const float OuterRadius = 10f;​
  • 内圆半径定为:​​public const float InnerRadius = OuterRadius * 0.866025404f;​
  • 定义模型:
Vector3[] vers = new Vector3[]{
new Vector3(0f,0f,0f),
new Vector3(0f, 0f, OuterRadius),
new Vector3(InnerRadius, 0f, 0.5f * OuterRadius),
new Vector3(InnerRadius, 0f, -0.5f * OuterRadius),
new Vector3(0f, 0f, -OuterRadius),
new Vector3(-InnerRadius, 0f, -0.5f * OuterRadius),
new Vector3(-InnerRadius, 0f, 0.5f * OuterRadius)
};
int[] triangles = new int[] { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 6, 0, 6, 1 };

0x01. unity模型

  • Hex模型
  • Unity Hex Map技术测试_数据_02

  • Hex Grid
for (int i = 0; i < _column; i++)
{
for (int j = 0; j < _row; j++)
{
HexMesh clone = new GameObject().AddComponent<HexMesh>();
float offet = j % 2 == 0 ? 0 : HexMesh.InnerRadius;
clone.transform.localPosition = new Vector3(i * HexMesh.InnerRadius * 2 + offet, 0, j * HexMesh.OuterRadius * 1.5f);
}
}

Unity Hex Map技术测试_List_03

其实上面用来满足以纯六变形做地形的需求,是没问题的, 但是我希望我们的地形是一个现成风格更加可控可变的,HexMap应该是附加到地形之上,所以需要重新转换一下思路。

0x02. 八叉树管理场景的三角面

创建三角形的数据结构,保存三角行的顶点数据,以及包含三角形的Bounds

public struct TriangleVertices
{
public Vector3 Vertex0;
public Vector3 Vertex1;
public Vector3 Vertex2;

public Bounds Bounds;

public TriangleVertices(Vector3 vertex0, Vector3 vertex1, Vector3 vertex2)
{
Vertex0 = vertex0;
Vertex1 = vertex1;
Vertex2 = vertex2;

float maxX = Mathf.Max(vertex0.x, vertex1.x, vertex2.x);
float maxY = Mathf.Max(vertex0.y, vertex1.y, vertex2.y);
float maxZ = Mathf.Max(vertex0.z, vertex1.z, vertex2.z);

float minX = Mathf.Min(vertex0.x, vertex1.x, vertex2.x);
float minY = Mathf.Min(vertex0.y, vertex1.y, vertex2.y);
float minZ = Mathf.Min(vertex0.z, vertex1.z, vertex2.z);

Vector3 si = new Vector3(maxX - minX, maxY - minY, maxZ - minZ);
if (si.x <= 0)
si.x = 0.1f;
if (si.y <= 0)
si.y = 0.1f;
if (si.z <= 0)
si.z = 0.1f;
Vector3 ct = new Vector3(minX, minY, minZ) + si / 2;
Bounds = new Bounds(ct, si);
}

}

创建ScriptableObject保存数据,并在细化八叉树到最小的节点,如果有三角形被多个Bounds包含,则同时存同一个三角形

public struct OctreeNode
{
public Bounds Bounds;
public int CurrentDepth;
public List<TriangleVertices> Triangles;
}

[System.Serializable]
public class Octree : ScriptableObject
{
public OctreeNode Root;
public int MaxDepth;
public int TriangleCount;
public void Setup(Bounds maxBounds, int maxDepth, List<TriangleVertices> triangles)
{
MaxDepth = maxDepth;
Root = new OctreeNode();
Root.Bounds = maxBounds;

SplitBounds(ref Root, triangles, 0);
}

private void SplitBounds(ref OctreeNode node, List<TriangleVertices> triangles, int deep)
{
node.CurrentDepth = deep;
if (deep < MaxDepth)
{
node.Triangles = new List<TriangleVertices>();
node.ChildNodes = new OctreeNode[8];

Bounds bounds = node.Bounds;
Vector3 half2Vector = bounds.size / 4;
// 八块空间的位置
node.ChildNodes[0].Bounds.center = bounds.center - half2Vector;
node.ChildNodes[0].Bounds.size = bounds.size / 2;
node.ChildNodes[1].Bounds.center = node.ChildNodes[0].Bounds.center + new Vector3(bounds.size.x / 2, 0, 0);
node.ChildNodes[1].Bounds.size = bounds.size / 2;
node.ChildNodes[2].Bounds.center = node.ChildNodes[1].Bounds.center + new Vector3(0, 0, bounds.size.z / 2);
node.ChildNodes[2].Bounds.size = bounds.size / 2;
node.ChildNodes[3].Bounds.center = node.ChildNodes[0].Bounds.center + new Vector3(0, 0, bounds.size.z / 2);
node.ChildNodes[3].Bounds.size = bounds.size / 2;
node.ChildNodes[4].Bounds.center = node.ChildNodes[0].Bounds.center + new Vector3(0, bounds.size.y / 2, 0);
node.ChildNodes[4].Bounds.size = bounds.size / 2;
node.ChildNodes[5].Bounds.center = node.ChildNodes[1].Bounds.center + new Vector3(0, bounds.size.y / 2, 0);
node.ChildNodes[5].Bounds.size = bounds.size / 2;
node.ChildNodes[6].Bounds.center = node.ChildNodes[2].Bounds.center + new Vector3(0, bounds.size.y / 2, 0);
node.ChildNodes[6].Bounds.size = bounds.size / 2;
node.ChildNodes[7].Bounds.center = node.ChildNodes[3].Bounds.center + new Vector3(0, bounds.size.y / 2, 0);
node.ChildNodes[7].Bounds.size = bounds.size / 2;

//整理在自己的碰撞盒子里面
for (int i = 0; i < triangles.Count; i++)
{
TriangleVertices triangle = triangles[i];
if (!node.Bounds.Intersects(triangle.Bounds))
{
triangles.RemoveAt(i);
i--;
}
}
// 3、遍历8个区域 递归调用
List<TriangleVertices> childtriangles = new List<TriangleVertices>();
for (int i = 0; i < node.ChildNodes.Length; i++)
{
childtriangles.Clear();
node.ChildNodes[i].Triangles = new List<TriangleVertices>();
for (int j = 0; j < triangles.Count; j++)
{
TriangleVertices triangle = triangles[j];
if (node.ChildNodes[i].Bounds.Intersects(triangle.Bounds))
{
childtriangles.Add(triangle);
}
}

if (childtriangles.Count > 0)
{
SplitBounds(ref node.ChildNodes[i], childtriangles, node.CurrentDepth + 1);
}
}


}
else
{
node.Triangles.AddRange(triangles);
TriangleCount += triangles.Count;
}
}
}

Unity Hex Map技术测试_unity3d_04

0x03. 创建独立的检索Bounds

利用独立的Bounds,去检索Octree里的bounds,并获取对应的三角形的数据,动态生成模型,然后跟其顶点在Bounds的范围,来修改模型的UV数据,保证其值在0-1之间。

public void Handle(Bounds bounds, IProjectorHandle handle, string meshName = null)
{
List<TriangleVertices> triangles = ListPool<TriangleVertices>.Get();
//索取所有的三角形
GetTriangles(bounds, this, triangles);
//转换成模式
Mesh mesh = new Mesh();
if (!string.IsNullOrEmpty(meshName))
mesh.name = $"{meshName}";
List<Vector3> vertices = ListPool<Vector3>.Get();
List<Vector2> uvs = ListPool<Vector2>.Get();
List<int> indexs = ListPool<int>.Get();
Vector2 uv = new Vector2();
int index = 0;
for (int i = 0; i < triangles.Count; i++)
{
TriangleVertices triangle = triangles[i];
//vertices
vertices.Add(triangle.Vertex0);
vertices.Add(triangle.Vertex1);
vertices.Add(triangle.Vertex2);
//uvs
uv.x = (triangle.Vertex0.x - bounds.min.x) / bounds.size.x;
uv.y = (triangle.Vertex0.z - bounds.min.z) / bounds.size.z;
uvs.Add(uv);
uv.x = (triangle.Vertex1.x - bounds.min.x) / bounds.size.x;
uv.y = (triangle.Vertex1.z - bounds.min.z) / bounds.size.z;
uvs.Add(uv);
uv.x = (triangle.Vertex2.x - bounds.min.x) / bounds.size.x;
uv.y = (triangle.Vertex2.z - bounds.min.z) / bounds.size.z;
uvs.Add(uv);
//index
indexs.Add(index);
indexs.Add(index + 1);
indexs.Add(index + 2);
index += 3;
}
//设置模型信息
mesh.SetVertices(vertices);
mesh.SetUVs(0, uvs);
mesh.SetTriangles(indexs, 0);
ListPool<TriangleVertices>.Release(triangles);
ListPool<Vector3>.Release(vertices);
ListPool<Vector2>.Release(uvs);
ListPool<int>.Release(indexs);
//回调
handle.ProjectorHandle(mesh);
}

0x04. 准备一个包含六变形的图片的材质

取消掉​​Generate Mip Maps​​​,​​Wrap Mode​​​改为​​Clamp​

Unity Hex Map技术测试_List_05

0x05. 生成多个Hex

不断移动独立Bounds,即可生成多个Hex组成HexMap

/// <summary>
/// 创建模型的GameObject
/// </summary>
private void MakeMeshGameObject()
{
//projetor的大小
float size = _octreeConfig.ProjectorSize;
float halfSize = size * 0.5f;
float offsetSize = _octreeConfig.ProjectorSize * _octreeConfig.ProjectorInnerCircleScale;
float offsetHalfSize = offsetSize * 0.5f;

//初始化 projector的数据
Vector3 startPos = new Vector3(_octreeConfig.MaxBounds.min.x + halfSize, _octreeConfig.MaxBounds.center.y, _octreeConfig.MaxBounds.min.z + halfSize);
Vector3 projectorSize = new Vector3(size, _octreeConfig.MaxBounds.size.y, size);
//初始化 projectorBounds
for (int i = 0; i < _octreeConfig.Rows; i++)
{
for (int j = 0; j < _octreeConfig.Columns; j++)
{
float offset = i % 2 == 0 ? 0 : offsetHalfSize;
Vector3 center = startPos + new Vector3(j * offsetSize + offset, 0, i * halfSize * 1.5f);
Bounds projectorBounds = new Bounds(center, projectorSize);
_octreeDebug.ProjectorBounds = projectorBounds;
_octree.Root.Handle(projectorBounds, this, $"{i}_{j}");
// new Task(
// () =>
// {
// _octree.Root.Handle(projectorBounds, this);
// }
// ).Start();
}
}
}

Unity Hex Map技术测试_unity3d_06

0x05. 导出FBX

使用unity官方插件​​FBX Exporter​​导出模型文件,可作为静态模型

0x06. TODO






标签:node,Map,Vector3,Hex,Bounds,bounds,Unity,new,size
From: https://blog.51cto.com/u_15911199/5934051

相关文章

  • 【Unity】MeshEditor.Effects.Vortex 网格编辑器特效篇之涡流特效:开启你的不会Shader
    更新日期:2020年4月22日。Github源码:​​​[点我获取源码]​​索引​​前言​​​​扩展​​​​Vortex​​​​使用​​​​参数​​​​原理及算法​​​​图像展示​​前......
  • Unity角色残影特效
    残影特效在网上有很多例子,比如​​这个​​,我参考着自己整合了一下,算是整合了一个比较完整且特别简单易用的出来,只需要一个脚本挂上去无需任何设定就能用。这里只针对Skinne......
  • 【Unity】 HTFramework框架(三十四)框架实用特性
    更新日期:2020年11月6日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​框架实用特性​​​​LnkTools特性(快捷工具)​​​​CSDNBlogURL......
  • Unity 资源管理插件
    之所以写这个插件呢,就是为了方便整理项目中的资源文件,我记得之前好像也用了这么一个插件,但是也没去找,还是自己动手写一个吧,需要什么功能就看自己的需求。在项目的过程中呢,已......
  • 【Unity】 HTFramework框架(三十三)XLua热更新
    更新日期:2020年3月20日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​XLua热更新简介​​​​使用XLua热更新​​​​创建XLua开发环境......
  • 【Unity】 HTFramework框架(三十二)授权验证
    更新日期:2020年3月2日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​授权验证简介​​​​使用授权验证​​​​取消永久授权​​​​......
  • Unity插件 - MeshEditor(八)模型镜像特效
    将静态模型(带MeshFilter)按指定轴向、指定距离克隆一个镜像物体出来,思路很简单,将模型的顶点坐标按指定轴取反,并累加上设定的距离值,然后就完毕了!不过,因为镜像体的顶点镜像于之......
  • 【Unity】 HTFramework框架(三十一)全局设置
    更新日期:2020年3月2日。Github源码:​​​[点我获取源码]​​​Gitee源码:​​[点我获取源码]​​索引​​全局设置简介​​​​使用全局设置​​​​打开全局设置面板​​......
  • unity使用ugui自制调色面板
    突然想实现一个调色面板,然后开工...首先找找有没有什么接口可调,木有找到,找到一些调用win32实现的本地颜色面板的调用,感觉不科学,反正多平台肯定是搞不定的。既然没找到,还是老......
  • 017.开发请假申请Mapper层
    1.创建请假单实体(com.imooc.oa.entity)LeaveForm.javapackagecom.imooc.oa.entity;importjava.util.Date;publicclassLeaveForm{privateLongformId;......