STLExporter.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. import { Vector3 } from '../lib/three.module.js'
  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 && object.visible) {
  18. const geometry = object.geometry
  19. if (geometry.isBufferGeometry !== true) {
  20. throw new Error('THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.')
  21. }
  22. const index = geometry.index
  23. const positionAttribute = geometry.getAttribute('position')
  24. triangles += index !== null ? index.count / 3 : positionAttribute.count / 3
  25. objects.push({
  26. object3d: object,
  27. geometry: geometry
  28. })
  29. }
  30. })
  31. let output
  32. let offset = 80 // skip header
  33. if (binary === true) {
  34. const bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4
  35. const arrayBuffer = new ArrayBuffer(bufferLength)
  36. output = new DataView(arrayBuffer)
  37. output.setUint32(offset, triangles, true)
  38. offset += 4
  39. } else {
  40. output = ''
  41. output += 'solid exported\n'
  42. }
  43. const vA = new Vector3()
  44. const vB = new Vector3()
  45. const vC = new Vector3()
  46. const cb = new Vector3()
  47. const ab = new Vector3()
  48. const normal = new Vector3()
  49. for (let i = 0, il = objects.length; i < il; i++) {
  50. const object = objects[i].object3d
  51. const geometry = objects[i].geometry
  52. const index = geometry.index
  53. const positionAttribute = geometry.getAttribute('position')
  54. if (index !== null) {
  55. // indexed geometry
  56. for (let j = 0; j < index.count; j += 3) {
  57. const a = index.getX(j + 0)
  58. const b = index.getX(j + 1)
  59. const c = index.getX(j + 2)
  60. writeFace(a, b, c, positionAttribute, object)
  61. }
  62. } else {
  63. // non-indexed geometry
  64. for (let j = 0; j < positionAttribute.count; j += 3) {
  65. const a = j + 0
  66. const b = j + 1
  67. const c = j + 2
  68. writeFace(a, b, c, positionAttribute, object)
  69. }
  70. }
  71. }
  72. if (binary === false) {
  73. output += 'endsolid exported\n'
  74. }
  75. return output
  76. function writeFace(a, b, c, positionAttribute, object) {
  77. vA.fromBufferAttribute(positionAttribute, a)
  78. vB.fromBufferAttribute(positionAttribute, b)
  79. vC.fromBufferAttribute(positionAttribute, c)
  80. if (object.isSkinnedMesh === true) {
  81. object.boneTransform(a, vA)
  82. object.boneTransform(b, vB)
  83. object.boneTransform(c, vC)
  84. }
  85. vA.applyMatrix4(object.matrixWorld)
  86. vB.applyMatrix4(object.matrixWorld)
  87. vC.applyMatrix4(object.matrixWorld)
  88. writeNormal(vA, vB, vC)
  89. writeVertex(vA)
  90. writeVertex(vB)
  91. writeVertex(vC)
  92. if (binary === true) {
  93. output.setUint16(offset, 0, true)
  94. 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)
  107. offset += 4
  108. output.setFloat32(offset, normal.y, true)
  109. offset += 4
  110. output.setFloat32(offset, normal.z, true)
  111. offset += 4
  112. } else {
  113. output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'
  114. output += '\t\touter loop\n'
  115. }
  116. }
  117. function writeVertex(vertex) {
  118. if (binary === true) {
  119. output.setFloat32(offset, vertex.x, true)
  120. offset += 4
  121. output.setFloat32(offset, vertex.y, true)
  122. offset += 4
  123. output.setFloat32(offset, vertex.z, true)
  124. offset += 4
  125. } else {
  126. output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'
  127. }
  128. }
  129. }
  130. }
  131. export { STLExporter }