小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

[Mesh]網(wǎng)格的快速切割

 勤奮不止 2019-06-25

最終效果




思路

  • 確定切面
  • 根據(jù)切面將原模型頂點(diǎn)分為切面上下兩類
  • 將交面進(jìn)行特殊處理,根據(jù)角度或距離插值運(yùn)算交點(diǎn),并添加頂點(diǎn)索引
  • 對剖面頂點(diǎn)進(jìn)行重新排序,連接,UV映射

實(shí)現(xiàn)

因?yàn)榇a量大只寫局部偽代碼說明。
關(guān)于網(wǎng)格的基礎(chǔ)教程,請參閱Mesh網(wǎng)格篇(一)代碼生成圓柱Mesh
為了方便這里我們拿BOX舉例。

頂點(diǎn)站隊(duì)

當(dāng)我們確定切面裁切一個(gè)box時(shí),我們首先需要做的是把頂點(diǎn)分類,通過向量的點(diǎn)乘將頂點(diǎn)0145和2376分為切面的ab兩組,同時(shí)記錄下ab的頂點(diǎn)進(jìn)入排序和他在切面上下的狀態(tài)。

  1. bool[] above = new bool[MeshInfo.vertices.Count];
  2. int[] newTriangles = new int[MeshInfo.vertices.Count];
  3. for (int i = 0; i < newTriangles.Length; i++)
  4. {
  5. Vector3 vert = MeshInfo.vertices[i];
  6. above[i] = Vector3.Dot(vert - point, normal) >= 0f;
  7. if (above[i])
  8. {
  9. newTriangles[i] = a.vertices.Count;
  10. a.Add(vert, MeshInfo.uvs[i], MeshInfo.normals[i], MeshInfo.tangents[i]);
  11. }
  12. else
  13. {
  14. newTriangles[i] = b.vertices.Count;
  15. b.Add(vert, MeshInfo.uvs[i], MeshInfo.normals[i], MeshInfo.tangents[i]);
  16. }
  17. }

接下來我們按照原模型的連接方式逐個(gè)連接ab中的頂點(diǎn)

  1. for (int i = 0; i < triangleCount; i++)
  2. {
  3. int _i0 = MeshInfo.triangles[i * 3];
  4. int _i1 = MeshInfo.triangles[i * 3 + 1];
  5. int _i2 = MeshInfo.triangles[i * 3 + 2];
  6. bool _a0 = above[_i0];
  7. bool _a1 = above[_i1];
  8. bool _a2 = above[_i2];
  9. if (_a0 && _a1 && _a2)
  10. {
  11. a.triangles.Add(newTriangles[_i0]);
  12. a.triangles.Add(newTriangles[_i1]);
  13. a.triangles.Add(newTriangles[_i2]);
  14. }
  15. else if (!_a0 && !_a1 && !_a2)
  16. {
  17. b.triangles.Add(newTriangles[_i0]);
  18. b.triangles.Add(newTriangles[_i1]);
  19. b.triangles.Add(newTriangles[_i2]);
  20. }
  21. else
  22. {
  23. //....
  24. }
通過與原模型頂點(diǎn)索引的比較,我們將得到

切面補(bǔ)間

這樣2個(gè)模型,很明顯中間網(wǎng)格需要我們在else中進(jìn)行補(bǔ)點(diǎn)補(bǔ)線。

這里講下我們?nèi)绻デ懈钜粋€(gè)平面。
一個(gè)平面被切割時(shí),也就兩個(gè)三角面被切割。

假如△abc被坐標(biāo)軸x切割,我們?nèi)绾未_定點(diǎn)d和e的位置呢。
求角度比scale = ∠yba/ ∠yoa;(float scale = Vector.Dot(a-o,y-o)/Vector.Dot(a-b,y-o);)
d = b+(a-b)*scale;
e = c+(a-c)*scale;
然后根據(jù)網(wǎng)格的連接順序連接,aed,bdc,cde。
然后把頂點(diǎn)和a頂點(diǎn)索引加入到a面中,頂點(diǎn)和b頂點(diǎn)索引加入到b面中。

我們就能得到類似上面的2個(gè)模型。

剖面填充

這時(shí)我們就要填充剖面,但是剖面的頂點(diǎn)順序我們并不知道。
所以要對頂點(diǎn)進(jìn)行排序。

局限性排序

