PolyhedronGeometry.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /**
  2. * @author clockworkgeek / https://github.com/clockworkgeek
  3. * @author timothypratley / https://github.com/timothypratley
  4. * @author WestLangley / http://github.com/WestLangley
  5. * @author Mugen87 / https://github.com/Mugen87
  6. */
  7. import { Geometry } from '../core/Geometry';
  8. import { BufferGeometry } from '../core/BufferGeometry';
  9. import { Float32BufferAttribute } from '../core/BufferAttribute';
  10. import { Vector3 } from '../math/Vector3';
  11. import { Vector2 } from '../math/Vector2';
  12. // PolyhedronGeometry
  13. function PolyhedronGeometry( vertices, indices, radius, detail ) {
  14. Geometry.call( this );
  15. this.type = 'PolyhedronGeometry';
  16. this.parameters = {
  17. vertices: vertices,
  18. indices: indices,
  19. radius: radius,
  20. detail: detail
  21. };
  22. this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
  23. this.mergeVertices();
  24. }
  25. PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
  26. PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
  27. // PolyhedronBufferGeometry
  28. function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
  29. BufferGeometry.call( this );
  30. this.type = 'PolyhedronBufferGeometry';
  31. this.parameters = {
  32. vertices: vertices,
  33. indices: indices,
  34. radius: radius,
  35. detail: detail
  36. };
  37. radius = radius || 1;
  38. detail = detail || 0;
  39. // default buffer data
  40. var vertexBuffer = [];
  41. var uvBuffer = [];
  42. // the subdivision creates the vertex buffer data
  43. subdivide( detail );
  44. // all vertices should lie on a conceptual sphere with a given radius
  45. appplyRadius( radius );
  46. // finally, create the uv data
  47. generateUVs();
  48. // build non-indexed geometry
  49. this.addAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
  50. this.addAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
  51. this.addAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
  52. if ( detail === 0 ) {
  53. this.computeVertexNormals(); // flat normals
  54. } else {
  55. this.normalizeNormals(); // smooth normals
  56. }
  57. // helper functions
  58. function subdivide( detail ) {
  59. var a = new Vector3();
  60. var b = new Vector3();
  61. var c = new Vector3();
  62. // iterate over all faces and apply a subdivison with the given detail value
  63. for ( var i = 0; i < indices.length; i += 3 ) {
  64. // get the vertices of the face
  65. getVertexByIndex( indices[ i + 0 ], a );
  66. getVertexByIndex( indices[ i + 1 ], b );
  67. getVertexByIndex( indices[ i + 2 ], c );
  68. // perform subdivision
  69. subdivideFace( a, b, c, detail );
  70. }
  71. }
  72. function subdivideFace( a, b, c, detail ) {
  73. var cols = Math.pow( 2, detail );
  74. // we use this multidimensional array as a data structure for creating the subdivision
  75. var v = [];
  76. var i, j;
  77. // construct all of the vertices for this subdivision
  78. for ( i = 0; i <= cols; i ++ ) {
  79. v[ i ] = [];
  80. var aj = a.clone().lerp( c, i / cols );
  81. var bj = b.clone().lerp( c, i / cols );
  82. var rows = cols - i;
  83. for ( j = 0; j <= rows; j ++ ) {
  84. if ( j === 0 && i === cols ) {
  85. v[ i ][ j ] = aj;
  86. } else {
  87. v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
  88. }
  89. }
  90. }
  91. // construct all of the faces
  92. for ( i = 0; i < cols; i ++ ) {
  93. for ( j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
  94. var k = Math.floor( j / 2 );
  95. if ( j % 2 === 0 ) {
  96. pushVertex( v[ i ][ k + 1 ] );
  97. pushVertex( v[ i + 1 ][ k ] );
  98. pushVertex( v[ i ][ k ] );
  99. } else {
  100. pushVertex( v[ i ][ k + 1 ] );
  101. pushVertex( v[ i + 1 ][ k + 1 ] );
  102. pushVertex( v[ i + 1 ][ k ] );
  103. }
  104. }
  105. }
  106. }
  107. function appplyRadius( radius ) {
  108. var vertex = new Vector3();
  109. // iterate over the entire buffer and apply the radius to each vertex
  110. for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
  111. vertex.x = vertexBuffer[ i + 0 ];
  112. vertex.y = vertexBuffer[ i + 1 ];
  113. vertex.z = vertexBuffer[ i + 2 ];
  114. vertex.normalize().multiplyScalar( radius );
  115. vertexBuffer[ i + 0 ] = vertex.x;
  116. vertexBuffer[ i + 1 ] = vertex.y;
  117. vertexBuffer[ i + 2 ] = vertex.z;
  118. }
  119. }
  120. function generateUVs() {
  121. var vertex = new Vector3();
  122. for ( var i = 0; i < vertexBuffer.length; i += 3 ) {
  123. vertex.x = vertexBuffer[ i + 0 ];
  124. vertex.y = vertexBuffer[ i + 1 ];
  125. vertex.z = vertexBuffer[ i + 2 ];
  126. var u = azimuth( vertex ) / 2 / Math.PI + 0.5;
  127. var v = inclination( vertex ) / Math.PI + 0.5;
  128. uvBuffer.push( u, 1 - v );
  129. }
  130. correctUVs();
  131. correctSeam();
  132. }
  133. function correctSeam() {
  134. // handle case when face straddles the seam, see #3269
  135. for ( var i = 0; i < uvBuffer.length; i += 6 ) {
  136. // uv data of a single face
  137. var x0 = uvBuffer[ i + 0 ];
  138. var x1 = uvBuffer[ i + 2 ];
  139. var x2 = uvBuffer[ i + 4 ];
  140. var max = Math.max( x0, x1, x2 );
  141. var min = Math.min( x0, x1, x2 );
  142. // 0.9 is somewhat arbitrary
  143. if ( max > 0.9 && min < 0.1 ) {
  144. if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
  145. if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
  146. if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
  147. }
  148. }
  149. }
  150. function pushVertex( vertex ) {
  151. vertexBuffer.push( vertex.x, vertex.y, vertex.z );
  152. }
  153. function getVertexByIndex( index, vertex ) {
  154. var stride = index * 3;
  155. vertex.x = vertices[ stride + 0 ];
  156. vertex.y = vertices[ stride + 1 ];
  157. vertex.z = vertices[ stride + 2 ];
  158. }
  159. function correctUVs() {
  160. var a = new Vector3();
  161. var b = new Vector3();
  162. var c = new Vector3();
  163. var centroid = new Vector3();
  164. var uvA = new Vector2();
  165. var uvB = new Vector2();
  166. var uvC = new Vector2();
  167. for ( var i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
  168. a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
  169. b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
  170. c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
  171. uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
  172. uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
  173. uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
  174. centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
  175. var azi = azimuth( centroid );
  176. correctUV( uvA, j + 0, a, azi );
  177. correctUV( uvB, j + 2, b, azi );
  178. correctUV( uvC, j + 4, c, azi );
  179. }
  180. }
  181. function correctUV( uv, stride, vector, azimuth ) {
  182. if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
  183. uvBuffer[ stride ] = uv.x - 1;
  184. }
  185. if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
  186. uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
  187. }
  188. }
  189. // Angle around the Y axis, counter-clockwise when looking from above.
  190. function azimuth( vector ) {
  191. return Math.atan2( vector.z, - vector.x );
  192. }
  193. // Angle above the XZ plane.
  194. function inclination( vector ) {
  195. return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
  196. }
  197. }
  198. PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
  199. PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
  200. export { PolyhedronGeometry, PolyhedronBufferGeometry };