STLExporter.js 3.8 KB

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