babylon.edgesRenderer.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. var BABYLON;
  2. (function (BABYLON) {
  3. var FaceAdjacencies = (function () {
  4. function FaceAdjacencies() {
  5. this.edges = new Array();
  6. this.edgesConnectedCount = 0;
  7. }
  8. return FaceAdjacencies;
  9. })();
  10. var EdgesRenderer = (function () {
  11. function EdgesRenderer(source) {
  12. this._lines = new Array();
  13. this._source = source;
  14. this._material = new BABYLON.StandardMaterial(this._source.name + "EdgeMaterial", this._source.getScene());
  15. this._material.emissiveColor = this._source.edgesColor;
  16. this._material.diffuseColor = BABYLON.Color3.Black();
  17. this._material.specularColor = BABYLON.Color3.Black();
  18. this._generateEdgesLines();
  19. }
  20. EdgesRenderer.prototype.dispose = function () {
  21. for (var index = 0; index < this._lines.length; index++) {
  22. this._lines[index].dispose();
  23. }
  24. this._lines = new Array();
  25. };
  26. EdgesRenderer.prototype._processEdgeForAdjacencies = function (pa, pb, p0, p1, p2) {
  27. if (pa === p0 && pb === p1 || pa === p1 && pb === p0) {
  28. return 0;
  29. }
  30. if (pa === p1 && pb === p2 || pa === p2 && pb === p1) {
  31. return 1;
  32. }
  33. if (pa === p2 && pb === p0 || pa === p0 && pb === p2) {
  34. return 2;
  35. }
  36. return -1;
  37. };
  38. EdgesRenderer.prototype._checkEdge = function (faceIndex, edge, faceNormals, p0, p1) {
  39. var needToCreateLine;
  40. if (edge === undefined) {
  41. needToCreateLine = true;
  42. }
  43. else {
  44. var dotProduct = BABYLON.Vector3.Dot(faceNormals[faceIndex], faceNormals[edge]);
  45. needToCreateLine = dotProduct < this._source.edgesEpsilon;
  46. }
  47. if (needToCreateLine) {
  48. var scene = this._source.getScene();
  49. var lineMesh = BABYLON.Mesh.CreateTube(this._source.name + "edge", [p0, p1], this._source.edgesWidth / 100.0, 5, null, BABYLON.Mesh.CAP_ALL, scene, false, BABYLON.Mesh.DEFAULTSIDE);
  50. this._lines.push(lineMesh);
  51. }
  52. };
  53. EdgesRenderer.prototype._generateEdgesLines = function () {
  54. var positions = this._source.getVerticesData(BABYLON.VertexBuffer.PositionKind);
  55. var indices = this._source.getIndices();
  56. // First let's find adjacencies
  57. var adjacencies = new Array();
  58. var faceNormals = new Array();
  59. var index;
  60. var faceAdjacencies;
  61. // Prepare faces
  62. for (index = 0; index < indices.length; index += 3) {
  63. faceAdjacencies = new FaceAdjacencies();
  64. var p0Index = indices[index];
  65. var p1Index = indices[index + 1];
  66. var p2Index = indices[index + 2];
  67. faceAdjacencies.p0 = new BABYLON.Vector3(positions[p0Index * 3], positions[p0Index * 3 + 1], positions[p0Index * 3 + 2]);
  68. faceAdjacencies.p1 = new BABYLON.Vector3(positions[p1Index * 3], positions[p1Index * 3 + 1], positions[p1Index * 3 + 2]);
  69. faceAdjacencies.p2 = new BABYLON.Vector3(positions[p2Index * 3], positions[p2Index * 3 + 1], positions[p2Index * 3 + 2]);
  70. var faceNormal = BABYLON.Vector3.Cross(faceAdjacencies.p1.subtract(faceAdjacencies.p0), faceAdjacencies.p2.subtract(faceAdjacencies.p1));
  71. faceNormal.normalize();
  72. faceNormals.push(faceNormal);
  73. adjacencies.push(faceAdjacencies);
  74. }
  75. // Scan
  76. for (index = 0; index < adjacencies.length; index++) {
  77. faceAdjacencies = adjacencies[index];
  78. for (var otherIndex = index + 1; otherIndex < adjacencies.length; otherIndex++) {
  79. if (faceAdjacencies.edgesConnectedCount === 3) {
  80. break;
  81. }
  82. var otherP0 = indices[otherIndex * 3];
  83. var otherP1 = indices[otherIndex * 3 + 1];
  84. var otherP2 = indices[otherIndex * 3 + 2];
  85. for (var edgeIndex = 0; edgeIndex < 3; edgeIndex++) {
  86. var otherEdgeIndex;
  87. switch (edgeIndex) {
  88. case 0:
  89. otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3], indices[index * 3 + 1], otherP0, otherP1, otherP2);
  90. break;
  91. case 1:
  92. otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 1], indices[index * 3 + 2], otherP0, otherP1, otherP2);
  93. break;
  94. case 2:
  95. otherEdgeIndex = this._processEdgeForAdjacencies(indices[index * 3 + 2], indices[index * 3], otherP0, otherP1, otherP2);
  96. break;
  97. }
  98. if (otherEdgeIndex === -1) {
  99. continue;
  100. }
  101. faceAdjacencies.edges[edgeIndex] = otherIndex;
  102. adjacencies[otherIndex].edges[otherEdgeIndex] = index;
  103. faceAdjacencies.edgesConnectedCount++;
  104. adjacencies[otherIndex].edgesConnectedCount++;
  105. }
  106. }
  107. }
  108. // Create lines
  109. for (index = 0; index < adjacencies.length; index++) {
  110. // We need a line when a face has no adjacency on a specific edge or if all the adjacencies has an angle greater than epsilon
  111. var current = adjacencies[index];
  112. this._checkEdge(index, current.edges[0], faceNormals, current.p0, current.p1);
  113. this._checkEdge(index, current.edges[1], faceNormals, current.p1, current.p2);
  114. this._checkEdge(index, current.edges[2], faceNormals, current.p2, current.p0);
  115. }
  116. // Merge into a single mesh
  117. this._renderMesh = BABYLON.Mesh.MergeMeshes(this._lines, true, true);
  118. this._renderMesh.parent = this._source;
  119. this._renderMesh.material = this._material;
  120. this._renderMesh.name = this._source.name + "edge";
  121. };
  122. return EdgesRenderer;
  123. })();
  124. BABYLON.EdgesRenderer = EdgesRenderer;
  125. })(BABYLON || (BABYLON = {}));