export_threejs.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. __author__ = "Mr.doob"
  2. __url__ = ("http://mrdoob.com")
  3. __version__ = "1"
  4. __bpydoc__ = """\
  5. This script exports the selected object for the three.js engine.
  6. """
  7. import bpy
  8. def rvec3d(v):
  9. return round(v[0], 6), round(v[1], 6), round(v[2], 6)
  10. def rvec2d(v):
  11. return round(v[0], 6), round(v[1], 6)
  12. def write(filename, scene, ob, \
  13. EXPORT_APPLY_MODIFIERS=True,\
  14. EXPORT_NORMALS=True,\
  15. EXPORT_UV=True,\
  16. EXPORT_COLORS=True):
  17. if not filename.lower().endswith('.js'):
  18. filename += '.js'
  19. classname = ob.name
  20. if not ob:
  21. raise Exception("Error, Select the object to export")
  22. return
  23. file = open(filename, 'w')
  24. if EXPORT_APPLY_MODIFIERS:
  25. mesh = ob.create_mesh(True, 'PREVIEW')
  26. else:
  27. mesh = ob.data
  28. if not mesh:
  29. raise ("Error, could not get mesh data from selected object")
  30. return
  31. faceUV = len(mesh.uv_textures) > 0
  32. vertexUV = len(mesh.sticky) > 0
  33. vertexColors = len(mesh.vertex_colors) > 0
  34. if (not faceUV) and (not vertexUV):
  35. EXPORT_UV = False
  36. if not vertexColors:
  37. EXPORT_COLORS = False
  38. if not EXPORT_UV:
  39. faceUV = vertexUV = False
  40. if not EXPORT_COLORS:
  41. vertexColors = False
  42. if faceUV:
  43. active_uv_layer = mesh.active_uv_texture
  44. if not active_uv_layer:
  45. EXPORT_UV = False
  46. faceUV = None
  47. else:
  48. active_uv_layer = active_uv_layer.data
  49. if vertexColors:
  50. active_col_layer = mesh.active_vertex_color
  51. if not active_col_layer:
  52. EXPORT_COLORS = False
  53. vertexColors = None
  54. else:
  55. active_col_layer = active_col_layer.data
  56. # incase
  57. color = uvcoord = uvcoord_key = normal = normal_key = None
  58. file.write('var %s = function () {\n\n' % classname)
  59. file.write('\tvar scope = this;\n\n')
  60. file.write('\tTHREE.Geometry.call(this);\n\n')
  61. for v in mesh.verts:
  62. file.write('\tv( %.6f, %.6f, %.6f );\n' % (v.co.x, v.co.z, -v.co.y)) # co
  63. file.write('\n')
  64. if EXPORT_NORMALS:
  65. for f in mesh.faces:
  66. if len(f.verts) == 3:
  67. file.write('\tf3n( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.verts[0], f.verts[1], f.verts[2], f.normal[0], f.normal[1], f.normal[2]))
  68. else:
  69. file.write('\tf3n( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.verts[3], f.verts[1], f.verts[2], f.normal[0], f.normal[1], f.normal[2]))
  70. file.write('\tf3n( %d, %d, %d, %.6f, %.6f, %.6f );\n' % (f.verts[1], f.verts[3], f.verts[0], f.normal[0], f.normal[1], f.normal[2]))
  71. else:
  72. for f in mesh.faces:
  73. if len(f.verts) == 3:
  74. file.write('\tf3( %d, %d, %d );\n' % (f.verts[0], f.verts[1], f.verts[2]))
  75. else:
  76. file.write('\tf3( %d, %d, %d );\n' % (f.verts[2], f.verts[1], f.verts[3]))
  77. file.write('\tf3( %d, %d, %d );\n' % (f.verts[0], f.verts[3], f.verts[1]))
  78. face_index_pairs = [ (face, index) for index, face in enumerate(mesh.faces)]
  79. if EXPORT_UV:
  80. file.write('\n')
  81. for f, f_index in face_index_pairs:
  82. tface = mesh.uv_textures[0].data[f_index]
  83. if len(f.verts) == 3:
  84. file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv1[0], 1.0-tface.uv1[1], tface.uv2[0], 1.0-tface.uv2[1], tface.uv3[0], 1.0-tface.uv3[1]))
  85. else:
  86. file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv4[0], 1.0-tface.uv4[1], tface.uv2[0], 1.0-tface.uv2[1], tface.uv3[0], 1.0-tface.uv3[1]))
  87. file.write('\tuv( %.6f, %.6f, %.6f, %.6f, %.6f, %.6f );\n' % (tface.uv2[0], 1.0-tface.uv2[1], tface.uv4[0], 1.0-tface.uv4[1], tface.uv1[0], 1.0-tface.uv1[1]))
  88. file.write('\n')
  89. file.write('\tfunction v( x, y, z ) {\n\n')
  90. file.write('\t\tscope.vertices.push( new THREE.Vertex( new THREE.Vector3( x, y, z ) ) );\n\n')
  91. file.write('\t}\n\n')
  92. file.write('\tfunction f3( a, b, c ) {\n\n')
  93. file.write('\t\tscope.faces.push( new THREE.Face3( a, b, c ) );\n\n')
  94. file.write('\t}\n\n')
  95. file.write('\tfunction f3n( a, b, c, nx, ny, nz ) {\n\n')
  96. file.write('\t\tscope.faces.push( new THREE.Face3( a, b, c, new THREE.Vector3( nx, ny, nz ) ) );\n\n')
  97. file.write('\t}\n\n')
  98. file.write('\tfunction uv( u1, v1, u2, v2, u3, v3 ) {\n\n')
  99. file.write('\t\tscope.uvs.push( [ \n\n')
  100. file.write('\t\t\t new THREE.Vector2( u1, v1 ), \n')
  101. file.write('\t\t\t new THREE.Vector2( u2, v2 ), \n')
  102. file.write('\t\t\t new THREE.Vector2( u3, v3 ) \n')
  103. file.write('\t\t]);\n')
  104. file.write('\t}\n\n')
  105. file.write('}\n\n')
  106. file.write('%s.prototype = new THREE.Geometry();\n' % classname)
  107. file.write('%s.prototype.constructor = %s;' % (classname, classname))
  108. file.close()
  109. print("writing", filename, "done")
  110. if EXPORT_APPLY_MODIFIERS:
  111. bpy.data.meshes.remove(mesh)
  112. from bpy.props import *
  113. class ExportTHREEJS(bpy.types.Operator):
  114. '''TODO'''
  115. bl_idname = "export.three_js"
  116. bl_label = "Export three.js"
  117. # List of operator properties, the attributes will be assigned
  118. # to the class instance from the operator settings before calling.
  119. path = StringProperty(name="File Path", description="File path used for exporting the PLY file", maxlen=1024, default="")
  120. check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
  121. use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
  122. use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
  123. use_uvs = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
  124. use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
  125. def poll(self, context):
  126. return context.active_object != None
  127. def execute(self, context):
  128. print("Selected: " + context.active_object.name)
  129. if not self.properties.path:
  130. raise Exception("filename not set")
  131. write(self.properties.path, context.scene, context.active_object,\
  132. EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
  133. EXPORT_NORMALS=self.properties.use_normals,
  134. EXPORT_UV=self.properties.use_uvs,
  135. EXPORT_COLORS=self.properties.use_colors,
  136. )
  137. return {'FINISHED'}
  138. def invoke(self, context, event):
  139. wm = context.manager
  140. wm.add_fileselect(self)
  141. return {'RUNNING_MODAL'}
  142. def draw(self, context):
  143. layout = self.layout
  144. props = self.properties
  145. row = layout.row()
  146. row.prop(props, "use_modifiers")
  147. row.prop(props, "use_normals")
  148. row = layout.row()
  149. row.prop(props, "use_uvs")
  150. row.prop(props, "use_colors")
  151. def menu_func(self, context):
  152. default_path = bpy.data.filename.replace(".blend", ".js")
  153. self.layout.operator(ExportTHREEJS.bl_idname, text="three.js (.js)").path = default_path
  154. def register():
  155. bpy.types.register(ExportTHREEJS)
  156. bpy.types.INFO_MT_file_export.append(menu_func)
  157. def unregister():
  158. bpy.types.unregister(ExportTHREEJS)
  159. bpy.types.INFO_MT_file_export.remove(menu_func)
  160. if __name__ == "__main__":
  161. register()