1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
21 ###############################################################################
22 #234567890123456789012345678901234567890123456789012345678901234567890123456789
23 #--------1---------2---------3---------4---------5---------6---------7---------
26 # ##### BEGIN COPYRIGHT BLOCK #####
28 # initial script copyright (c)2011-2013 Alexander Nussbaumer
30 # ##### END COPYRIGHT BLOCK #####
35 from mathutils
import (
50 # import io_scene_ms3d stuff
51 from io_scene_ms3d
.ms3d_strings
import (
54 from io_scene_ms3d
.ms3d_spec
import (
61 from io_scene_ms3d
.ms3d_utils
import (
65 pre_setup_environment
,
66 post_setup_environment
,
67 get_edge_split_modifier_add_if
,
69 from io_scene_ms3d
.ms3d_ui
import (
79 from bpy_extras
.image_utils
import (
84 ###############################################################################
87 FORMAT_TEXTURE
= "{}.tex"
88 # keep material name like it is (prevent name "snakes" on re-import)
89 #FORMAT_MATERIAL = "{}.mat"
90 FORMAT_MATERIAL
= "{}"
91 FORMAT_ACTION
= "{}.act"
93 FORMAT_MESH_OBJECT
= "{}.mo"
94 FORMAT_EMPTY_OBJECT
= "{}.eo"
95 FORMAT_ARMATURE
= "{}.a"
96 FORMAT_ARMATURE_OBJECT
= "{}.ao"
97 FORMAT_ARMATURE_NLA
= "{}.an"
99 ###############################################################################
100 class Ms3dImporter():
102 Load a MilkShape3D MS3D File
107 use_extended_normal_handling
=False,
109 use_quaternion_rotation
=False,
110 use_joint_size
=False,
112 use_joint_to_bones
=False,
115 self
.options_verbose
= verbose
116 self
.options_use_extended_normal_handling
= use_extended_normal_handling
117 self
.options_use_animation
= use_animation
118 self
.options_use_quaternion_rotation
= use_quaternion_rotation
119 self
.options_use_joint_size
= use_joint_size
120 self
.options_joint_size
= joint_size
121 self
.options_use_joint_to_bones
= use_joint_to_bones
122 self
.directory_name
= ""
126 ###########################################################################
127 # create empty blender ms3d_model
129 # fill blender with ms3d_model content
130 def read(self
, blender_context
, filepath
):
131 """ read ms3d file and convert ms3d content to bender content """
134 self
.has_textures
= False
138 pre_setup_environment(self
, blender_context
)
140 # inject splitted filepath
141 self
.directory_name
, self
.file_name
= path
.split(filepath
)
143 # create an empty ms3d template
144 ms3d_model
= Ms3dModel(self
.file_name
)
148 with io
.FileIO(filepath
, 'rb') as raw_io
:
149 # read and inject ms3d data from disk to internal structure
150 debug_out
= ms3d_model
.read(raw_io
)
153 if self
.options_verbose
in Ms3dUi
.VERBOSE_MAXIMAL
:
158 # if option is set, this time will enlarges the io time
159 if self
.options_verbose
in Ms3dUi
.VERBOSE_MAXIMAL
:
160 ms3d_model
.print_internal()
164 is_valid
, statistics
= ms3d_model
.is_valid()
167 # inject ms3d data to blender
168 self
.to_blender(blender_context
, ms3d_model
)
170 post_setup_environment(self
, blender_context
)
172 if self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
174 print("##########################################################")
175 print("Import from MS3D to Blender")
177 print("##########################################################")
179 except Ms3dHeader
.HeaderError
:
180 msg
= "read - invalid file format."
181 if self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
184 self
.report({'WARNING', 'ERROR', }, msg
)
189 type, value
, traceback
= exc_info()
190 if self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
191 print("read - exception in try block\n type: '{0}'\n"
192 " value: '{1}'".format(type, value
, traceback
))
194 self
.report({'WARNING', 'ERROR', }, "read - exception.")
206 if self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
207 print(ms3d_str
['SUMMARY_IMPORT'].format(
208 (t3
- t1
), (t2
- t1
), (t3
- t2
)))
213 ###########################################################################
214 def to_blender(self
, blender_context
, ms3d_model
):
215 blender_mesh_object
= self
.create_geometry(blender_context
, ms3d_model
)
216 blender_armature_object
= self
.create_animation(
217 blender_context
, ms3d_model
, blender_mesh_object
)
219 blender_empty_object
= self
.organize_objects(
220 blender_context
, ms3d_model
,
221 [blender_mesh_object
, blender_armature_object
])
223 return blender_empty_object
, blender_mesh_object
226 ###########################################################################
227 def organize_objects(self
, blender_context
, ms3d_model
, blender_objects
):
228 ##########################
229 # blender_armature_object to blender_mesh_object
230 # that has bad side effects to the armature
231 # and causes cyclic dependencies
232 ###blender_armature_object.parent = blender_mesh_object
233 ###blender_mesh_object.parent = blender_armature_object
235 blender_scene
= blender_context
.scene
237 blender_group
= blender_context
.blend_data
.groups
.new(
238 FORMAT_GROUP
.format(ms3d_model
.name
))
239 blender_empty_object
= blender_context
.blend_data
.objects
.new(
240 FORMAT_EMPTY_OBJECT
.format(ms3d_model
.name
), None)
241 blender_empty_object
.location
= blender_scene
.cursor_location
242 blender_scene
.objects
.link(blender_empty_object
)
243 blender_group
.objects
.link(blender_empty_object
)
245 for blender_object
in blender_objects
:
246 if blender_object
is not None:
247 blender_group
.objects
.link(blender_object
)
248 blender_object
.parent
= blender_empty_object
250 return blender_empty_object
253 ###########################################################################
254 def create_geometry(self
, blender_context
, ms3d_model
):
255 ##########################
257 # create a blender Mesh
258 blender_mesh
= blender_context
.blend_data
.meshes
.new(
259 FORMAT_MESH
.format(ms3d_model
.name
))
260 blender_mesh
.ms3d
.name
= ms3d_model
.name
262 ms3d_comment
= ms3d_model
.comment_object
263 if ms3d_comment
is not None:
264 blender_mesh
.ms3d
.comment
= ms3d_comment
.comment
265 ms3d_model_ex
= ms3d_model
.model_ex_object
266 if ms3d_model_ex
is not None:
267 blender_mesh
.ms3d
.joint_size
= ms3d_model_ex
.joint_size
268 blender_mesh
.ms3d
.alpha_ref
= ms3d_model_ex
.alpha_ref
269 blender_mesh
.ms3d
.transparency_mode \
270 = Ms3dUi
.transparency_mode_from_ms3d(
271 ms3d_model_ex
.transparency_mode
)
273 ##########################
275 # link to blender object
276 blender_mesh_object
= blender_context
.blend_data
.objects
.new(
277 FORMAT_MESH_OBJECT
.format(ms3d_model
.name
), blender_mesh
)
279 ##########################
281 # create edge split modifier, to make sharp edges visible
282 blender_modifier
= get_edge_split_modifier_add_if(blender_mesh_object
)
284 ##########################
286 # link to blender scene
287 blender_scene
= blender_context
.scene
288 blender_scene
.objects
.link(blender_mesh_object
)
289 #blender_mesh_object.location = blender_scene.cursor_location
290 enable_edit_mode(False, blender_context
)
292 blender_mesh_object
.select
= True
293 blender_scene
.objects
.active
= blender_mesh_object
295 ##########################
296 # take this as active object after import
297 self
.active_object
= blender_mesh_object
299 ##########################
301 # create all (ms3d) groups
302 ms3d_to_blender_group_index
= {}
303 blender_group_manager
= blender_mesh
.ms3d
304 for ms3d_group_index
, ms3d_group
in enumerate(ms3d_model
.groups
):
305 blender_group
= blender_group_manager
.create_group()
306 blender_group
.name
= ms3d_group
.name
307 blender_group
.flags
= Ms3dUi
.flags_from_ms3d(ms3d_group
.flags
)
308 blender_group
.material_index
= ms3d_group
.material_index
310 ms3d_comment
= ms3d_group
.comment_object
311 if ms3d_comment
is not None:
312 blender_group
.comment
= ms3d_comment
.comment
314 # translation dictionary
315 ms3d_to_blender_group_index
[ms3d_group_index
] = blender_group
.id
317 ####################################################
321 ##########################
323 # create an empty BMesh
326 ##########################
328 # create new Layers for custom data per "mesh face"
329 layer_texture
= bm
.faces
.layers
.tex
.get(
330 ms3d_str
['OBJECT_LAYER_TEXTURE'])
331 if layer_texture
is None:
332 layer_texture
= bm
.faces
.layers
.tex
.new(
333 ms3d_str
['OBJECT_LAYER_TEXTURE'])
335 layer_smoothing_group
= bm
.faces
.layers
.int.get(
336 ms3d_str
['OBJECT_LAYER_SMOOTHING_GROUP'])
337 if layer_smoothing_group
is None:
338 layer_smoothing_group
= bm
.faces
.layers
.int.new(
339 ms3d_str
['OBJECT_LAYER_SMOOTHING_GROUP'])
341 layer_group
= bm
.faces
.layers
.int.get(
342 ms3d_str
['OBJECT_LAYER_GROUP'])
343 if layer_group
is None:
344 layer_group
= bm
.faces
.layers
.int.new(
345 ms3d_str
['OBJECT_LAYER_GROUP'])
347 ##########################
349 # create new Layers for custom data per "face vertex"
350 layer_uv
= bm
.loops
.layers
.uv
.get(ms3d_str
['OBJECT_LAYER_UV'])
352 layer_uv
= bm
.loops
.layers
.uv
.new(ms3d_str
['OBJECT_LAYER_UV'])
354 ##########################
356 # create new Layers for custom data per "vertex"
357 layer_extra
= bm
.verts
.layers
.int.get(ms3d_str
['OBJECT_LAYER_EXTRA'])
358 if layer_extra
is None:
359 layer_extra
= bm
.verts
.layers
.int.new(ms3d_str
['OBJECT_LAYER_EXTRA'])
361 ##########################
363 # create all vertices
364 for ms3d_vertex_index
, ms3d_vertex
in enumerate(ms3d_model
.vertices
):
365 bmv
= bm
.verts
.new(self
.geometry_correction(ms3d_vertex
.vertex
))
366 bmv
.index
= ms3d_vertex_index
368 if layer_extra
and ms3d_vertex
.vertex_ex_object
and \
369 (isinstance(ms3d_vertex
.vertex_ex_object
, Ms3dVertexEx2
) \
370 or isinstance(ms3d_vertex
.vertex_ex_object
, Ms3dVertexEx3
)):
372 #bmv[layer_extra] = ms3d_vertex.vertex_ex_object.extra
373 # bm.verts.layers.int does only support signed int32
374 # convert unsigned int32 to signed int32 (little-endian)
375 unsigned_int32
= ms3d_vertex
.vertex_ex_object
.extra
376 bytes_int32
= unsigned_int32
.to_bytes(
377 4, byteorder
='little', signed
=False)
378 signed_int32
= int.from_bytes(
379 bytes_int32
, byteorder
='little', signed
=True)
380 bmv
[layer_extra
] = signed_int32
382 ##########################
383 # blender stuff (uses BMesh stuff):
384 # create all materials / image textures
385 ms3d_to_blender_material
= {}
386 for ms3d_material_index
, ms3d_material
in enumerate(
387 ms3d_model
.materials
):
388 blender_material
= blender_context
.blend_data
.materials
.new(
389 FORMAT_MATERIAL
.format(ms3d_material
.name
))
392 blender_material
.ms3d
.name
= ms3d_material
.name
393 blender_material
.ms3d
.ambient
= ms3d_material
.ambient
394 blender_material
.ms3d
.diffuse
= ms3d_material
.diffuse
395 blender_material
.ms3d
.specular
= ms3d_material
.specular
396 blender_material
.ms3d
.emissive
= ms3d_material
.emissive
397 blender_material
.ms3d
.shininess
= ms3d_material
.shininess
398 blender_material
.ms3d
.transparency
= ms3d_material
.transparency
399 blender_material
.ms3d
.mode
= Ms3dUi
.texture_mode_from_ms3d(
402 if ms3d_material
.texture
:
403 blender_material
.ms3d
.texture
= ms3d_material
.texture
405 if ms3d_material
.alphamap
:
406 blender_material
.ms3d
.alphamap
= ms3d_material
.alphamap
408 ms3d_comment
= ms3d_material
.comment_object
409 if ms3d_comment
is not None:
410 blender_material
.ms3d
.comment
= ms3d_comment
.comment
413 blender_material
.ambient
= (
414 (ms3d_material
.ambient
[0]
415 + ms3d_material
.ambient
[1]
416 + ms3d_material
.ambient
[2]) / 3.0)
418 blender_material
.diffuse_color
[0] = ms3d_material
.diffuse
[0]
419 blender_material
.diffuse_color
[1] = ms3d_material
.diffuse
[1]
420 blender_material
.diffuse_color
[2] = ms3d_material
.diffuse
[2]
422 blender_material
.specular_color
[0] = ms3d_material
.specular
[0]
423 blender_material
.specular_color
[1] = ms3d_material
.specular
[1]
424 blender_material
.specular_color
[2] = ms3d_material
.specular
[2]
426 blender_material
.emit
= (
427 (ms3d_material
.emissive
[0]
428 + ms3d_material
.emissive
[1]
429 + ms3d_material
.emissive
[2]) / 3.0)
431 blender_material
.specular_hardness
= ms3d_material
.shininess
* 4.0
432 blender_material
.alpha
= 1.0 - ms3d_material
.transparency
435 if ms3d_material
.texture
:
436 dir_name_diffuse
= self
.directory_name
437 file_name_diffuse
= path
.split(ms3d_material
.texture
)[1]
438 blender_image_diffuse
= load_image(
439 file_name_diffuse
, dir_name_diffuse
)
440 name_diffuse
= path
.splitext(file_name_diffuse
)[0]
441 if blender_image_diffuse
:
442 blender_image_diffuse
.name
= FORMAT_IMAGE
.format(name_diffuse
)
443 blender_texture_diffuse
= \
444 blender_context
.blend_data
.textures
.new(
445 name
=FORMAT_TEXTURE
.format(name_diffuse
),
447 blender_texture_diffuse
.image
= blender_image_diffuse
448 blender_texture_slot_diffuse \
449 = blender_material
.texture_slots
.add()
450 blender_texture_slot_diffuse
.texture
= blender_texture_diffuse
451 blender_texture_slot_diffuse
.texture_coords
= 'UV'
452 blender_texture_slot_diffuse
.uv_layer
= layer_uv
.name
453 blender_texture_slot_diffuse
.use_map_color_diffuse
= True
454 blender_texture_slot_diffuse
.use_map_alpha
= False
455 if blender_image_diffuse
is not None:
456 self
.has_textures
= True
458 blender_image_diffuse
= None
461 if ms3d_material
.alphamap
:
462 dir_name_alpha
= self
.directory_name
463 file_name_alpha
= path
.split(ms3d_material
.alphamap
)[1]
464 blender_image_alpha
= load_image(
465 file_name_alpha
, dir_name_alpha
)
466 name_alpha
= path
.splitext(file_name_alpha
)[0]
467 if blender_image_alpha
:
468 blender_image_alpha
.name
= FORMAT_IMAGE
.format(name_alpha
)
469 blender_texture_alpha
= blender_context
.blend_data
.textures
.new(
470 name
=FORMAT_TEXTURE
.format(file_name_alpha
),
472 blender_texture_alpha
.image
= blender_image_alpha
473 blender_texture_slot_alpha \
474 = blender_material
.texture_slots
.add()
475 blender_texture_slot_alpha
.texture
= blender_texture_alpha
476 blender_texture_slot_alpha
.texture_coords
= 'UV'
477 blender_texture_slot_alpha
.uv_layer
= layer_uv
.name
478 blender_texture_slot_alpha
.use_map_color_diffuse
= False
479 blender_texture_slot_alpha
.use_map_alpha
= True
480 blender_texture_slot_alpha
.use_rgb_to_intensity
= True
481 blender_material
.alpha
= 0
482 blender_material
.specular_alpha
= 0
484 # append blender material to blender mesh, to be linked to
485 blender_mesh
.materials
.append(blender_material
)
487 # translation dictionary
488 ms3d_to_blender_material
[ms3d_material_index
] \
489 = blender_image_diffuse
491 ##########################
493 # create all triangles
494 length_verts
= len(bm
.verts
)
495 vertex_extra_index
= length_verts
496 blender_invalide_normal
= Vector()
497 smoothing_group_blender_faces
= {}
498 for ms3d_triangle_index
, ms3d_triangle
in enumerate(
499 ms3d_model
.triangles
):
501 bmf_normal
= Vector()
503 for index
, vert_index
in enumerate(ms3d_triangle
.vertex_indices
):
504 if vert_index
< 0 or vert_index
>= length_verts
:
506 bmv
= bm
.verts
[vert_index
]
508 blender_normal
= self
.geometry_correction(
509 ms3d_triangle
.vertex_normals
[index
])
510 if bmv
.normal
== blender_invalide_normal
:
511 bmv
.normal
= blender_normal
512 elif bmv
.normal
!= blender_normal \
513 and self
.options_use_extended_normal_handling
:
514 ## search for an already created extra vertex
516 for vert_index_candidat
in range(
517 vertex_extra_index
, length_verts
):
518 bmv_candidat
= bm
.verts
[vert_index_candidat
]
519 if bmv_candidat
.co
== bmv
.co \
520 and bmv_candidat
.normal
== blender_normal
:
521 bmv_new
= bmv_candidat
522 vert_index
= vert_index_candidat
525 ## if not exists, create one in blender and ms3d as well
527 ms3d_model
.vertices
.append(
528 ms3d_model
.vertices
[vert_index
])
529 bmv_new
= bm
.verts
.new(bmv
.co
)
530 bmv_new
.index
= -vert_index
531 bmv_new
.normal
= blender_normal
532 bmv_new
[layer_extra
] = bmv
[layer_extra
]
533 vert_index
= length_verts
535 if self
.report
and self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
536 self
.report({'WARNING', 'INFO'},
537 ms3d_str
['WARNING_IMPORT_EXTRA_VERTEX_NORMAL'].format(
538 bmv
.normal
, blender_normal
))
541 if [[x
] for x
in bmv_list
if x
== bmv
]:
542 if self
.report
and self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
545 ms3d_str
['WARNING_IMPORT_SKIP_VERTEX_DOUBLE'].format(
546 ms3d_triangle_index
))
549 bmf_normal
+= bmv
.normal
551 if len(bmv_list
) < 3:
552 if self
.report
and self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
555 ms3d_str
['WARNING_IMPORT_SKIP_LESS_VERTICES'].format(
556 ms3d_triangle_index
))
559 # create edges for the face
560 # (not really needed, because bm.faces.new() will create its edges,
561 # if not exist, but good if we have already in case we need full control
562 # of bmesh stuff maybe in the future.
563 bme
= bm
.edges
.get((bmv_list
[0], bmv_list
[1]))
565 bme
= bm
.edges
.new((bmv_list
[0], bmv_list
[1]))
566 bme
.index
= len(bm
.edges
) - 1
567 bme
= bm
.edges
.get((bmv_list
[1], bmv_list
[2]))
569 bme
= bm
.edges
.new((bmv_list
[1], bmv_list
[2]))
570 bme
.index
= len(bm
.edges
) - 1
571 bme
= bm
.edges
.get((bmv_list
[2], bmv_list
[0]))
573 bme
= bm
.edges
.new((bmv_list
[2], bmv_list
[0]))
574 bme
.index
= len(bm
.edges
) - 1
576 bmf
= bm
.faces
.get(bmv_list
)
578 if self
.report
and self
.options_verbose
in Ms3dUi
.VERBOSE_NORMAL
:
581 ms3d_str
['WARNING_IMPORT_SKIP_FACE_DOUBLE'].format(
582 ms3d_triangle_index
))
585 bmf
= bm
.faces
.new(bmv_list
)
586 bmf
.index
= ms3d_triangle_index
587 bmf_normal
.normalize()
588 bmf
.normal
= bmf_normal
590 # blender uv custom data per "face vertex"
591 bmf
.loops
[0][layer_uv
].uv
= Vector(
592 (ms3d_triangle
.s
[0], 1.0 - ms3d_triangle
.t
[0]))
593 bmf
.loops
[1][layer_uv
].uv
= Vector(
594 (ms3d_triangle
.s
[1], 1.0 - ms3d_triangle
.t
[1]))
595 bmf
.loops
[2][layer_uv
].uv
= Vector(
596 (ms3d_triangle
.s
[2], 1.0 - ms3d_triangle
.t
[2]))
598 # ms3d custom data per "mesh face"
599 bmf
[layer_smoothing_group
] = ms3d_triangle
.smoothing_group
601 blender_group_id
= ms3d_to_blender_group_index
.get(
602 ms3d_triangle
.group_index
)
603 if blender_group_id
is not None:
604 bmf
[layer_group
] = blender_group_id
606 if ms3d_triangle
.group_index
>= 0 \
607 and ms3d_triangle
.group_index
< len(ms3d_model
.groups
):
608 ms3d_material_index \
609 = ms3d_model
.groups
[ms3d_triangle
.group_index
].material_index
610 if ms3d_material_index
!= Ms3dSpec
.NONE_GROUP_MATERIAL_INDEX
:
611 bmf
.material_index
= ms3d_material_index
612 # apply diffuse texture image to face, to be visible in 3d view
613 bmf
[layer_texture
].image
= ms3d_to_blender_material
.get(
616 # helper dictionary for post-processing smoothing_groups
617 smoothing_group_blender_face
= smoothing_group_blender_faces
.get(
618 ms3d_triangle
.smoothing_group
)
619 if smoothing_group_blender_face
is None:
620 smoothing_group_blender_face
= []
621 smoothing_group_blender_faces
[ms3d_triangle
.smoothing_group
] \
622 = smoothing_group_blender_face
623 smoothing_group_blender_face
.append(bmf
)
625 ##########################
627 # create all sharp edges for blender to make smoothing_groups visible
628 for ms3d_smoothing_group_index
, blender_face_list \
629 in smoothing_group_blender_faces
.items():
631 for bmf
in blender_face_list
:
633 for bme
in bmf
.edges
:
634 if edge_dict
.get(bme
) is None:
638 bme
.seam
= (edge_dict
[bme
] == 0)
639 bme
.smooth
= (edge_dict
[bme
] != 0)
641 ##########################
643 # finally transfer BMesh to Mesh
644 bm
.to_mesh(blender_mesh
)
650 ####################################################
652 blender_mesh
.validate(self
.options_verbose
in Ms3dUi
.VERBOSE_MAXIMAL
)
654 return blender_mesh_object
657 ###########################################################################
658 def create_animation(self
, blender_context
, ms3d_model
, blender_mesh_object
):
659 ##########################
661 blender_scene
= blender_context
.scene
662 blender_scene
.render
.fps
= ms3d_model
.animation_fps
663 if ms3d_model
.animation_fps
:
664 blender_scene
.render
.fps_base
= (blender_scene
.render
.fps
/
665 ms3d_model
.animation_fps
)
667 blender_scene
.frame_start
= 1
668 blender_scene
.frame_end
= (ms3d_model
.number_total_frames
669 + blender_scene
.frame_start
) - 1
670 blender_scene
.frame_current
= (ms3d_model
.current_time
671 * ms3d_model
.animation_fps
)
673 ##########################
674 if not ms3d_model
.joints
:
677 ##########################
678 ms3d_armature_name
= FORMAT_ARMATURE
.format(ms3d_model
.name
)
679 ms3d_armature_object_name
= FORMAT_ARMATURE_OBJECT
.format(ms3d_model
.name
)
680 ms3d_action_name
= FORMAT_ACTION
.format(ms3d_model
.name
)
682 ##########################
683 # create new blender_armature_object
684 blender_armature
= blender_context
.blend_data
.armatures
.new(
686 blender_armature
.ms3d
.name
= ms3d_model
.name
687 blender_armature
.draw_type
= 'STICK'
688 blender_armature
.show_axes
= True
689 blender_armature
.use_auto_ik
= True
690 blender_armature_object
= blender_context
.blend_data
.objects
.new(
691 ms3d_armature_object_name
, blender_armature
)
692 blender_scene
.objects
.link(blender_armature_object
)
693 #blender_armature_object.location = blender_scene.cursor_location
694 blender_armature_object
.show_x_ray
= True
696 ##########################
697 # create new modifier
698 blender_modifier
= blender_mesh_object
.modifiers
.new(
699 blender_armature
.name
, type='ARMATURE')
700 blender_modifier
.show_expanded
= False
701 blender_modifier
.use_vertex_groups
= True
702 blender_modifier
.use_bone_envelopes
= False
703 blender_modifier
.object = blender_armature_object
705 ##########################
706 # prepare for vertex groups
707 ms3d_to_blender_vertex_groups
= {}
708 for ms3d_vertex_index
, ms3d_vertex
in enumerate(ms3d_model
.vertices
):
709 # prepare for later use for blender vertex group
710 if ms3d_vertex
.bone_id
!= Ms3dSpec
.NONE_VERTEX_BONE_ID
:
711 if ms3d_vertex
.vertex_ex_object \
713 ms3d_vertex
.vertex_ex_object
.bone_ids
[0] != \
714 Ms3dSpec
.NONE_VERTEX_BONE_ID \
715 or ms3d_vertex
.vertex_ex_object
.bone_ids
[1] != \
716 Ms3dSpec
.NONE_VERTEX_BONE_ID \
717 or ms3d_vertex
.vertex_ex_object
.bone_ids
[2] != \
718 Ms3dSpec
.NONE_VERTEX_BONE_ID \
720 ms3d_vertex_group_ids_weights
= []
721 ms3d_vertex_group_ids_weights
.append(
722 (ms3d_vertex
.bone_id
,
723 float(ms3d_vertex
.vertex_ex_object
.weights
[0] % 101) / 100.0,
725 if ms3d_vertex
.vertex_ex_object
.bone_ids
[0] != \
726 Ms3dSpec
.NONE_VERTEX_BONE_ID
:
727 ms3d_vertex_group_ids_weights
.append(
728 (ms3d_vertex
.vertex_ex_object
.bone_ids
[0],
729 float(ms3d_vertex
.vertex_ex_object
.weights
[1] % 101) / 100.0
731 if ms3d_vertex
.vertex_ex_object
.bone_ids
[1] != \
732 Ms3dSpec
.NONE_VERTEX_BONE_ID
:
733 ms3d_vertex_group_ids_weights
.append(
734 (ms3d_vertex
.vertex_ex_object
.bone_ids
[1],
735 float(ms3d_vertex
.vertex_ex_object
.weights
[2] % 101) / 100.0
737 if ms3d_vertex
.vertex_ex_object
.bone_ids
[2] != \
738 Ms3dSpec
.NONE_VERTEX_BONE_ID
:
739 ms3d_vertex_group_ids_weights
.append(
740 (ms3d_vertex
.vertex_ex_object
.bone_ids
[2],
742 float((ms3d_vertex
.vertex_ex_object
.weights
[0] % 101)
743 + (ms3d_vertex
.vertex_ex_object
.weights
[1] % 101)
744 + (ms3d_vertex
.vertex_ex_object
.weights
[2] % 101)) / 100.0
748 ms3d_vertex_group_ids_weights
= [(ms3d_vertex
.bone_id
, 1.0), ]
750 for ms3d_vertex_group_id_weight
in ms3d_vertex_group_ids_weights
:
751 ms3d_vertex_group_id
= ms3d_vertex_group_id_weight
[0]
752 blender_vertex_weight
= ms3d_vertex_group_id_weight
[1]
753 blender_vertex_group
= ms3d_to_blender_vertex_groups
.get(
754 ms3d_vertex_group_id
)
755 if blender_vertex_group
is None:
756 ms3d_to_blender_vertex_groups
[ms3d_vertex_group_id
] \
757 = blender_vertex_group
= []
758 blender_vertex_group
.append((ms3d_vertex_index
,
759 blender_vertex_weight
))
761 ##########################
763 # create all vertex groups to be used for bones
764 for ms3d_bone_id
, blender_vertex_index_weight_list \
765 in ms3d_to_blender_vertex_groups
.items():
766 ms3d_name
= ms3d_model
.joints
[ms3d_bone_id
].name
767 blender_vertex_group
= blender_mesh_object
.vertex_groups
.new(
769 for blender_vertex_id_weight
in blender_vertex_index_weight_list
:
770 blender_vertex_index
= blender_vertex_id_weight
[0]
771 blender_vertex_weight
= blender_vertex_id_weight
[1]
772 blender_vertex_group
.add((blender_vertex_index
, ),
773 blender_vertex_weight
, 'ADD')
775 ##########################
776 # bring joints in the correct order
777 ms3d_joints_ordered
= []
778 self
.build_ms3d_joint_dependency_order(ms3d_model
.joints
,
781 ##########################
782 # prepare joint data for later use
783 ms3d_joint_by_name
= {}
784 for ms3d_joint
in ms3d_joints_ordered
:
785 item
= ms3d_joint_by_name
.get(ms3d_joint
.name
)
787 ms3d_joint
.__children
= []
788 ms3d_joint_by_name
[ms3d_joint
.name
] = ms3d_joint
790 matrix_local_rot
= (Matrix
.Rotation(ms3d_joint
.rotation
[2], 4, 'Z')
791 * Matrix
.Rotation(ms3d_joint
.rotation
[1], 4, 'Y')
792 ) * Matrix
.Rotation(ms3d_joint
.rotation
[0], 4, 'X')
793 matrix_local
= Matrix
.Translation(Vector(ms3d_joint
.position
)
796 ms3d_joint
.__matrix
_local
_rot
= matrix_local_rot
797 ms3d_joint
.__matrix
_global
_rot
= matrix_local_rot
798 ms3d_joint
.__matrix
_local
= matrix_local
799 ms3d_joint
.__matrix
_global
= matrix_local
801 if ms3d_joint
.parent_name
:
802 ms3d_joint_parent
= ms3d_joint_by_name
.get(
803 ms3d_joint
.parent_name
)
804 if ms3d_joint_parent
is not None:
805 ms3d_joint_parent
.__children
.append(ms3d_joint
)
807 matrix_global
= ms3d_joint_parent
.__matrix
_global \
809 ms3d_joint
.__matrix
_global
= matrix_global
811 matrix_global_rot
= ms3d_joint_parent
.__matrix
_global
_rot \
813 ms3d_joint
.__matrix
_global
_rot
= matrix_global_rot
815 ##########################
816 # ms3d_joint to blender_edit_bone
817 if ms3d_model
.model_ex_object
and not self
.options_use_joint_size
:
818 joint_length
= ms3d_model
.model_ex_object
.joint_size
820 joint_length
= self
.options_joint_size
821 if joint_length
< 0.01:
824 blender_scene
.objects
.active
= blender_armature_object
825 enable_edit_mode(True, blender_context
)
826 for ms3d_joint
in ms3d_joints_ordered
:
827 blender_edit_bone
= blender_armature
.edit_bones
.new(ms3d_joint
.name
)
828 blender_edit_bone
.use_connect
= False
829 blender_edit_bone
.use_inherit_rotation
= True
830 blender_edit_bone
.use_inherit_scale
= True
831 blender_edit_bone
.use_local_location
= True
832 blender_armature
.edit_bones
.active
= blender_edit_bone
834 ms3d_joint
= ms3d_joint_by_name
[ms3d_joint
.name
]
835 ms3d_joint_vector
= ms3d_joint
.__matrix
_global
* Vector()
837 blender_edit_bone
.head \
838 = self
.geometry_correction(ms3d_joint_vector
)
840 vector_tail_end_up
= ms3d_joint
.__matrix
_global
_rot
* Vector((0,1,0))
841 vector_tail_end_dir
= ms3d_joint
.__matrix
_global
_rot
* Vector((0,0,1))
842 vector_tail_end_up
.normalize()
843 vector_tail_end_dir
.normalize()
844 blender_edit_bone
.tail
= blender_edit_bone
.head \
845 + self
.geometry_correction(
846 vector_tail_end_dir
* joint_length
)
847 blender_edit_bone
.align_roll(self
.geometry_correction(
850 if ms3d_joint
.parent_name
:
851 ms3d_joint_parent
= ms3d_joint_by_name
[ms3d_joint
.parent_name
]
852 blender_edit_bone_parent
= ms3d_joint_parent
.blender_edit_bone
853 blender_edit_bone
.parent
= blender_edit_bone_parent
855 ms3d_joint
.blender_bone_name
= blender_edit_bone
.name
856 ms3d_joint
.blender_edit_bone
= blender_edit_bone
857 enable_edit_mode(False, blender_context
)
859 if self
.options_use_joint_to_bones
:
860 enable_edit_mode(True, blender_context
)
861 for ms3d_joint
in ms3d_joints_ordered
:
862 blender_edit_bone
= blender_armature
.edit_bones
[ms3d_joint
.name
]
863 if blender_edit_bone
.children
:
865 for child_bone
in blender_edit_bone
.children
:
866 length
= (child_bone
.head
- blender_edit_bone
.head
).length
867 if new_length
<= 0 or length
< new_length
:
869 if new_length
>= 0.01:
870 direction
= blender_edit_bone
.tail
- blender_edit_bone
.head
871 direction
.normalize()
872 blender_edit_bone
.tail
= blender_edit_bone
.head
+ (direction
* new_length
)
873 enable_edit_mode(False, blender_context
)
875 ##########################
877 enable_edit_mode(False, blender_context
)
878 for ms3d_joint_name
, ms3d_joint
in ms3d_joint_by_name
.items():
879 blender_bone
= blender_armature
.bones
.get(
880 ms3d_joint
.blender_bone_name
)
881 if blender_bone
is None:
884 blender_bone
.ms3d
.name
= ms3d_joint
.name
885 blender_bone
.ms3d
.flags
= Ms3dUi
.flags_from_ms3d(ms3d_joint
.flags
)
887 ms3d_joint_ex
= ms3d_joint
.joint_ex_object
888 if ms3d_joint_ex
is not None:
889 blender_bone
.ms3d
.color
= ms3d_joint_ex
.color
891 ms3d_comment
= ms3d_joint
.comment_object
892 if ms3d_comment
is not None:
893 blender_bone
.ms3d
.comment
= ms3d_comment
.comment
895 ##########################
896 if not self
.options_use_animation
:
897 return blender_armature_object
900 ##########################
902 enable_pose_mode(True, blender_context
)
904 blender_action
= blender_context
.blend_data
.actions
.new(ms3d_action_name
)
905 if blender_armature_object
.animation_data
is None:
906 blender_armature_object
.animation_data_create()
907 blender_armature_object
.animation_data
.action
= blender_action
909 ##########################
910 # transition between keys may be incorrect
911 # because of the gimbal-lock problem!
912 # http://www.youtube.com/watch?v=zc8b2Jo7mno
913 # http://www.youtube.com/watch?v=rrUCBOlJdt4
914 # you can fix it manually by selecting the affected keyframes
915 # and apply the following option to it:
916 # "Graph Editor -> Key -> Discontinuity (Euler) Filter"
917 # ==> "bpy.ops.graph.euler_filter()"
918 # but this option is only available for Euler rotation f-curves!
920 for ms3d_joint_name
, ms3d_joint
in ms3d_joint_by_name
.items():
921 blender_pose_bone
= blender_armature_object
.pose
.bones
.get(
922 ms3d_joint
.blender_bone_name
)
923 if blender_pose_bone
is None:
926 data_path
= blender_pose_bone
.path_from_id('location')
927 fcurve_location_x
= blender_action
.fcurves
.new(data_path
, index
=0)
928 fcurve_location_y
= blender_action
.fcurves
.new(data_path
, index
=1)
929 fcurve_location_z
= blender_action
.fcurves
.new(data_path
, index
=2)
930 for translation_key_frames
in ms3d_joint
.translation_key_frames
:
931 frame
= (translation_key_frames
.time
* ms3d_model
.animation_fps
)
932 matrix_local
= Matrix
.Translation(
933 Vector(translation_key_frames
.position
))
934 v
= (matrix_local
) * Vector()
935 fcurve_location_x
.keyframe_points
.insert(frame
, -v
[0])
936 fcurve_location_y
.keyframe_points
.insert(frame
, v
[2])
937 fcurve_location_z
.keyframe_points
.insert(frame
, v
[1])
939 if self
.options_use_quaternion_rotation
:
940 blender_pose_bone
.rotation_mode
= 'QUATERNION'
941 data_path
= blender_pose_bone
.path_from_id("rotation_quaternion")
942 fcurve_rotation_w
= blender_action
.fcurves
.new(data_path
, index
=0)
943 fcurve_rotation_x
= blender_action
.fcurves
.new(data_path
, index
=1)
944 fcurve_rotation_y
= blender_action
.fcurves
.new(data_path
, index
=2)
945 fcurve_rotation_z
= blender_action
.fcurves
.new(data_path
, index
=3)
946 for rotation_key_frames
in ms3d_joint
.rotation_key_frames
:
947 frame
= (rotation_key_frames
.time
* ms3d_model
.animation_fps
)
950 rotation_key_frames
.rotation
[2], 4, 'Y')
952 rotation_key_frames
.rotation
[1], 4, 'Z')
954 -rotation_key_frames
.rotation
[0], 4, 'X')
955 q
= (matrix_local_rot
).to_quaternion()
956 fcurve_rotation_w
.keyframe_points
.insert(frame
, q
.w
)
957 fcurve_rotation_x
.keyframe_points
.insert(frame
, q
.x
)
958 fcurve_rotation_y
.keyframe_points
.insert(frame
, q
.y
)
959 fcurve_rotation_z
.keyframe_points
.insert(frame
, q
.z
)
961 blender_pose_bone
.rotation_mode
= 'XZY'
962 data_path
= blender_pose_bone
.path_from_id("rotation_euler")
963 fcurve_rotation_x
= blender_action
.fcurves
.new(data_path
, index
=0)
964 fcurve_rotation_y
= blender_action
.fcurves
.new(data_path
, index
=1)
965 fcurve_rotation_z
= blender_action
.fcurves
.new(data_path
, index
=2)
966 for rotation_key_frames
in ms3d_joint
.rotation_key_frames
:
967 frame
= (rotation_key_frames
.time
* ms3d_model
.animation_fps
)
968 fcurve_rotation_x
.keyframe_points
.insert(
969 frame
, -rotation_key_frames
.rotation
[0])
970 fcurve_rotation_y
.keyframe_points
.insert(
971 frame
, rotation_key_frames
.rotation
[2])
972 fcurve_rotation_z
.keyframe_points
.insert(
973 frame
, rotation_key_frames
.rotation
[1])
975 enable_pose_mode(False, blender_context
)
977 return blender_armature_object
980 ###########################################################################
981 def geometry_correction(self
, value
):
982 return Vector((value
[2], value
[0], value
[1]))
985 ###########################################################################
986 def build_ms3d_joint_dependency_order(self
, ms3d_joints
, ms3d_joints_ordered
):
987 ms3d_joints_children
= {"": {}}
988 for ms3d_joint
in ms3d_joints
:
989 if ms3d_joint
.parent_name
:
990 ms3d_joint_children
= ms3d_joints_children
.get(
991 ms3d_joint
.parent_name
)
992 if ms3d_joint_children
is None:
993 ms3d_joint_children
= ms3d_joints_children
[
994 ms3d_joint
.parent_name
] = {}
996 ms3d_joint_children
= ms3d_joints_children
[""]
998 ms3d_joint_children
[ms3d_joint
.name
] = ms3d_joint
1000 self
.traverse_dependencies(
1001 ms3d_joints_ordered
,
1002 ms3d_joints_children
,
1006 return ms3d_joints_ordered
1009 ###########################################################################
1010 def traverse_dependencies(self
, ms3d_joints_ordered
, ms3d_joints_children
,
1012 ms3d_joint_children
= ms3d_joints_children
.get(key
)
1013 if ms3d_joint_children
:
1014 for item
in ms3d_joint_children
.items():
1015 ms3d_joint_name
= item
[0]
1016 ms3d_joint
= item
[1]
1017 ms3d_joints_ordered
.append(ms3d_joint
)
1018 self
.traverse_dependencies(
1019 ms3d_joints_ordered
,
1020 ms3d_joints_children
,
1024 ###############################################################################
1025 #234567890123456789012345678901234567890123456789012345678901234567890123456789
1026 #--------1---------2---------3---------4---------5---------6---------7---------
1027 # ##### END OF FILE #####