使用相似GeoJson的數據生成物體(建築等)的功能邏輯

  GeoJson做爲一種模型傳輸格式, 用的最多的就是地圖裏面的各類簡單模型了, 好比下圖中很貼切的俄羅斯方塊樓:html

  它的格式大概就是下面這樣:ide

{
    "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": "商服"
        }
    }]

}

  通常的多邊形, 它是給了一個底面的各個頂點, 而後給了一個高度讓你去生成簡單模型, 這個頂點列表是有序的, 因此這個多是個凹多邊形. 這就關聯到前面寫的這篇文章了 : 二維空間內的三角剖分 -- (給出邊緣頂點的例子)oop

經過三角剖分咱們就能正確生成底面的全部三角面了, 而後底面加上高度就是頂面的全部三角面了, 而後由於底邊和頂邊是對齊的, 咱們就能夠按照順序每一個相對應的邊組成一個四邊形進行三角形劃分. 邏輯實在過於簡單, 不解釋了. 測試

問題在於三角形面的朝向問題, 這裏只計算了三角面, 並無對朝向進行計算, 若是要進行朝向計算的話就要對每一個三角面的朝向是否向外(相對於該多邊形來講), 這樣邏輯會很複雜, 這裏爲了簡便直接把全部三角形添加一個朝向相反的三角形便可.spa

  代碼 :code

        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 = 0; 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 = 0; i < basePoints.Count; i++)
            {
                bool loop = i + 1 >= basePoints.Count;
                var p0 = basePoints[i];
                var p1 = basePoints[loop ? 0 : i + 1];
                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 = 0, imax = vertices.Count; i < imax; i += 3)
            {
                vertices.Add(vertices[i + 2]);
                vertices.Add(vertices[i + 1]);
                vertices.Add(vertices[i]);
            }

            // set vertices
            mesh.vertices = vertices.ToArray();

            // set triangles
            int[] triangles = new int[vertices.Count];
            for(int i = 0; i < vertices.Count; i++)
            {
                triangles[i] = i;
            }
            mesh.triangles = triangles;

            // set uvs
            Vector2[] uv = new Vector2[vertices.Count];
            for(int i = 0; i < vertices.Count; i++)
            {
                uv[i] = Vector2.zero;
            }
            mesh.uv = uv;

            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            mesh.RecalculateTangents();
            return mesh;
        }

  

  測試代碼, 仍是那個凹字 :orm

        List<Vector3> points = new List<Vector3>();
        points.Add(new Vector3(0.5f, 1, 0.5f));
        points.Add(new Vector3(0.5f, 1, 1.5f));
        points.Add(new Vector3(1.5f, 1, 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;

  得到的模型htm

 

 

  PS : 按照這樣的邏輯作出來的模型, 有 點-面 數量過多的問題 :blog

   一. 由於用了正反兩面, 直接就多了一倍的面數和三角形數量.ip

   二. 在三角剖分以後, 每一個三角面都使用三個非共享頂點(通常來講在同一個平面上 Normal 相同的全部面均可以使用共享頂點來減小頂點數)

看下圖 : 

  左邊是生成出來的正方體, 右邊是系統自帶的正方體.

  它們的差異:

  1. 系統自帶的正方體每一個面用四個頂點表示, 每一個面的兩個三角形共享頂點, 因此只有 4*6 = 24個頂點, 而後三角形經過Index描述

  2. 生成的正方體每一個面2個三角形, 頂點不共享, 就是6個頂點每一個面, 也就是36頂點12個面的原始圖形

  3. 生成的正方體由於三角形朝向沒有明確因此進行了複製翻轉, 多出了一倍的頂點和麪, 72頂點24個面. 

  因此雖然生成過程簡單高效, 但是運行時額外增長了系統負荷. 後續仍是須要進行改進.

 

  通常狀況下給出的頂點列表若是都是按照順時針或逆時針的順序給出的話, 仍是能很簡單作出三角面的方向的, 這就直接減小了一半的點面.

 

  直接修改了一下三角剖分的邏輯, 使用共享點的剖分, 如今能夠減小原始剖分帶來的頂點數問題了:

        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 = 0; i < baseVerts.Count; i++)
            {
                var p = baseVerts[i];
                p.y += height;
                vertices.Add(p);
            }
            for(int i = 0; i < baseIndexes.Count; i++)
            {
                triangles.Add(baseIndexes[i] + baseVerts.Count);
            }

            // vertical triangles
            int startIndex = vertices.Count;
            for(int i = 0; i < basePoints.Count; i++)
            {
                bool loop = i + 1 >= basePoints.Count;
                var p0 = basePoints[i];
                var p1 = basePoints[loop ? 0 : i + 1];
                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 + 1);
                triangles.Add(startIndex + 2);

                triangles.Add(startIndex);
                triangles.Add(startIndex + 2);
                triangles.Add(startIndex + 3);

                startIndex += 4;
            }

            // add inverse triangles for clip
            int baseVertsCount = vertices.Count;
            for(int i = 0, imax = triangles.Count; i < imax; i += 3)
            {
                triangles.Add(triangles[i + 2] + baseVertsCount);
                triangles.Add(triangles[i + 1] + baseVertsCount);
                triangles.Add(triangles[i] + baseVertsCount);
            }
            for(int i = 0, 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 = 0; i < vertices.Count; i++)
            {
                uv[i] = Vector2.zero;
            }
            mesh.uv = uv;

            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            mesh.RecalculateTangents();
            return mesh;
        }

  結果對比: 

  頂點數下降到48個了, 這樣就只剩下由於生成正反兩面形成的頂點和三角面數量翻倍的問題了.

相關文章
相關標籤/搜索