io_export_babylon.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. bl_info = {
  2. "name": "Babylon.js",
  3. "author": "David Catuhe",
  4. "version": (1, 0),
  5. "blender": (2, 67, 0),
  6. "location": "File > Export > Babylon.js (.babylon)",
  7. "description": "Export Babylon.js scenes (.babylon)",
  8. "warning": "",
  9. "wiki_url": "",
  10. "tracker_url": "",
  11. "category": "Import-Export"}
  12. import math
  13. import os
  14. import bpy
  15. import string
  16. import bpy_extras.io_utils
  17. from bpy.props import *
  18. import mathutils, math
  19. import struct
  20. import shutil
  21. from os import remove
  22. from bpy_extras.io_utils import (ExportHelper, axis_conversion)
  23. from bpy.props import (BoolProperty, FloatProperty, StringProperty, EnumProperty, FloatVectorProperty)
  24. class SubMesh:
  25. materialIndex = 0
  26. verticesStart = 0
  27. verticesCount = 0
  28. indexStart = 0
  29. indexCount = 0
  30. class MultiMaterial:
  31. name = ""
  32. materials = []
  33. class Export_babylon(bpy.types.Operator, ExportHelper):
  34. """Export Babylon.js scene (.babylon)"""
  35. bl_idname = "scene.babylon"
  36. bl_label = "Export Babylon.js scene"
  37. filename_ext = ".babylon"
  38. filepath = ""
  39. # global_scale = FloatProperty(name="Scale", min=0.01, max=1000.0, default=1.0)
  40. def execute(self, context):
  41. return Export_babylon.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob", "global_scale")))
  42. def mesh_triangulate(mesh):
  43. import bmesh
  44. bm = bmesh.new()
  45. bm.from_mesh(mesh)
  46. bmesh.ops.triangulate(bm, faces=bm.faces)
  47. bm.to_mesh(mesh)
  48. mesh.calc_tessface()
  49. bm.free()
  50. def write_array3(file_handler, name, array):
  51. file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(array[0],array[1],array[2]) + "]")
  52. def write_color(file_handler, name, color):
  53. file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(color.r,color.g,color.b) + "]")
  54. def write_vector(file_handler, name, vector):
  55. file_handler.write(",\""+name+"\":[" + "%.4f,%.4f,%.4f"%(vector.x,vector.z,vector.y) + "]")
  56. def write_string(file_handler, name, string, noComma=False):
  57. if noComma == False:
  58. file_handler.write(",")
  59. file_handler.write("\""+name+"\":\"" + string + "\"")
  60. def write_float(file_handler, name, float):
  61. file_handler.write(",\""+name+"\":" + "%.4f"%(float))
  62. def write_int(file_handler, name, int, noComma=False):
  63. if noComma == False:
  64. file_handler.write(",")
  65. file_handler.write("\""+name+"\":" + str(int))
  66. def write_bool(file_handler, name, bool, noComma=False):
  67. if noComma == False:
  68. file_handler.write(",")
  69. if bool:
  70. file_handler.write("\""+name+"\":" + "true")
  71. else:
  72. file_handler.write("\""+name+"\":" + "false")
  73. def getDirection(matrix):
  74. return (matrix.to_3x3() * mathutils.Vector((0.0, 0.0, -1.0))).normalized()
  75. def export_camera(object, scene, file_handler):
  76. invWorld = object.matrix_world.copy()
  77. invWorld.invert()
  78. target = mathutils.Vector((0, 1, 0)) * invWorld
  79. file_handler.write("{")
  80. Export_babylon.write_string(file_handler, "name", object.name, True)
  81. Export_babylon.write_string(file_handler, "id", object.name)
  82. Export_babylon.write_vector(file_handler, "position", object.location)
  83. Export_babylon.write_vector(file_handler, "target", target)
  84. Export_babylon.write_float(file_handler, "fov", object.data.angle)
  85. Export_babylon.write_float(file_handler, "minZ", object.data.clip_start)
  86. Export_babylon.write_float(file_handler, "maxZ", object.data.clip_end)
  87. Export_babylon.write_float(file_handler, "speed", 1.0)
  88. Export_babylon.write_float(file_handler, "inertia", 0.9)
  89. Export_babylon.write_bool(file_handler, "checkCollisions", object.data.checkCollisions)
  90. Export_babylon.write_bool(file_handler, "applyGravity", object.data.applyGravity)
  91. Export_babylon.write_array3(file_handler, "ellipsoid", object.data.ellipsoid)
  92. file_handler.write("}")
  93. def export_light(object, scene, file_handler):
  94. light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 0}
  95. light_type = light_type_items[object.data.type]
  96. file_handler.write("{")
  97. Export_babylon.write_string(file_handler, "name", object.name, True)
  98. Export_babylon.write_string(file_handler, "id", object.name)
  99. Export_babylon.write_float(file_handler, "type", light_type)
  100. if light_type == 0:
  101. Export_babylon.write_vector(file_handler, "position", object.location)
  102. elif light_type == 1:
  103. direction = Export_babylon.getDirection(object.matrix_world)
  104. Export_babylon.write_vector(file_handler, "position", object.location)
  105. Export_babylon.write_vector(file_handler, "direction", direction)
  106. elif light_type == 2:
  107. Export_babylon.write_vector(file_handler, "position", object.location)
  108. direction = Export_babylon.getDirection(object.matrix_world)
  109. Export_babylon.write_vector(file_handler, "direction", direction)
  110. Export_babylon.write_float(file_handler, "angle", object.data.spot_size)
  111. Export_babylon.write_float(file_handler, "exponent", object.data.spot_blend * 2)
  112. else:
  113. matrix_world = object.matrix_world.copy()
  114. matrix_world.translation = mathutils.Vector((0, 0, 0))
  115. direction = mathutils.Vector((0, 0, -1)) * matrix_world
  116. Export_babylon.write_vector(file_handler, "direction", -direction)
  117. Export_babylon.write_color(file_handler, "groundColor", mathutils.Color((0, 0, 0)))
  118. Export_babylon.write_float(file_handler, "intensity", object.data.energy)
  119. if object.data.use_diffuse:
  120. Export_babylon.write_color(file_handler, "diffuse", object.data.color)
  121. else:
  122. Export_babylon.write_color(file_handler, "diffuse", mathutils.Color((0, 0, 0)))
  123. if object.data.use_specular:
  124. Export_babylon.write_color(file_handler, "specular", object.data.color)
  125. else:
  126. Export_babylon.write_color(file_handler, "specular", mathutils.Color((0, 0, 0)))
  127. file_handler.write("}")
  128. def export_texture(slot, level, texture, scene, file_handler, filepath):
  129. # Copy image to output
  130. try:
  131. image = texture.texture.image
  132. imageFilepath = os.path.normpath(bpy.path.abspath(image.filepath))
  133. basename = os.path.basename(imageFilepath)
  134. targetdir = os.path.dirname(filepath)
  135. targetpath = os.path.join(targetdir, basename)
  136. if image.packed_file:
  137. image.save_render(targetpath)
  138. else:
  139. sourcepath = bpy.path.abspath(image.filepath)
  140. shutil.copy(sourcepath, targetdir)
  141. except:
  142. pass
  143. # Export
  144. file_handler.write(",\""+slot+"\":{")
  145. Export_babylon.write_string(file_handler, "name", basename, True)
  146. Export_babylon.write_float(file_handler, "level", level)
  147. Export_babylon.write_float(file_handler, "hasAlpha", texture.texture.use_alpha)
  148. coordinatesMode = 0;
  149. if (texture.mapping == "CUBE"):
  150. coordinatesMode = 3;
  151. if (texture.mapping == "SPHERE"):
  152. coordinatesMode = 1;
  153. Export_babylon.write_int(file_handler, "coordinatesMode", coordinatesMode)
  154. Export_babylon.write_float(file_handler, "uOffset", texture.offset.x)
  155. Export_babylon.write_float(file_handler, "vOffset", texture.offset.y)
  156. Export_babylon.write_float(file_handler, "uScale", texture.scale.x)
  157. Export_babylon.write_float(file_handler, "vScale", texture.scale.y)
  158. Export_babylon.write_float(file_handler, "uAng", 0)
  159. Export_babylon.write_float(file_handler, "vAng", 0)
  160. Export_babylon.write_float(file_handler, "wAng", 0)
  161. if (texture.texture.extension == "REPEAT"):
  162. Export_babylon.write_bool(file_handler, "wrapU", True)
  163. Export_babylon.write_bool(file_handler, "wrapV", True)
  164. else:
  165. Export_babylon.write_bool(file_handler, "wrapU", False)
  166. Export_babylon.write_bool(file_handler, "wrapV", False)
  167. Export_babylon.write_int(file_handler, "coordinatesIndex", 0)
  168. file_handler.write("}")
  169. def export_material(material, scene, file_handler, filepath):
  170. file_handler.write("{")
  171. Export_babylon.write_string(file_handler, "name", material.name, True)
  172. Export_babylon.write_string(file_handler, "id", material.name)
  173. Export_babylon.write_color(file_handler, "ambient", material.ambient * material.diffuse_color)
  174. Export_babylon.write_color(file_handler, "diffuse", material.diffuse_intensity * material.diffuse_color)
  175. Export_babylon.write_color(file_handler, "specular", material.specular_intensity * material.specular_color)
  176. Export_babylon.write_float(file_handler, "specularPower", material.specular_hardness)
  177. Export_babylon.write_color(file_handler, "emissive", material.emit * material.diffuse_color)
  178. Export_babylon.write_float(file_handler, "alpha", material.alpha)
  179. Export_babylon.write_bool(file_handler, "backFaceCulling", material.game_settings.use_backface_culling)
  180. # Textures
  181. for mtex in material.texture_slots:
  182. if mtex and mtex.texture and mtex.texture.type == 'IMAGE':
  183. if mtex.texture.image:
  184. if (mtex.use_map_color_diffuse and(mtex.texture_coords != 'REFLECTION')):
  185. # Diffuse
  186. Export_babylon.export_texture("diffuseTexture", mtex.diffuse_color_factor, mtex, scene, file_handler, filepath)
  187. if mtex.use_map_ambient:
  188. # Ambient
  189. Export_babylon.export_texture("ambientTexture", mtex.ambient_factor, mtex, scene, file_handler, filepath)
  190. if mtex.use_map_alpha:
  191. # Opacity
  192. Export_babylon.export_texture("opacityTexture", mtex.alpha_factor, mtex, scene, file_handler, filepath)
  193. if mtex.use_map_color_diffuse and (mtex.texture_coords == 'REFLECTION'):
  194. # Reflection
  195. Export_babylon.export_texture("reflectionTexture", mtex.diffuse_color_factor, mtex, scene, file_handler, filepath)
  196. if mtex.use_map_emit:
  197. # Emissive
  198. Export_babylon.export_texture("emissiveTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)
  199. if mtex.use_map_normal:
  200. # Bump
  201. Export_babylon.export_texture("bumpTexture", mtex.emit_factor, mtex, scene, file_handler, filepath)
  202. file_handler.write("}")
  203. def export_multimaterial(multimaterial, scene, file_handler):
  204. file_handler.write("{")
  205. Export_babylon.write_string(file_handler, "name", multimaterial.name, True)
  206. Export_babylon.write_string(file_handler, "id", multimaterial.name)
  207. file_handler.write(",\"materials\":[")
  208. first = True
  209. for materialName in multimaterial.materials:
  210. if first != True:
  211. file_handler.write(",")
  212. file_handler.write("\"" + materialName +"\"")
  213. first = False
  214. file_handler.write("]")
  215. file_handler.write("}")
  216. def export_animation(object, scene, file_handler, typeBl, typeBa, coma):
  217. if coma == True:
  218. file_handler.write(",")
  219. file_handler.write("{")
  220. Export_babylon.write_int(file_handler, "dataType", 1, True)
  221. Export_babylon.write_int(file_handler, "framePerSecond", 30)
  222. Export_babylon.write_int(file_handler, "loopBehavior", 1)
  223. Export_babylon.write_string(file_handler, "name", typeBa+" animation")
  224. Export_babylon.write_string(file_handler, "property", typeBa)
  225. file_handler.write(",\"keys\":[")
  226. frames = dict()
  227. for fcurve in object.animation_data.action.fcurves:
  228. if fcurve.data_path == typeBl:
  229. for key in fcurve.keyframe_points:
  230. frame = key.co.x
  231. frames[frame] = 1
  232. #for each frame (next step ==> set for key frames)
  233. i = 0
  234. for Frame in sorted(frames):
  235. if i == 0 and Frame != 0.0:
  236. file_handler.write("{")
  237. Export_babylon.write_int(file_handler, "frame", 0, True)
  238. bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
  239. Export_babylon.write_vector(file_handler, "values", getattr(object,typeBl))
  240. file_handler.write("},")
  241. i = i + 1
  242. file_handler.write("{")
  243. Export_babylon.write_int(file_handler, "frame", Frame, True)
  244. bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
  245. Export_babylon.write_vector(file_handler, "values", getattr(object,typeBl))
  246. file_handler.write("}")
  247. if i != len(frames):
  248. file_handler.write(",")
  249. else:
  250. file_handler.write(",{")
  251. Export_babylon.write_int(file_handler, "frame", bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1, True)
  252. bpy.context.scene.frame_set(int(Frame + bpy.context.scene.frame_start))
  253. Export_babylon.write_vector(file_handler, "values", getattr(object,typeBl))
  254. file_handler.write("}")
  255. file_handler.write("]}")
  256. def export_mesh(object, scene, file_handler, multiMaterials):
  257. # Get mesh
  258. mesh = object.to_mesh(scene, True, "PREVIEW")
  259. # Transform
  260. matrix_world = object.matrix_world.copy()
  261. matrix_world.translation = mathutils.Vector((0, 0, 0))
  262. mesh.transform(matrix_world)
  263. # Triangulate mesh if required
  264. Export_babylon.mesh_triangulate(mesh)
  265. # Getting vertices and indices
  266. positions=",\"positions\":["
  267. normals=",\"normals\":["
  268. indices=",\"indices\":["
  269. hasUV = True;
  270. hasUV2 = True;
  271. hasVertexColor = True
  272. if len(mesh.tessface_uv_textures) > 0:
  273. UVmap=mesh.tessface_uv_textures[0].data
  274. uvs=",\"uvs\":["
  275. else:
  276. hasUV = False
  277. if len(mesh.tessface_uv_textures) > 1:
  278. UV2map=mesh.tessface_uv_textures[1].data
  279. uvs2=",\"uvs2\":["
  280. else:
  281. hasUV2 = False
  282. if len(mesh.vertex_colors) > 0:
  283. Colormap = mesh.tessface_vertex_colors.active.data
  284. colors=",\"colors\":["
  285. else:
  286. hasVertexColor = False
  287. alreadySavedVertices = []
  288. vertices_UVs=[]
  289. vertices_UV2s=[]
  290. vertices_Colors=[]
  291. vertices_indices=[]
  292. subMeshes = []
  293. for v in range(0, len(mesh.vertices)):
  294. alreadySavedVertices.append(False)
  295. vertices_UVs.append([])
  296. vertices_UV2s.append([])
  297. vertices_Colors.append([])
  298. vertices_indices.append([])
  299. materialsCount = max(1, len(object.material_slots))
  300. verticesCount = 0
  301. indicesCount = 0
  302. for materialIndex in range(materialsCount):
  303. subMeshes.append(SubMesh())
  304. subMeshes[materialIndex].materialIndex = materialIndex
  305. subMeshes[materialIndex].verticesStart = verticesCount
  306. subMeshes[materialIndex].indexStart = indicesCount
  307. for face in mesh.tessfaces: # For each face
  308. if face.material_index != materialIndex:
  309. continue
  310. for v in range(3): # For each vertex in face
  311. vertex_index = face.vertices[v]
  312. vertex = mesh.vertices[vertex_index]
  313. position = vertex.co
  314. normal = vertex.normal
  315. if hasUV:
  316. vertex_UV = UVmap[face.index].uv[v]
  317. if hasUV2:
  318. vertex_UV2 = UV2map[face.index].uv[v]
  319. if hasVertexColor:
  320. if v == 0:
  321. vertex_Color = Colormap[face.index].color1
  322. if v == 1:
  323. vertex_Color = Colormap[face.index].color2
  324. if v == 2:
  325. vertex_Color = Colormap[face.index].color3
  326. # Check if the current vertex is already saved
  327. alreadySaved = alreadySavedVertices[vertex_index]
  328. if alreadySaved:
  329. alreadySaved=False
  330. # UV
  331. index_UV = 0
  332. for savedIndex in vertices_indices[vertex_index]:
  333. if hasUV:
  334. vUV = vertices_UVs[vertex_index][index_UV]
  335. if (vUV[0]!=vertex_UV[0] or vUV[1]!=vertex_UV[1]):
  336. continue
  337. if hasUV2:
  338. vUV2 = vertices_UV2s[vertex_index][index_UV]
  339. if (vUV2[0]!=vertex_UV2[0] or vUV2[1]!=vertex_UV2[1]):
  340. continue
  341. if hasVertexColor:
  342. vColor = vertices_Colors[vertex_index][index_UV]
  343. if (vColor.r!=vertex_Color.r or vColor.g!=vertex_Color.g or vColor.b!=vertex_Color.b):
  344. continue
  345. if vertices_indices[vertex_index][index_UV] >= subMeshes[materialIndex].verticesStart:
  346. alreadySaved=True
  347. break
  348. index_UV+=1
  349. if (alreadySaved):
  350. # Reuse vertex
  351. index=vertices_indices[vertex_index][index_UV]
  352. else:
  353. # Export new one
  354. index=verticesCount
  355. alreadySavedVertices[vertex_index]=True
  356. if hasUV:
  357. vertices_UVs[vertex_index].append(vertex_UV)
  358. uvs+="%.4f,%.4f,"%(vertex_UV[0], vertex_UV[1])
  359. if hasUV2:
  360. vertices_UV2s[vertex_index].append(vertex_UV2)
  361. uvs2+="%.4f,%.4f,"%(vertex_UV2[0], vertex_UV2[1])
  362. if hasVertexColor:
  363. vertices_Colors[vertex_index].append(vertex_Color)
  364. colors+="%.4f,%.4f,%.4f,"%(vertex_Color.r,vertex_Color.g,vertex_Color.b)
  365. vertices_indices[vertex_index].append(index)
  366. positions+="%.4f,%.4f,%.4f,"%(position.x,position.z,position.y)
  367. normals+="%.4f,%.4f,%.4f,"%(normal.x,normal.z,normal.y)
  368. verticesCount += 1
  369. indices+="%i,"%(index)
  370. indicesCount += 1
  371. subMeshes[materialIndex].verticesCount = verticesCount - subMeshes[materialIndex].verticesStart
  372. subMeshes[materialIndex].indexCount = indicesCount - subMeshes[materialIndex].indexStart
  373. positions=positions.rstrip(',')
  374. normals=normals.rstrip(',')
  375. indices=indices.rstrip(',')
  376. positions+="]\n"
  377. normals+="]\n"
  378. indices+="]\n"
  379. if hasUV:
  380. uvs=uvs.rstrip(',')
  381. uvs+="]\n"
  382. if hasUV2:
  383. uvs2=uvs.rstrip(',')
  384. uvs2+="]\n"
  385. if hasVertexColor:
  386. colors=uvs.rstrip(',')
  387. colors+="]\n"
  388. # Writing mesh
  389. file_handler.write("{")
  390. Export_babylon.write_string(file_handler, "name", object.name, True)
  391. Export_babylon.write_string(file_handler, "id", object.name)
  392. if object.parent != None:
  393. Export_babylon.write_string(file_handler, "parentId", object.parent.name)
  394. if len(object.material_slots) == 1:
  395. material = object.material_slots[0].material
  396. Export_babylon.write_string(file_handler, "materialId", object.material_slots[0].name)
  397. if material.game_settings.face_orientation != "BILLBOARD":
  398. billboardMode = 0
  399. else:
  400. billboardMode = 7
  401. elif len(object.material_slots) > 1:
  402. multimat = MultiMaterial()
  403. multimat.name = "Multimaterial#" + str(len(multiMaterials))
  404. Export_babylon.write_string(file_handler, "materialId", multimat.name)
  405. for mat in object.material_slots:
  406. multimat.materials.append(mat.name)
  407. multiMaterials.append(multimat)
  408. billboardMode = 0
  409. else:
  410. billboardMode = 0
  411. Export_babylon.write_vector(file_handler, "position", object.location)
  412. Export_babylon.write_vector(file_handler, "rotation", mathutils.Vector((0, 0, 0)))
  413. Export_babylon.write_vector(file_handler, "scaling", mathutils.Vector((1, 1, 1)))
  414. Export_babylon.write_bool(file_handler, "isVisible", object.is_visible(scene))
  415. Export_babylon.write_bool(file_handler, "isEnabled", True)
  416. Export_babylon.write_bool(file_handler, "checkCollisions", object.data.checkCollisions)
  417. Export_babylon.write_int(file_handler, "billboardMode", billboardMode)
  418. Export_babylon.write_bool(file_handler, "receiveShadows", object.data.receiveShadows)
  419. file_handler.write(positions)
  420. file_handler.write(normals)
  421. if hasUV:
  422. file_handler.write(uvs)
  423. if hasUV2:
  424. file_handler.write(uvs2)
  425. if hasVertexColor:
  426. file_handler.write(colors)
  427. file_handler.write(indices)
  428. # Sub meshes
  429. file_handler.write(",\"subMeshes\":[")
  430. first = True
  431. for subMesh in subMeshes:
  432. if first == False:
  433. file_handler.write(",")
  434. file_handler.write("{")
  435. Export_babylon.write_int(file_handler, "materialIndex", subMesh.materialIndex, True)
  436. Export_babylon.write_int(file_handler, "verticesStart", subMesh.verticesStart)
  437. Export_babylon.write_int(file_handler, "verticesCount", subMesh.verticesCount)
  438. Export_babylon.write_int(file_handler, "indexStart", subMesh.indexStart)
  439. Export_babylon.write_int(file_handler, "indexCount", subMesh.indexCount)
  440. file_handler.write("}")
  441. first = False
  442. file_handler.write("]")
  443. #Export Animations
  444. rotAnim = False
  445. locAnim = False
  446. scaAnim = False
  447. coma = False
  448. if object.animation_data:
  449. if object.animation_data.action:
  450. file_handler.write(",\"animations\":[")
  451. for fcurve in object.animation_data.action.fcurves:
  452. if fcurve.data_path == "rotation_euler" and rotAnim == False:
  453. Export_babylon.export_animation(object, scene, file_handler, "rotation_euler", "rotation", coma)
  454. rotAnim = coma = True
  455. elif fcurve.data_path == "location" and locAnim == False:
  456. Export_babylon.export_animation(object, scene, file_handler, "location", "position", coma)
  457. locAnim = coma = True
  458. elif fcurve.data_path == "scale" and scaAnim == False:
  459. Export_babylon.export_animation(object, scene, file_handler, "scale", "scaling", coma)
  460. locAnim = coma = True
  461. file_handler.write("]")
  462. #Set Animations
  463. Export_babylon.write_bool(file_handler, "autoAnimate", True)
  464. Export_babylon.write_int(file_handler, "autoAnimateFrom", 0)
  465. Export_babylon.write_int(file_handler, "autoAnimateTo", bpy.context.scene.frame_end - bpy.context.scene.frame_start + 1)
  466. Export_babylon.write_bool(file_handler, "autoAnimateLoop", True)
  467. # Closing
  468. file_handler.write("}")
  469. def export_shadowGenerator(lamp, scene, file_handler):
  470. file_handler.write("{")
  471. if lamp.data.shadowMap == 'VAR':
  472. Export_babylon.write_bool(file_handler, "useVarianceShadowMap", True, True)
  473. else:
  474. Export_babylon.write_bool(file_handler, "useVarianceShadowMap", False, True)
  475. Export_babylon.write_int(file_handler, "mapSize", lamp.data.shadowMapSize)
  476. Export_babylon.write_string(file_handler, "lightId", lamp.name)
  477. file_handler.write(",\"renderList\":[")
  478. multiMaterials = []
  479. first = True
  480. for object in [object for object in scene.objects]:
  481. if (object.type == 'MESH' and object.data.castShadows):
  482. if first != True:
  483. file_handler.write(",")
  484. first = False
  485. file_handler.write("\"" + object.name + "\"")
  486. file_handler.write("]")
  487. file_handler.write("}")
  488. def save(operator, context, filepath="",
  489. use_apply_modifiers=False,
  490. use_triangulate=True,
  491. use_compress=False):
  492. # Open file
  493. file_handler = open(filepath, 'w')
  494. if bpy.ops.object.mode_set.poll():
  495. bpy.ops.object.mode_set(mode='OBJECT')
  496. # Writing scene
  497. scene=context.scene
  498. world = scene.world
  499. if world:
  500. world_ambient = world.ambient_color
  501. else:
  502. world_ambient = Color((0.0, 0.0, 0.0))
  503. file_handler.write("{")
  504. file_handler.write("\"autoClear\":true")
  505. Export_babylon.write_color(file_handler, "clearColor", world_ambient)
  506. Export_babylon.write_color(file_handler, "ambientColor", world_ambient)
  507. Export_babylon.write_vector(file_handler, "gravity", scene.gravity)
  508. if world and world.mist_settings.use_mist:
  509. Export_babylon.write_int(file_handler, "fogMode", 3)
  510. Export_babylon.write_color(file_handler, "fogColor", world.horizon_color)
  511. Export_babylon.write_float(file_handler, "fogStart", world.mist_settings.start)
  512. Export_babylon.write_float(file_handler, "fogEnd", world.mist_settings.depth)
  513. Export_babylon.write_float(file_handler, "fogDensity", 0.1)
  514. # Cameras
  515. file_handler.write(",\"cameras\":[")
  516. first = True
  517. for object in [object for object in scene.objects if object.is_visible(scene)]:
  518. if (object.type == 'CAMERA'):
  519. if first != True:
  520. file_handler.write(",")
  521. first = False
  522. data_string = Export_babylon.export_camera(object, scene, file_handler)
  523. file_handler.write("]")
  524. # Active camera
  525. if scene.camera != None:
  526. Export_babylon.write_string(file_handler, "activeCamera", scene.camera.name)
  527. # Lights
  528. file_handler.write(",\"lights\":[")
  529. first = True
  530. for object in [object for object in scene.objects if object.is_visible(scene)]:
  531. if (object.type == 'LAMP'):
  532. if first != True:
  533. file_handler.write(",")
  534. first = False
  535. data_string = Export_babylon.export_light(object, scene, file_handler)
  536. file_handler.write("]")
  537. # Materials
  538. materials = [mat for mat in bpy.data.materials if mat.users >= 1]
  539. file_handler.write(",\"materials\":[")
  540. first = True
  541. for material in materials:
  542. if first != True:
  543. file_handler.write(",")
  544. first = False
  545. data_string = Export_babylon.export_material(material, scene, file_handler, filepath)
  546. file_handler.write("]")
  547. # Meshes
  548. file_handler.write(",\"meshes\":[")
  549. multiMaterials = []
  550. first = True
  551. for object in [object for object in scene.objects]:
  552. if (object.type == 'MESH'):
  553. if first != True:
  554. file_handler.write(",")
  555. first = False
  556. data_string = Export_babylon.export_mesh(object, scene, file_handler, multiMaterials)
  557. file_handler.write("]")
  558. # Multi-materials
  559. file_handler.write(",\"multiMaterials\":[")
  560. first = True
  561. for multimaterial in multiMaterials:
  562. if first != True:
  563. file_handler.write(",")
  564. first = False
  565. data_string = Export_babylon.export_multimaterial(multimaterial, scene, file_handler)
  566. file_handler.write("]")
  567. # Shadow generators
  568. file_handler.write(",\"shadowGenerators\":[")
  569. first = True
  570. for object in [object for object in scene.objects if object.is_visible(scene)]:
  571. if (object.type == 'LAMP' and object.data.shadowMap != 'NONE'):
  572. if first != True:
  573. file_handler.write(",")
  574. first = False
  575. data_string = Export_babylon.export_shadowGenerator(object, scene, file_handler)
  576. file_handler.write("]")
  577. # Closing
  578. file_handler.write("}")
  579. file_handler.close()
  580. return {'FINISHED'}
  581. # UI
  582. bpy.types.Mesh.checkCollisions = BoolProperty(
  583. name="Check Collisions",
  584. default = False)
  585. bpy.types.Mesh.castShadows = BoolProperty(
  586. name="Cast Shadows",
  587. default = False)
  588. bpy.types.Mesh.receiveShadows = BoolProperty(
  589. name="Receive Shadows",
  590. default = False)
  591. bpy.types.Camera.checkCollisions = BoolProperty(
  592. name="Check Collisions",
  593. default = False)
  594. bpy.types.Camera.applyGravity = BoolProperty(
  595. name="Apply Gravity",
  596. default = False)
  597. bpy.types.Camera.ellipsoid = FloatVectorProperty(
  598. name="Ellipsoid",
  599. default = mathutils.Vector((0.2, 0.9, 0.2)))
  600. bpy.types.Lamp.shadowMap = EnumProperty(
  601. name="Shadow Map Type",
  602. items = (('NONE', "None", "No Shadow Maps"), ('STD', "Standard", "Use Standard Shadow Maps"), ('VAR', "Variance", "Use Variance Shadow Maps")),
  603. default = 'NONE')
  604. bpy.types.Lamp.shadowMapSize = IntProperty(
  605. name="Shadow Map Size",
  606. default = 512)
  607. class ObjectPanel(bpy.types.Panel):
  608. bl_label = "Babylon.js"
  609. bl_space_type = "PROPERTIES"
  610. bl_region_type = "WINDOW"
  611. bl_context = "data"
  612. def draw(self, context):
  613. ob = context.object
  614. if not ob or not ob.data:
  615. return
  616. layout = self.layout
  617. isMesh = isinstance(ob.data, bpy.types.Mesh)
  618. isCamera = isinstance(ob.data, bpy.types.Camera)
  619. isLight = isinstance(ob.data, bpy.types.Lamp)
  620. if isMesh:
  621. layout.prop(ob.data, 'checkCollisions')
  622. layout.prop(ob.data, 'castShadows')
  623. layout.prop(ob.data, 'receiveShadows')
  624. elif isCamera:
  625. layout.prop(ob.data, 'checkCollisions')
  626. layout.prop(ob.data, 'applyGravity')
  627. layout.prop(ob.data, 'ellipsoid')
  628. elif isLight:
  629. layout.prop(ob.data, 'shadowMap')
  630. layout.prop(ob.data, 'shadowMapSize')
  631. ### REGISTER ###
  632. def menu_func(self, context):
  633. self.layout.operator(Export_babylon.bl_idname, text="Babylon.js (.babylon)")
  634. def register():
  635. bpy.utils.register_module(__name__)
  636. bpy.types.INFO_MT_file_export.append(menu_func)
  637. def unregister():
  638. bpy.utils.unregister_module(__name__)
  639. bpy.types.INFO_MT_file_export.remove(menu_func)
  640. if __name__ == "__main__":
  641. register()