OBJExporter.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import { Color, Matrix3, Vector2, Vector3 } from '../lib/three.module.js'
  2. class OBJExporter {
  3. parse(object) {
  4. let output = ''
  5. let indexVertex = 0
  6. let indexVertexUvs = 0
  7. let indexNormals = 0
  8. const vertex = new Vector3()
  9. const color = new Color()
  10. const normal = new Vector3()
  11. const uv = new Vector2()
  12. const face = []
  13. function parseMesh(mesh) {
  14. let nbVertex = 0
  15. let nbNormals = 0
  16. let nbVertexUvs = 0
  17. const geometry = mesh.geometry
  18. const normalMatrixWorld = new Matrix3()
  19. if (geometry.isBufferGeometry !== true) {
  20. throw new Error('THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.')
  21. }
  22. // shortcuts
  23. const vertices = geometry.getAttribute('position')
  24. const normals = geometry.getAttribute('normal')
  25. const uvs = geometry.getAttribute('uv')
  26. const indices = geometry.getIndex()
  27. // name of the mesh object
  28. output += 'o ' + mesh.name + '\n'
  29. // name of the mesh material
  30. if (mesh.material && mesh.material.name) {
  31. output += 'usemtl ' + mesh.material.name + '\n'
  32. }
  33. // vertices
  34. if (vertices !== undefined) {
  35. for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
  36. vertex.x = vertices.getX(i)
  37. vertex.y = vertices.getY(i)
  38. vertex.z = vertices.getZ(i)
  39. // transform the vertex to world space
  40. vertex.applyMatrix4(mesh.matrixWorld)
  41. // transform the vertex to export format
  42. output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'
  43. }
  44. }
  45. // uvs
  46. if (uvs !== undefined) {
  47. for (let i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
  48. uv.x = uvs.getX(i)
  49. uv.y = uvs.getY(i)
  50. // transform the uv to export format
  51. output += 'vt ' + uv.x + ' ' + uv.y + '\n'
  52. }
  53. }
  54. // normals
  55. if (normals !== undefined) {
  56. normalMatrixWorld.getNormalMatrix(mesh.matrixWorld)
  57. for (let i = 0, l = normals.count; i < l; i++, nbNormals++) {
  58. normal.x = normals.getX(i)
  59. normal.y = normals.getY(i)
  60. normal.z = normals.getZ(i)
  61. // transform the normal to world space
  62. normal.applyMatrix3(normalMatrixWorld).normalize()
  63. // transform the normal to export format
  64. output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'
  65. }
  66. }
  67. // faces
  68. if (indices !== null) {
  69. for (let i = 0, l = indices.count; i < l; i += 3) {
  70. for (let m = 0; m < 3; m++) {
  71. const j = indices.getX(i + m) + 1
  72. face[m] = indexVertex + j + (normals || uvs ? '/' + (uvs ? indexVertexUvs + j : '') + (normals ? '/' + (indexNormals + j) : '') : '')
  73. }
  74. // transform the face to export format
  75. output += 'f ' + face.join(' ') + '\n'
  76. }
  77. } else {
  78. for (let i = 0, l = vertices.count; i < l; i += 3) {
  79. for (let m = 0; m < 3; m++) {
  80. const j = i + m + 1
  81. face[m] = indexVertex + j + (normals || uvs ? '/' + (uvs ? indexVertexUvs + j : '') + (normals ? '/' + (indexNormals + j) : '') : '')
  82. }
  83. // transform the face to export format
  84. output += 'f ' + face.join(' ') + '\n'
  85. }
  86. }
  87. // update index
  88. indexVertex += nbVertex
  89. indexVertexUvs += nbVertexUvs
  90. indexNormals += nbNormals
  91. }
  92. function parseLine(line) {
  93. let nbVertex = 0
  94. const geometry = line.geometry
  95. const type = line.type
  96. if (geometry.isBufferGeometry !== true) {
  97. throw new Error('THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.')
  98. }
  99. // shortcuts
  100. const vertices = geometry.getAttribute('position')
  101. // name of the line object
  102. output += 'o ' + line.name + '\n'
  103. if (vertices !== undefined) {
  104. for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
  105. vertex.x = vertices.getX(i)
  106. vertex.y = vertices.getY(i)
  107. vertex.z = vertices.getZ(i)
  108. // transform the vertex to world space
  109. vertex.applyMatrix4(line.matrixWorld)
  110. // transform the vertex to export format
  111. output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'
  112. }
  113. }
  114. if (type === 'Line') {
  115. output += 'l '
  116. for (let j = 1, l = vertices.count; j <= l; j++) {
  117. output += indexVertex + j + ' '
  118. }
  119. output += '\n'
  120. }
  121. if (type === 'LineSegments') {
  122. for (let j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
  123. output += 'l ' + (indexVertex + j) + ' ' + (indexVertex + k) + '\n'
  124. }
  125. }
  126. // update index
  127. indexVertex += nbVertex
  128. }
  129. function parsePoints(points) {
  130. let nbVertex = 0
  131. const geometry = points.geometry
  132. if (geometry.isBufferGeometry !== true) {
  133. throw new Error('THREE.OBJExporter: Geometry is not of type THREE.BufferGeometry.')
  134. }
  135. const vertices = geometry.getAttribute('position')
  136. const colors = geometry.getAttribute('color')
  137. output += 'o ' + points.name + '\n'
  138. if (vertices !== undefined) {
  139. for (let i = 0, l = vertices.count; i < l; i++, nbVertex++) {
  140. vertex.fromBufferAttribute(vertices, i)
  141. vertex.applyMatrix4(points.matrixWorld)
  142. output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z
  143. if (colors !== undefined) {
  144. color.fromBufferAttribute(colors, i)
  145. output += ' ' + color.r + ' ' + color.g + ' ' + color.b
  146. }
  147. output += '\n'
  148. }
  149. }
  150. output += 'p '
  151. for (let j = 1, l = vertices.count; j <= l; j++) {
  152. output += indexVertex + j + ' '
  153. }
  154. output += '\n'
  155. // update index
  156. indexVertex += nbVertex
  157. }
  158. object.traverse(function(child) {
  159. if (child.visible) {
  160. if (child.isMesh === true) {
  161. parseMesh(child)
  162. }
  163. if (child.isLine === true) {
  164. parseLine(child)
  165. }
  166. if (child.isPoints === true) {
  167. parsePoints(child)
  168. }
  169. }
  170. })
  171. return output
  172. }
  173. }
  174. export { OBJExporter }