STLExporter.js 3.9 KB

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