使用类似GeoJson的数据生成物体(建筑等)的功能逻辑
GeoJson作为一种模型传输格式, 用的最多的就是地图里面的各种简单模型了, 比如下图中很贴切的俄罗斯方块楼:
它的格式大概就是下面这样:
{
"type": "FeatureCollection",
"crs": {
"type": "name",
"properties": {
"name": "EPSG:3857"
}
},
"features": [{
"type": "Feature",
"id": 0,
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-2066.3279353108665, -7427.2858673485389],
[-2071.2341353108641, -7436.5054673485392],
[-2090.8278353108617, -7426.2554673485392],
[-2092.9139353108621, -7430.4644673485382],
[-2096.9763353108574, -7438.1128673485382],
[-2089.4294353108708, -7441.1304673485392],
[-2091.4216353108641, -7448.0708673485387],
[-2090.0935353108653, -7448.4624673485378],
[-2086.7887353108672, -7449.4635673485391],
[-2087.0934353108605, -7450.4654673485384],
[-2077.6715353108593, -7453.5912673485382],
[-2071.241835310866, -7455.724267348538],
[-2070.8513353108574, -7455.8531673485377],
[-2070.5388353108574, -7454.7720673485383],
[-2066.2340353108593, -7440.1365673485379],
[-2064.8513353108574, -7440.5699673485396],
[-2064.2340353108593, -7438.5963673485385],
[-2064.3123353108676, -7437.5268673485389],
[-2068.0935353108653, -7436.5689673485394],
[-2064.1636353108624, -7428.1470673485383],
[-2066.3279353108665, -7427.2858673485389]
]
]
},
"properties": {
"FID": 0,
"CZWCODE": "4403050050110200020",
"ADDRESS": "湾厦路2号海鲜交易中心",
"NAME": "海鲜交易中心",
"LAYERS": 2,
"floor": 2,
"height": 6,
"朝向": -61.9803735785,
"面积": 540.39058542500004,
"ID": "4403050050110200020",
"分类": " ",
"usage": "商服"
}
}]
}
一般的多边形, 它是给了一个底面的各个顶点, 然后给了一个高度让你去生成简单模型, 这个顶点列表是有序的, 所以这个可能是个凹多边形. 这就关联到前面写的这篇文章了 : 二维空间内的三角剖分 -- (给出边缘顶点的例子)
通过三角剖分我们就能正确生成底面的所有三角面了, 然后底面加上高度就是顶面的所有三角面了, 然后因为底边和顶边是对齐的, 我们就可以按照顺序每个相对应的边组成一个四边形进行三角形划分. 逻辑实在过于简单, 不解释了.
问题在于三角形面的朝向问题, 这里只计算了三角面, 并没有对朝向进行计算, 如果要进行朝向计算的话就要对每个三角面的朝向是否向外(相对于该多边形来说), 这样逻辑会很复杂, 这里为了简便直接把所有三角形添加一个朝向相反的三角形即可.
代码 :
public static Mesh CreateGeoJsonMesh(List<Vector3> basePoints, float height)
{
Mesh mesh = new Mesh();
mesh.name = "GeoJsonMesh"; List<Vector3> vertices = new List<Vector3>(); // bottom and top triangles
var baseVerts = Triangulation.GenericTriangulate(basePoints);
var topVerts = new List<Vector3>();
for (int i = ; i < baseVerts.Count; i++)
{
var p = baseVerts[i];
p.y += height;
topVerts.Add(p);
}
vertices.AddRange(baseVerts);
vertices.AddRange(topVerts); // vertical triangles
for(int i = ; i < basePoints.Count; i++)
{
bool loop = i + >= basePoints.Count;
var p0 = basePoints[i];
var p1 = basePoints[loop ? : i + ];
var p2 = p1 + Vector3.up * height;
var p3 = p0 + Vector3.up * height; vertices.Add(p0);
vertices.Add(p1);
vertices.Add(p2); vertices.Add(p0);
vertices.Add(p2);
vertices.Add(p3);
} // add inverse triangles for clip
for(int i = , imax = vertices.Count; i < imax; i += )
{
vertices.Add(vertices[i + ]);
vertices.Add(vertices[i + ]);
vertices.Add(vertices[i]);
} // set vertices
mesh.vertices = vertices.ToArray(); // set triangles
int[] triangles = new int[vertices.Count];
for(int i = ; i < vertices.Count; i++)
{
triangles[i] = i;
}
mesh.triangles = triangles; // set uvs
Vector2[] uv = new Vector2[vertices.Count];
for(int i = ; i < vertices.Count; i++)
{
uv[i] = Vector2.zero;
}
mesh.uv = uv; mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.RecalculateTangents();
return mesh;
}
测试代码, 还是那个凹字 :
List<Vector3> points = new List<Vector3>();
points.Add(new Vector3(0.5f, , 0.5f));
points.Add(new Vector3(0.5f, , 1.5f));
points.Add(new Vector3(1.5f, , 1.5f));
points.Add(new Vector3(1.5f, 1f, -1f));
points.Add(new Vector3(-1.5f, 1f, -1f));
points.Add(new Vector3(-1.5f, 1f, 1.5f));
points.Add(new Vector3(-0.5f, 1f, 1.5f));
points.Add(new Vector3(-0.5f, 1f, 0.5f)); var go = GameObject.CreatePrimitive(PrimitiveType.Quad);
var mesh = CreateGeoJsonMesh(points, 5.0f);
go.GetComponent<MeshFilter>().mesh = mesh;
go.GetComponent<MeshCollider>().sharedMesh = mesh;
获得的模型
PS : 按照这样的逻辑做出来的模型, 有 点-面 数量过多的问题 :
一. 因为用了正反两面, 直接就多了一倍的面数和三角形数量.
二. 在三角剖分之后, 每个三角面都使用三个非共享顶点(一般来说在同一个平面上 Normal 相同的所有面都可以使用共享顶点来减少顶点数)
看下图 :
左边是生成出来的正方体, 右边是系统自带的正方体.
它们的差别:
1. 系统自带的正方体每个面用四个顶点表示, 每个面的两个三角形共享顶点, 所以只有 4*6 = 24个顶点, 然后三角形通过Index描述
2. 生成的正方体每个面2个三角形, 顶点不共享, 就是6个顶点每个面, 也就是36顶点12个面的原始图形
3. 生成的正方体因为三角形朝向没有明确所以进行了复制翻转, 多出了一倍的顶点和面, 72顶点24个面.
所以虽然生成过程简单高效, 可是运行时额外增加了系统负荷. 后续还是需要进行改进.
一般情况下给出的顶点列表如果都是按照顺时针或逆时针的顺序给出的话, 还是能很简单做出三角面的方向的, 这就直接减少了一半的点面.
(2019.06.21)
直接修改了一下三角剖分的逻辑, 使用共享点的剖分, 现在可以减少原始剖分带来的顶点数问题了:
public static Mesh CreateGeoJsonMesh(List<Vector3> basePoints, float height)
{
Mesh mesh = new Mesh();
mesh.name = "GeoJsonMesh"; List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>(); // bottom and top triangles
List<Vector3> baseVerts = null;
List<int> baseIndexes = null;
Triangulation.GenericTriangulate(basePoints, out baseVerts, out baseIndexes); vertices.AddRange(baseVerts);
triangles.AddRange(baseIndexes); for(int i = ; i < baseVerts.Count; i++)
{
var p = baseVerts[i];
p.y += height;
vertices.Add(p);
}
for(int i = ; i < baseIndexes.Count; i++)
{
triangles.Add(baseIndexes[i] + baseVerts.Count);
} // vertical triangles
int startIndex = vertices.Count;
for(int i = ; i < basePoints.Count; i++)
{
bool loop = i + >= basePoints.Count;
var p0 = basePoints[i];
var p1 = basePoints[loop ? : i + ];
var p2 = p1 + Vector3.up * height;
var p3 = p0 + Vector3.up * height; vertices.Add(p0);
vertices.Add(p1);
vertices.Add(p2);
vertices.Add(p3); triangles.Add(startIndex);
triangles.Add(startIndex + );
triangles.Add(startIndex + ); triangles.Add(startIndex);
triangles.Add(startIndex + );
triangles.Add(startIndex + ); startIndex += ;
} // add inverse triangles for clip
int baseVertsCount = vertices.Count;
for(int i = , imax = triangles.Count; i < imax; i += )
{
triangles.Add(triangles[i + ] + baseVertsCount);
triangles.Add(triangles[i + ] + baseVertsCount);
triangles.Add(triangles[i] + baseVertsCount);
}
for(int i = , imax = vertices.Count; i < imax; i++)
{
vertices.Add(vertices[i]);
} // set vertices
mesh.vertices = vertices.ToArray(); // set triangles
mesh.triangles = triangles.ToArray(); // set uvs
Vector2[] uv = new Vector2[vertices.Count];
for(int i = ; i < vertices.Count; i++)
{
uv[i] = Vector2.zero;
}
mesh.uv = uv; mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.RecalculateTangents();
return mesh;
}
结果对比:
顶点数降低到48个了, 这样就只剩下因为生成正反两面造成的顶点和三角面数量翻倍的问题了.
PS : 其实在生成侧面的时候也是有问题的, 虽然它使用的是4个共享点来生成一个面, 可是如果侧面也有多个面的Normal一样, 就造成顶点冗余了. 不过这个影响因子不大,
要修改起来又很难, 暂时无视.
(2019.06.26)
在生成Mesh时添加一个是否顺时针排列的顶点标记, 这样就可以按照方向生成了, 免去多余的一般点和面. 这个逻辑是在三角剖分的部分进行修改的, 这里只贴经过修改后的
模型生成代码:
public static Mesh CreateGeoJsonMesh(List<Vector3> basePoints, float height, bool clockwise)
{
Mesh mesh = new Mesh();
mesh.name = "GeoJsonMesh"; List<Vector3> vertices = new List<Vector3>();
List<int> triangles = new List<int>(); // bottom triangles
List<Vector3> baseVerts = null;
List<int> baseIndexes = null;
Triangulation.GenericTriangulate(basePoints, clockwise == false, out baseVerts, out baseIndexes);
vertices.AddRange(baseVerts);
triangles.AddRange(baseIndexes); // fast caculate top triangles
List<Vector3> topVerts = new List<Vector3>();
List<int> topIndexes = new List<int>();
for(int i = ; i < baseVerts.Count; i++)
{
var p = baseVerts[i];
p.y += height;
topVerts.Add(p);
}
for(int i = ; i < baseIndexes.Count; i += )
{
topIndexes.Add(baseIndexes[i + ] + baseVerts.Count);
topIndexes.Add(baseIndexes[i + ] + baseVerts.Count);
topIndexes.Add(baseIndexes[i] + baseVerts.Count);
}
vertices.AddRange(topVerts);
triangles.AddRange(topIndexes); // vertical triangles
int startIndex = vertices.Count;
for(int i = ; i < basePoints.Count; i++)
{
bool loop = i + >= basePoints.Count;
var p0 = basePoints[i];
var p1 = basePoints[loop ? : i + ];
var p2 = p1 + Vector3.up * height;
var p3 = p0 + Vector3.up * height; vertices.Add(p0);
vertices.Add(p1);
vertices.Add(p2);
vertices.Add(p3); if(clockwise)
{
triangles.Add(startIndex);
triangles.Add(startIndex + );
triangles.Add(startIndex + ); triangles.Add(startIndex);
triangles.Add(startIndex + );
triangles.Add(startIndex + );
}
else
{
triangles.Add(startIndex);
triangles.Add(startIndex + );
triangles.Add(startIndex + ); triangles.Add(startIndex);
triangles.Add(startIndex + );
triangles.Add(startIndex + );
} startIndex += ;
} // set vertices
mesh.vertices = vertices.ToArray(); // set triangles
mesh.triangles = triangles.ToArray(); // set uvs
Vector2[] uv = new Vector2[vertices.Count];
for(int i = ; i < vertices.Count; i++)
{
uv[i] = Vector2.zero;
}
mesh.uv = uv; mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.RecalculateTangents();
return mesh;
}
因为顶点列表代表的是模型的底部, 所以朝向是Y轴负方向, 顶部才是Y轴正方向的.
这样顶部和底部的三角剖分是没有什么问题了, 竖直的边缘的三角剖分还是有点问题的, 问题在于共享点上, 仍然存在同样的面没有使用同样的共享点的情况. 后面会把这些功能另外提取出来做出最精简的模型.
生成的模型已经和系统自带的一样了没有冗余了.
使用类似GeoJson的数据生成物体(建筑等)的功能逻辑的更多相关文章
- plsql中数据生成工具data generator的使用
使用数据库时,有时需要使用大量的数据,可以用PLSQL Developer提供的Data Generator工具, 这里记录一下工具的介绍及几个使用注意事项 1.工具介绍 功能入口位于 工具 菜单下, ...
- 快速将一个表的数据生成SQL插入语句
将一个表中的数据生成SQL插入语句,方便系统快速初始化,在数据库中执行创建以下过程就可以了. ) Drop Procedure GenerateData go CREATE PROCEDURE Gen ...
- Charted – 自动化的可视化数据生成工具
Charted 是一个让数据自动生成可视化图表的工具.只需要提供一个数据文件的链接,它就能返回一个美丽的,可共享的图表.Charted 不会存储任何数据.它只是获取和让链接提供的数据可视化. 在线演示 ...
- Web 开发人员必备的随机 JSON 数据生成工具
在 Web 开发中,经常会需要一些测试数据来测试接口或者功能时候正确.JSON Generator 就是这样一款生成随机 JSON 数据的在线工具,Web 开发人员必备,记得收藏和分享啊. 您可能感兴 ...
- 将表数据生成Insert脚本
set ANSI_NULLS ONset QUOTED_IDENTIFIER ONgo-- =============================================-- Author ...
- 一个比较全面的java随机数据生成工具包
最近,由于一个项目的原因需要使用一些随机数据做测试,于是写了一个随机数据生成工具,ExtraRanom.可以看成是Java官方Random类的扩展,主要用于主要用于测试程序.生成密码.设计抽奖程序等情 ...
- 将表中数据生成SQL语句
在开发过程中,经常需要我们对表中的数据进行转移,如果在同台机器,可以使用SQL自带的导入数据,但是如果想让所有的数据生成可执行的SQL语句,它的移植性最强了.首先要设计一个存储过程.具体如下: CRE ...
- Entity Framework 数据生成选项DatabaseGenerated
在EF中,我们建立数据模型的时候,可以给属性配置数据生成选项DatabaseGenerated,它后有三个枚举值:Identity.None和Computed. Identity:自增长 None:不 ...
- skymvc网站测试之mysql数据生成
skymvc网站测试之mysql数据生成 使用方法: 删除数据 /index.php?m=test_mysql&a=autoDelete 重置自增ID /index.php?m=test_my ...
随机推荐
- 2.git的 分支管理
一般我们进行提交的时候.都是在master上面提交的. git status 查看当前分支. [root@localhost jenkins_git]# git branch about * mast ...
- 201871010111-刘佳华《面向对象程序设计(java)》第十五周学习总结
201871010111-刘佳华<面向对象程序设计(java)>第十五周学习总结 实验十三 Swing图形界面组件(二) 实验时间 2019-12-6 第一部分:理论知识总结 5> ...
- Python实现网络图形化界面多人聊天室 - Windows
Python实现网络图形化界面多人聊天室 - Windows 项目名称:网络多人聊天室图形界面版本 项目思路: server.py 服务端文件,主进程中,创建图形化界面,询问地址(主机名,端口),点击 ...
- CodeForces - 545CWoodcutters
传送门 题目大意:n棵树(10^5),坐标xi,高度hi,把这棵树砍到,可以向右倒[xi,xi+hi]被占, 向左倒[xi-hi,xi]被占,必须要倒的坐标没有被占才能倒,不砍倒就xi被占,问最多砍几 ...
- [[: not found,Ubuntu修改默认sh为bash
写好的shell sh执行脚本报错[[: not found,改shell多麻烦,索性直接把电脑默认的dash改成使用bash 1.查看目前使用 Ubuntu版本默认sh都是使用的dash 执行 ls ...
- Loj #2568. 「APIO2016」烟花表演
Loj #2568. 「APIO2016」烟花表演 题目描述 烟花表演是最引人注目的节日活动之一.在表演中,所有的烟花必须同时爆炸.为了确保安全,烟花被安置在远离开关的位置上,通过一些导火索与开关相连 ...
- Algorithm: CRT、EX-CRT & Lucas、Ex-Lucas
中国剩余定理 中国剩余定理,Chinese Remainder Theorem,又称孙子定理,给出了一元线性同余方程组的有解判定条件,并用构造法给出了通解的具体形式. \[ \begin{aligne ...
- Django学习笔记(10)——Book单表的增删改查页面
一,项目题目:Book单表的增删改查页面 该项目主要练习使用Django开发一个Book单表的增删改查页面,通过这个项目巩固自己这段时间学习Django知识. 二,项目需求: 开发一个简单的Book增 ...
- JavaScript定时器越走越快的问题
目录 JavaScript定时器越走越快的问题 (setinterval)多次初始化 清除(clearInterval)的失效 解决方法 JavaScript定时器越走越快的问题 之前在项目中写了定时 ...
- 什么是code-Behind技术?
code-Behind技术就是代码隐藏(代码后置),在ASP.NET中通过ASPX页面指向CS文件的方法实现显示逻辑和处理逻辑的分离,这样有助于web应用程序的创建. 比如分工,美工和编程的可以个干各 ...