STLExporter.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. ( function () {
  2. /**
  3. * Usage:
  4. * const exporter = new STLExporter();
  5. *
  6. * // second argument is a list of options
  7. * const data = exporter.parse( mesh, { binary: true } );
  8. *
  9. */
  10. class STLExporter {
  11. parse( scene, options = {} ) {
  12. const binary = options.binary !== undefined ? options.binary : false; //
  13. const objects = [];
  14. let triangles = 0;
  15. scene.traverse( function ( object ) {
  16. if ( object.isMesh ) {
  17. const geometry = object.geometry;
  18. if ( geometry.isBufferGeometry !== true ) {
  19. throw new Error( 'THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.' );
  20. }
  21. const index = geometry.index;
  22. const positionAttribute = geometry.getAttribute( 'position' );
  23. triangles += index !== null ? index.count / 3 : positionAttribute.count / 3;
  24. objects.push( {
  25. object3d: object,
  26. geometry: geometry
  27. } );
  28. }
  29. } );
  30. let output;
  31. let offset = 80; // skip header
  32. if ( binary === true ) {
  33. const bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4;
  34. const arrayBuffer = new ArrayBuffer( bufferLength );
  35. output = new DataView( arrayBuffer );
  36. output.setUint32( offset, triangles, true );
  37. offset += 4;
  38. } else {
  39. output = '';
  40. output += 'solid exported\n';
  41. }
  42. const vA = new THREE.Vector3();
  43. const vB = new THREE.Vector3();
  44. const vC = new THREE.Vector3();
  45. const cb = new THREE.Vector3();
  46. const ab = new THREE.Vector3();
  47. const normal = new THREE.Vector3();
  48. for ( let i = 0, il = objects.length; i < il; i ++ ) {
  49. const object = objects[ i ].object3d;
  50. const geometry = objects[ i ].geometry;
  51. const index = geometry.index;
  52. const positionAttribute = geometry.getAttribute( 'position' );
  53. if ( index !== null ) {
  54. // indexed geometry
  55. for ( let j = 0; j < index.count; j += 3 ) {
  56. const a = index.getX( j + 0 );
  57. const b = index.getX( j + 1 );
  58. const c = index.getX( j + 2 );
  59. writeFace( a, b, c, positionAttribute, object );
  60. }
  61. } else {
  62. // non-indexed geometry
  63. for ( let j = 0; j < positionAttribute.count; j += 3 ) {
  64. const a = j + 0;
  65. const b = j + 1;
  66. const c = j + 2;
  67. writeFace( a, b, c, positionAttribute, object );
  68. }
  69. }
  70. }
  71. if ( binary === false ) {
  72. output += 'endsolid exported\n';
  73. }
  74. return output;
  75. function writeFace( a, b, c, positionAttribute, object ) {
  76. vA.fromBufferAttribute( positionAttribute, a );
  77. vB.fromBufferAttribute( positionAttribute, b );
  78. vC.fromBufferAttribute( positionAttribute, c );
  79. if ( object.isSkinnedMesh === true ) {
  80. object.boneTransform( a, vA );
  81. object.boneTransform( b, vB );
  82. object.boneTransform( c, vC );
  83. }
  84. vA.applyMatrix4( object.matrixWorld );
  85. vB.applyMatrix4( object.matrixWorld );
  86. vC.applyMatrix4( object.matrixWorld );
  87. writeNormal( vA, vB, vC );
  88. writeVertex( vA );
  89. writeVertex( vB );
  90. writeVertex( vC );
  91. if ( binary === true ) {
  92. output.setUint16( offset, 0, true );
  93. offset += 2;
  94. } else {
  95. output += '\t\tendloop\n';
  96. output += '\tendfacet\n';
  97. }
  98. }
  99. function writeNormal( vA, vB, vC ) {
  100. cb.subVectors( vC, vB );
  101. ab.subVectors( vA, vB );
  102. cb.cross( ab ).normalize();
  103. normal.copy( cb ).normalize();
  104. if ( binary === true ) {
  105. output.setFloat32( offset, normal.x, true );
  106. offset += 4;
  107. output.setFloat32( offset, normal.y, true );
  108. offset += 4;
  109. output.setFloat32( offset, normal.z, true );
  110. offset += 4;
  111. } else {
  112. output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
  113. output += '\t\touter loop\n';
  114. }
  115. }
  116. function writeVertex( vertex ) {
  117. if ( binary === true ) {
  118. output.setFloat32( offset, vertex.x, true );
  119. offset += 4;
  120. output.setFloat32( offset, vertex.y, true );
  121. offset += 4;
  122. output.setFloat32( offset, vertex.z, true );
  123. offset += 4;
  124. } else {
  125. output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
  126. }
  127. }
  128. }
  129. }
  130. THREE.STLExporter = STLExporter;
  131. } )();