幸運(yùn)的是我們的頂點(diǎn)都是兩兩相連,每個(gè)頂點(diǎn)的位置其實(shí)有2個(gè)面的頂點(diǎn)重疊。
根據(jù)這個(gè)特性,我們就可以以此為根據(jù)尋找下個(gè)連接頂點(diǎn)的位置,然后刪除重復(fù)的頂點(diǎn)。
  1. for (int i = 0; i < edges.Count - 3; i++)
  2. {
  3. Vector3 t = edges[i + 1];
  4. Vector3 temp = edges[i + 3];
  5. for (int j = i + 2; j < edges.Count - 1; j += 2)
  6. {
  7. if ((edges[j] - t).sqrMagnitude < 1e-6)
  8. {
  9. edges[j] = edges[i + 2];
  10. edges[i + 3] = edges[j + 1];
  11. edges[j + 1] = temp;
  12. break;
  13. }
  14. if ((edges[j + 1] - t).sqrMagnitude < 1e-6)
  15. {
  16. edges[j + 1] = edges[i + 2];
  17. edges[i + 3] = edges[j];
  18. edges[j] = temp;
  19. break;
  20. }
  21. }
  22. edges.RemoveAt(i + 2);
  23. }
  24. edges.RemoveAt(edges.Count - 1);
這樣我們就得到了一個(gè)按剖面形狀連接的順序頂點(diǎn)。
只要按012,023,034。。。。的順序連接下去就能把剖面填充。

常規(guī)排序

那如何對凸多邊形上內(nèi)任意若干的頂點(diǎn)進(jìn)行連接呢。
這時(shí)候我們需要根據(jù)凸多邊形的外切線和角度來確定下個(gè)頂點(diǎn)的位置。
這里只提供思路,代碼太長就不貼了,而且在模型切割上效率不如上面的高。
首先將頂點(diǎn)都轉(zhuǎn)換到切線尋找凸多邊形的外切線向量。
然后逐頂點(diǎn)對比角度。
如果兩個(gè)頂點(diǎn)與切線共線,我們就比較距離,一個(gè)頂點(diǎn)只有2個(gè)頂點(diǎn)連接他。第一次共線距離為近的排序,第二次共線距離為遠(yuǎn)的排序。

凹多邊形

有人問凹多邊形如何填充,呵呵,如果填充凹多邊形,要先把凹多邊形分割成若干個(gè)凸多邊形進(jìn)行填充。

UV映射

接下來就是對剖面的頂點(diǎn)UV進(jìn)行映射。根據(jù)情況賦值的方法不同。
拿BOX舉例,
我們需要把box的bound的size傳入,然后根據(jù) point/size 來確定uv偏移值,根據(jù)切面的法線方向決定取xy?xz?zy?
  1. int count = triangles.Count / 3;
  2. for (int i = 0; i < count; i++)
  3. {
  4. int _i0 = triangles[i * 3];
  5. int _i1 = triangles[i * 3 + 1];
  6. int _i2 = triangles[i * 3 + 2];
  7. Vector3 v0 = vertices[_i0] - center + size / 2f;
  8. Vector3 v1 = vertices[_i1] - center + size / 2f;
  9. Vector3 v2 = vertices[_i2] - center + size / 2f;
  10. v0 = new Vector3(v0.x / size.x, v0.y / size.y, v0.z / size.z);
  11. v1 = new Vector3(v1.x / size.x, v1.y / size.y, v1.z / size.z);
  12. v2 = new Vector3(v2.x / size.x, v2.y / size.y, v2.z / size.z);
  13. Vector3 a = v0 - v1;
  14. Vector3 b = v2 - v1;
  15. Vector3 dir = Vector3.Cross(a, b);
  16. float x = Mathf.Abs(Vector3.Dot(dir, Vector3.right));
  17. float y = Mathf.Abs(Vector3.Dot(dir, Vector3.up));
  18. float z = Mathf.Abs(Vector3.Dot(dir, Vector3.forward));
  19. if (x > y && x > z)
  20. {
  21. uvs[_i0] = new Vector2(v0.z, v0.y);
  22. uvs[_i1] = new Vector2(v1.z, v1.y);
  23. uvs[_i2] = new Vector2(v2.z, v2.y);
  24. }
  25. else if (y > x && y > z)
  26. {
  27. uvs[_i0] = new Vector2(v0.x, v0.z);
  28. uvs[_i1] = new Vector2(v1.x, v1.z);
  29. uvs[_i2] = new Vector2(v2.x, v2.z);
  30. }
  31. else if (z > x && z > y)
  32. {
  33. uvs[_i0] = new Vector2(v0.x, v0.y);
  34. uvs[_i1] = new Vector2(v1.x, v1.y);
  35. uvs[_i2] = new Vector2(v2.x, v2.y);
  36. }
  37. }

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多