def create_animation(self, blender_context, ms3d_model, blender_mesh_object): ########################## # setup scene blender_scene = blender_context.scene blender_scene.render.fps = ms3d_model.animation_fps if ms3d_model.animation_fps: blender_scene.render.fps_base = (blender_scene.render.fps / ms3d_model.animation_fps) blender_scene.frame_start = 1 blender_scene.frame_end = (ms3d_model.number_total_frames + blender_scene.frame_start) - 1 blender_scene.frame_current = (ms3d_model.current_time * ms3d_model.animation_fps) ########################## if not ms3d_model.joints: return ########################## ms3d_armature_name = "{}.a".format(ms3d_model.name) ms3d_action_name = "{}.act".format(ms3d_model.name) ########################## # create new blender_armature_object blender_armature = blender_context.blend_data.armatures.new( ms3d_armature_name) blender_armature.ms3d.name = ms3d_model.name blender_armature.draw_type = 'STICK' blender_armature.show_axes = True blender_armature.use_auto_ik = True blender_armature_object = blender_context.blend_data.objects.new( ms3d_armature_name, blender_armature) blender_scene.objects.link(blender_armature_object) #blender_armature_object.location = blender_scene.cursor_location blender_armature_object.show_x_ray = True ########################## # create new modifier blender_modifier = blender_mesh_object.modifiers.new( ms3d_armature_name, type='ARMATURE') blender_modifier.show_expanded = False blender_modifier.use_vertex_groups = True blender_modifier.use_bone_envelopes = False blender_modifier.object = blender_armature_object ########################## # prepare for vertex groups ms3d_to_blender_vertex_groups = {} for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices): # prepare for later use for blender vertex group if ms3d_vertex.bone_id != Ms3dSpec.NONE_VERTEX_BONE_ID: if ms3d_vertex.vertex_ex_object \ and ( \ ms3d_vertex.vertex_ex_object.bone_ids[0] != \ Ms3dSpec.NONE_VERTEX_BONE_ID \ or ms3d_vertex.vertex_ex_object.bone_ids[1] != \ Ms3dSpec.NONE_VERTEX_BONE_ID \ or ms3d_vertex.vertex_ex_object.bone_ids[2] != \ Ms3dSpec.NONE_VERTEX_BONE_ID \ ): ms3d_vertex_group_ids_weights = [] ms3d_vertex_group_ids_weights.append( (ms3d_vertex.bone_id, float(ms3d_vertex.vertex_ex_object.weights[0] % 101) / 100.0, )) if ms3d_vertex.vertex_ex_object.bone_ids[0] != \ Ms3dSpec.NONE_VERTEX_BONE_ID: ms3d_vertex_group_ids_weights.append( (ms3d_vertex.vertex_ex_object.bone_ids[0], float(ms3d_vertex.vertex_ex_object.weights[1] % 101) / 100.0 )) if ms3d_vertex.vertex_ex_object.bone_ids[1] != \ Ms3dSpec.NONE_VERTEX_BONE_ID: ms3d_vertex_group_ids_weights.append( (ms3d_vertex.vertex_ex_object.bone_ids[1], float(ms3d_vertex.vertex_ex_object.weights[2] % 101) / 100.0 )) if ms3d_vertex.vertex_ex_object.bone_ids[2] != \ Ms3dSpec.NONE_VERTEX_BONE_ID: ms3d_vertex_group_ids_weights.append( (ms3d_vertex.vertex_ex_object.bone_ids[2], 1.0 - float((ms3d_vertex.vertex_ex_object.weights[0] % 101) + (ms3d_vertex.vertex_ex_object.weights[1] % 101) + (ms3d_vertex.vertex_ex_object.weights[2] % 101)) / 100.0 )) else: ms3d_vertex_group_ids_weights = [(ms3d_vertex.bone_id, 1.0), ] for ms3d_vertex_group_id_weight in ms3d_vertex_group_ids_weights: ms3d_vertex_group_id = ms3d_vertex_group_id_weight[0] blender_vertex_weight = ms3d_vertex_group_id_weight[1] blender_vertex_group = ms3d_to_blender_vertex_groups.get( ms3d_vertex_group_id) if blender_vertex_group is None: ms3d_to_blender_vertex_groups[ms3d_vertex_group_id] \ = blender_vertex_group = [] blender_vertex_group.append((ms3d_vertex_index, blender_vertex_weight)) ########################## # blender stuff: # create all vertex groups to be used for bones for ms3d_bone_id, blender_vertex_index_weight_list \ in ms3d_to_blender_vertex_groups.items(): ms3d_name = ms3d_model.joints[ms3d_bone_id].name blender_vertex_group = blender_mesh_object.vertex_groups.new( ms3d_name) for blender_vertex_id_weight in blender_vertex_index_weight_list: blender_vertex_index = blender_vertex_id_weight[0] blender_vertex_weight = blender_vertex_id_weight[1] blender_vertex_group.add((blender_vertex_index, ), blender_vertex_weight, 'ADD') ########################## # bring joints in the correct order ms3d_joints_ordered = [] self.build_ms3d_joint_dependency_order(ms3d_model.joints, ms3d_joints_ordered) ########################## # prepare joint data for later use ms3d_joint_by_name = {} for ms3d_joint in ms3d_joints_ordered: item = ms3d_joint_by_name.get(ms3d_joint.name) if item is None: ms3d_joint.__children = [] ms3d_joint_by_name[ms3d_joint.name] = ms3d_joint matrix_local_rot = (Matrix.Rotation(ms3d_joint.rotation[2], 4, 'Z') * Matrix.Rotation(ms3d_joint.rotation[1], 4, 'Y') ) * Matrix.Rotation(ms3d_joint.rotation[0], 4, 'X') matrix_local = Matrix.Translation(Vector(ms3d_joint.position) ) * matrix_local_rot ms3d_joint.__matrix_local_rot = matrix_local_rot ms3d_joint.__matrix_global_rot = matrix_local_rot ms3d_joint.__matrix_local = matrix_local ms3d_joint.__matrix_global = matrix_local if ms3d_joint.parent_name: ms3d_joint_parent = ms3d_joint_by_name.get( ms3d_joint.parent_name) if ms3d_joint_parent is not None: ms3d_joint_parent.__children.append(ms3d_joint) matrix_global = ms3d_joint_parent.__matrix_global \ * matrix_local ms3d_joint.__matrix_global = matrix_global matrix_global_rot = ms3d_joint_parent.__matrix_global_rot \ * matrix_local_rot ms3d_joint.__matrix_global_rot = matrix_global_rot ########################## # ms3d_joint to blender_edit_bone if ms3d_model.model_ex_object and not self.options_use_joint_size: joint_length = ms3d_model.model_ex_object.joint_size else: joint_length = self.options_joint_size if joint_length < 0.01: joint_length = 0.01 blender_scene.objects.active = blender_armature_object enable_edit_mode(True, blender_context) for ms3d_joint in ms3d_joints_ordered: blender_edit_bone = blender_armature.edit_bones.new(ms3d_joint.name) blender_edit_bone.use_connect = False blender_edit_bone.use_inherit_rotation = True blender_edit_bone.use_inherit_scale = True blender_edit_bone.use_local_location = True blender_armature.edit_bones.active = blender_edit_bone ms3d_joint = ms3d_joint_by_name[ms3d_joint.name] ms3d_joint_vector = ms3d_joint.__matrix_global * Vector() blender_edit_bone.head \ = self.geometry_correction(ms3d_joint_vector) vector_tail_end_up = ms3d_joint.__matrix_global_rot * Vector((0,1,0)) vector_tail_end_dir = ms3d_joint.__matrix_global_rot * Vector((0,0,1)) vector_tail_end_up.normalize() vector_tail_end_dir.normalize() blender_edit_bone.tail = blender_edit_bone.head \ + self.geometry_correction( vector_tail_end_dir * joint_length) blender_edit_bone.align_roll(self.geometry_correction( vector_tail_end_up)) if ms3d_joint.parent_name: ms3d_joint_parent = ms3d_joint_by_name[ms3d_joint.parent_name] blender_edit_bone_parent = ms3d_joint_parent.blender_edit_bone blender_edit_bone.parent = blender_edit_bone_parent ms3d_joint.blender_bone_name = blender_edit_bone.name ms3d_joint.blender_edit_bone = blender_edit_bone enable_edit_mode(False, blender_context) if self.options_use_joint_to_bones: enable_edit_mode(True, blender_context) for ms3d_joint in ms3d_joints_ordered: blender_edit_bone = blender_armature.edit_bones[ms3d_joint.name] if blender_edit_bone.children: new_length = 0.0 for child_bone in blender_edit_bone.children: length = (child_bone.head - blender_edit_bone.head).length if new_length <= 0 or length < new_length: new_length = length if new_length >= 0.01: direction = blender_edit_bone.tail - blender_edit_bone.head direction.normalize() blender_edit_bone.tail = blender_edit_bone.head + (direction * new_length) enable_edit_mode(False, blender_context) ########################## # post process bones enable_edit_mode(False, blender_context) for ms3d_joint_name, ms3d_joint in ms3d_joint_by_name.items(): blender_bone = blender_armature.bones.get( ms3d_joint.blender_bone_name) if blender_bone is None: continue blender_bone.ms3d.name = ms3d_joint.name blender_bone.ms3d.flags = Ms3dUi.flags_from_ms3d(ms3d_joint.flags) ms3d_joint_ex = ms3d_joint.joint_ex_object if ms3d_joint_ex is not None: blender_bone.ms3d.color = ms3d_joint_ex.color ms3d_comment = ms3d_joint.comment_object if ms3d_comment is not None: blender_bone.ms3d.comment = ms3d_comment.comment ########################## if not self.options_use_animation: return blender_armature_object ########################## # process pose bones enable_pose_mode(True, blender_context) blender_action = blender_context.blend_data.actions.new(ms3d_action_name) if blender_armature_object.animation_data is None: blender_armature_object.animation_data_create() blender_armature_object.animation_data.action = blender_action ########################## # transition between keys may be incorrect # because of the gimbal-lock problem! # http://www.youtube.com/watch?v=zc8b2Jo7mno # http://www.youtube.com/watch?v=rrUCBOlJdt4 # you can fix it manually by selecting the affected keyframes # and allpy the following option to it: # "Graph Editor -> Key -> Discontinuity (Euler) Filter" # ==> "bpy.ops.graph.euler_filter()" # but this option is only available for Euler rotation f-curves! # for ms3d_joint_name, ms3d_joint in ms3d_joint_by_name.items(): blender_pose_bone = blender_armature_object.pose.bones.get( ms3d_joint.blender_bone_name) if blender_pose_bone is None: continue data_path = blender_pose_bone.path_from_id('location') fcurve_location_x = blender_action.fcurves.new(data_path, index=0) fcurve_location_y = blender_action.fcurves.new(data_path, index=1) fcurve_location_z = blender_action.fcurves.new(data_path, index=2) for translation_key_frames in ms3d_joint.translation_key_frames: frame = (translation_key_frames.time * ms3d_model.animation_fps) matrix_local = Matrix.Translation( Vector(translation_key_frames.position)) v = (matrix_local) * Vector() fcurve_location_x.keyframe_points.insert(frame, -v[0]) fcurve_location_y.keyframe_points.insert(frame, v[2]) fcurve_location_z.keyframe_points.insert(frame, v[1]) if self.options_use_quaternion_rotation: blender_pose_bone.rotation_mode = 'QUATERNION' data_path = blender_pose_bone.path_from_id("rotation_quaternion") fcurve_rotation_w = blender_action.fcurves.new(data_path, index=0) fcurve_rotation_x = blender_action.fcurves.new(data_path, index=1) fcurve_rotation_y = blender_action.fcurves.new(data_path, index=2) fcurve_rotation_z = blender_action.fcurves.new(data_path, index=3) for rotation_key_frames in ms3d_joint.rotation_key_frames: frame = (rotation_key_frames.time * ms3d_model.animation_fps) matrix_local_rot = ( Matrix.Rotation( rotation_key_frames.rotation[2], 4, 'Y') * Matrix.Rotation( rotation_key_frames.rotation[1], 4, 'Z') ) * Matrix.Rotation( -rotation_key_frames.rotation[0], 4, 'X') q = (matrix_local_rot).to_quaternion() fcurve_rotation_w.keyframe_points.insert(frame, q.w) fcurve_rotation_x.keyframe_points.insert(frame, q.x) fcurve_rotation_y.keyframe_points.insert(frame, q.y) fcurve_rotation_z.keyframe_points.insert(frame, q.z) else: blender_pose_bone.rotation_mode = 'XZY' data_path = blender_pose_bone.path_from_id("rotation_euler") fcurve_rotation_x = blender_action.fcurves.new(data_path, index=0) fcurve_rotation_y = blender_action.fcurves.new(data_path, index=1) fcurve_rotation_z = blender_action.fcurves.new(data_path, index=2) for rotation_key_frames in ms3d_joint.rotation_key_frames: frame = (rotation_key_frames.time * ms3d_model.animation_fps) fcurve_rotation_x.keyframe_points.insert( frame, -rotation_key_frames.rotation[0]) fcurve_rotation_y.keyframe_points.insert( frame, rotation_key_frames.rotation[2]) fcurve_rotation_z.keyframe_points.insert( frame, rotation_key_frames.rotation[1]) enable_pose_mode(False, blender_context) return blender_armature_object
def create_geometry(self, blender_context, ms3d_model): ########################## # blender stuff: # create a blender Mesh blender_mesh = blender_context.blend_data.meshes.new( "{}.m".format(ms3d_model.name)) blender_mesh.ms3d.name = ms3d_model.name ms3d_comment = ms3d_model.comment_object if ms3d_comment is not None: blender_mesh.ms3d.comment = ms3d_comment.comment ms3d_model_ex = ms3d_model.model_ex_object if ms3d_model_ex is not None: blender_mesh.ms3d.joint_size = ms3d_model_ex.joint_size blender_mesh.ms3d.alpha_ref = ms3d_model_ex.alpha_ref blender_mesh.ms3d.transparency_mode \ = Ms3dUi.transparency_mode_from_ms3d( ms3d_model_ex.transparency_mode) ########################## # blender stuff: # link to blender object blender_mesh_object = blender_context.blend_data.objects.new( "{}.m".format(ms3d_model.name), blender_mesh) ########################## # blender stuff: # create edge split modifire, to make sharp edges visible blender_modifier = get_edge_split_modifier_add_if(blender_mesh_object) ########################## # blender stuff: # link to blender scene blender_scene = blender_context.scene blender_scene.objects.link(blender_mesh_object) #blender_mesh_object.location = blender_scene.cursor_location enable_edit_mode(False, blender_context) select_all(False) blender_mesh_object.select = True blender_scene.objects.active = blender_mesh_object ########################## # take this as active object after import self.active_object = blender_mesh_object ########################## # blender stuff: # create all (ms3d) groups ms3d_to_blender_group_index = {} blender_group_manager = blender_mesh.ms3d for ms3d_group_index, ms3d_group in enumerate(ms3d_model.groups): blender_group = blender_group_manager.create_group() blender_group.name = ms3d_group.name blender_group.flags = Ms3dUi.flags_from_ms3d(ms3d_group.flags) blender_group.material_index = ms3d_group.material_index ms3d_comment = ms3d_group.comment_object if ms3d_comment is not None: blender_group.comment = ms3d_comment.comment # translation dictionary ms3d_to_blender_group_index[ms3d_group_index] = blender_group.id #################################################### # begin BMesh stuff # ########################## # BMesh stuff: # create an empty BMesh bm = bmesh.new() ########################## # BMesh stuff: # create new Layers for custom data per "mesh face" layer_texture = bm.faces.layers.tex.get( ms3d_str['OBJECT_LAYER_TEXTURE']) if layer_texture is None: layer_texture = bm.faces.layers.tex.new( ms3d_str['OBJECT_LAYER_TEXTURE']) layer_smoothing_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) if layer_smoothing_group is None: layer_smoothing_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) layer_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_GROUP']) if layer_group is None: layer_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_GROUP']) ########################## # BMesh stuff: # create new Layers for custom data per "face vertex" layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV']) if layer_uv is None: layer_uv = bm.loops.layers.uv.new(ms3d_str['OBJECT_LAYER_UV']) ########################## # BMesh stuff: # create new Layers for custom data per "vertex" layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA']) if layer_extra is None: layer_extra = bm.verts.layers.int.new(ms3d_str['OBJECT_LAYER_EXTRA']) ########################## # BMesh stuff: # create all vertices for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices): bmv = bm.verts.new(self.geometry_correction(ms3d_vertex.vertex)) if layer_extra and ms3d_vertex.vertex_ex_object and \ (isinstance(ms3d_vertex.vertex_ex_object, Ms3dVertexEx2) \ or isinstance(ms3d_vertex.vertex_ex_object, Ms3dVertexEx3)): #bmv[layer_extra] = ms3d_vertex.vertex_ex_object.extra # bm.verts.layers.int does only support signed int32 # convert unsigned int32 to signed int32 (little-endian) unsigned_int32 = ms3d_vertex.vertex_ex_object.extra bytes_int32 = unsigned_int32.to_bytes( 4, byteorder='little', signed=False) signed_int32 = int.from_bytes( bytes_int32, byteorder='little', signed=True) bmv[layer_extra] = signed_int32 ########################## # blender stuff (uses BMesh stuff): # create all materials / image textures ms3d_to_blender_material = {} for ms3d_material_index, ms3d_material in enumerate( ms3d_model.materials): blender_material = blender_context.blend_data.materials.new( ms3d_material.name) # custom datas blender_material.ms3d.name = ms3d_material.name blender_material.ms3d.ambient = ms3d_material.ambient blender_material.ms3d.diffuse = ms3d_material.diffuse blender_material.ms3d.specular = ms3d_material.specular blender_material.ms3d.emissive = ms3d_material.emissive blender_material.ms3d.shininess = ms3d_material.shininess blender_material.ms3d.transparency = ms3d_material.transparency blender_material.ms3d.mode = Ms3dUi.texture_mode_from_ms3d( ms3d_material.mode) if ms3d_material.texture: blender_material.ms3d.texture = ms3d_material.texture if ms3d_material.alphamap: blender_material.ms3d.alphamap = ms3d_material.alphamap ms3d_comment = ms3d_material.comment_object if ms3d_comment is not None: blender_material.ms3d.comment = ms3d_comment.comment # blender datas blender_material.ambient = ( (ms3d_material.ambient[0] + ms3d_material.ambient[1] + ms3d_material.ambient[2]) / 3.0) blender_material.diffuse_color[0] = ms3d_material.diffuse[0] blender_material.diffuse_color[1] = ms3d_material.diffuse[1] blender_material.diffuse_color[2] = ms3d_material.diffuse[2] blender_material.specular_color[0] = ms3d_material.specular[0] blender_material.specular_color[1] = ms3d_material.specular[1] blender_material.specular_color[2] = ms3d_material.specular[2] blender_material.emit = ( (ms3d_material.emissive[0] + ms3d_material.emissive[1] + ms3d_material.emissive[2]) / 3.0) blender_material.specular_hardness = ms3d_material.shininess * 4.0 blender_material.alpha = 1.0 - ms3d_material.transparency # diffuse texture if ms3d_material.texture: dir_name_diffuse = self.directory_name file_name_diffuse = path.split(ms3d_material.texture)[1] blender_image_diffuse = load_image( file_name_diffuse, dir_name_diffuse) blender_texture_diffuse = \ blender_context.blend_data.textures.new( name=file_name_diffuse, type='IMAGE') blender_texture_diffuse.image = blender_image_diffuse blender_texture_slot_diffuse \ = blender_material.texture_slots.add() blender_texture_slot_diffuse.texture = blender_texture_diffuse blender_texture_slot_diffuse.texture_coords = 'UV' blender_texture_slot_diffuse.uv_layer = layer_uv.name blender_texture_slot_diffuse.use_map_color_diffuse = True blender_texture_slot_diffuse.use_map_alpha = False if blender_image_diffuse is not None: self.has_textures = True else: blender_image_diffuse = None # alpha texture if ms3d_material.alphamap: dir_name_alpha = self.directory_name file_name_alpha = path.split(ms3d_material.alphamap)[1] blender_image_alpha = load_image( file_name_alpha, dir_name_alpha) blender_texture_alpha = blender_context.blend_data.textures.new( name=file_name_alpha, type='IMAGE') blender_texture_alpha.image = blender_image_alpha blender_texture_slot_alpha \ = blender_material.texture_slots.add() blender_texture_slot_alpha.texture = blender_texture_alpha blender_texture_slot_alpha.texture_coords = 'UV' blender_texture_slot_alpha.uv_layer = layer_uv.name blender_texture_slot_alpha.use_map_color_diffuse = False blender_texture_slot_alpha.use_map_alpha = True blender_texture_slot_alpha.use_rgb_to_intensity = True blender_material.alpha = 0 blender_material.specular_alpha = 0 # append blender material to blender mesh, to be linked to blender_mesh.materials.append(blender_material) # translation dictionary ms3d_to_blender_material[ms3d_material_index] \ = blender_image_diffuse ########################## # BMesh stuff: # create all triangles length_verts = len(bm.verts) vertex_extra_index = length_verts blender_invalide_normal = Vector() smoothing_group_blender_faces = {} for ms3d_triangle_index, ms3d_triangle in enumerate( ms3d_model.triangles): bmv_list = [] bmf_normal = Vector() for index, vert_index in enumerate(ms3d_triangle.vertex_indices): if vert_index < 0 or vert_index >= length_verts: continue bmv = bm.verts[vert_index] blender_normal = self.geometry_correction( ms3d_triangle.vertex_normals[index]) if bmv.normal == blender_invalide_normal: bmv.normal = blender_normal elif bmv.normal != blender_normal \ and self.options_use_extended_normal_handling: ## search for an already created extra vertex bmv_new = None for vert_index_candidat in range( vertex_extra_index, length_verts): bmv_candidat = bm.verts[vert_index_candidat] if bmv_candidat.co == bmv.co \ and bmv_candidat.normal == blender_normal: bmv_new = bmv_candidat vert_index = vert_index_candidat break ## if not exists, create one in blender and ms3d as well if bmv_new is None: ms3d_model.vertices.append( ms3d_model.vertices[vert_index]) bmv_new = bm.verts.new(bmv.co) bmv_new.normal = blender_normal bmv_new[layer_extra] = bmv[layer_extra] vert_index = length_verts length_verts += 1 if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report({'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_EXTRA_VERTEX_NORMAL'].format( bmv.normal, blender_normal)) bmv = bmv_new if [[x] for x in bmv_list if x == bmv]: if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_SKIP_VERTEX_DOUBLE'].format( ms3d_triangle_index)) continue bmv_list.append(bmv) bmf_normal += bmv.normal if len(bmv_list) < 3: if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_SKIP_LESS_VERTICES'].format( ms3d_triangle_index)) continue bmf_normal.normalize() bmf = bm.faces.get(bmv_list) if bmf is not None: if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_SKIP_FACE_DOUBLE'].format( ms3d_triangle_index)) continue bmf = bm.faces.new(bmv_list) bmf.normal = bmf_normal # blender uv custom data per "face vertex" bmf.loops[0][layer_uv].uv = Vector( (ms3d_triangle.s[0], 1.0 - ms3d_triangle.t[0])) bmf.loops[1][layer_uv].uv = Vector( (ms3d_triangle.s[1], 1.0 - ms3d_triangle.t[1])) bmf.loops[2][layer_uv].uv = Vector( (ms3d_triangle.s[2], 1.0 - ms3d_triangle.t[2])) # ms3d custom data per "mesh face" bmf[layer_smoothing_group] = ms3d_triangle.smoothing_group blender_group_id = ms3d_to_blender_group_index.get( ms3d_triangle.group_index) if blender_group_id is not None: bmf[layer_group] = blender_group_id if ms3d_triangle.group_index >= 0 \ and ms3d_triangle.group_index < len(ms3d_model.groups): ms3d_material_index \ = ms3d_model.groups[ms3d_triangle.group_index].material_index if ms3d_material_index != Ms3dSpec.NONE_GROUP_MATERIAL_INDEX: bmf.material_index = ms3d_material_index # apply diffuse texture image to face, to be visible in 3d view bmf[layer_texture].image = ms3d_to_blender_material.get( ms3d_material_index) # helper dictionary for post-processing smoothing_groups smoothing_group_blender_face = smoothing_group_blender_faces.get( ms3d_triangle.smoothing_group) if smoothing_group_blender_face is None: smoothing_group_blender_face = [] smoothing_group_blender_faces[ms3d_triangle.smoothing_group] \ = smoothing_group_blender_face smoothing_group_blender_face.append(bmf) ########################## # BMesh stuff: # create all sharp edges for blender to make smoothing_groups visible for ms3d_smoothing_group_index, blender_face_list \ in smoothing_group_blender_faces.items(): edge_dict = {} for bmf in blender_face_list: bmf.smooth = True for bme in bmf.edges: if edge_dict.get(bme) is None: edge_dict[bme] = 0 else: edge_dict[bme] += 1 bme.seam = (edge_dict[bme] == 0) bme.smooth = (edge_dict[bme] != 0) ########################## # BMesh stuff: # finally tranfer BMesh to Mesh bm.to_mesh(blender_mesh) bm.free() # # end BMesh stuff #################################################### blender_mesh.validate(self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL) return blender_mesh_object
def create_geometry(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones): blender_scene = blender_context.scene blender_to_ms3d_vertices = {} blender_to_ms3d_triangles = {} blender_to_ms3d_groups = {} blender_to_ms3d_materials = {} for blender_mesh_object in blender_mesh_objects: blender_mesh = blender_mesh_object.data ms3d_model._model_ex_object.joint_size = \ blender_mesh.ms3d.joint_size ms3d_model._model_ex_object.alpha_ref = blender_mesh.ms3d.alpha_ref ms3d_model._model_ex_object.transparency_mode = \ Ms3dUi.transparency_mode_to_ms3d( blender_mesh.ms3d.transparency_mode) if blender_mesh.ms3d.comment: ms3d_model._comment_object = Ms3dComment( blender_mesh.ms3d.comment) ########################## # prepare ms3d groups if available # works only for exporting active object ##EXPORT_ACTIVE_ONLY: for ms3d_local_group_index, blender_ms3d_group in enumerate( blender_mesh.ms3d.groups): ms3d_group = Ms3dGroup() ms3d_group.__index = len(ms3d_model._groups) ms3d_group.name = blender_ms3d_group.name ms3d_group.flags = Ms3dUi.flags_to_ms3d( blender_ms3d_group.flags) if blender_ms3d_group.comment: ms3d_group._comment_object = Ms3dCommentEx() ms3d_group._comment_object.comment = \ blender_ms3d_group.comment ms3d_group._comment_object.index = len(ms3d_model._groups) ms3d_group.material_index = None # to mark as not set ms3d_model._groups.append(ms3d_group) blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group ########################## # i have to use BMesh, because there are several custom data stored. # BMesh doesn't support quads_convert_to_tris() # so, i use that very ugly way: # create a complete copy of mesh and bend object data # to be able to apply operations to it. # temporary, create a full heavy copy of the model # (object, mesh, modifiers) blender_mesh_temp = blender_mesh_object.data.copy() blender_mesh_object_temp = blender_mesh_object.copy() blender_mesh_object_temp.data = blender_mesh_temp blender_scene.objects.link(blender_mesh_object_temp) blender_scene.objects.active = blender_mesh_object_temp # apply transform if self.options_apply_transform: matrix_transform = blender_mesh_object_temp.matrix_basis else: matrix_transform = 1 # apply modifiers for modifier in blender_mesh_object_temp.modifiers: if self.options_apply_modifiers: # disable only armature modifiers and only, # when use_animation is enabled if self.options_use_animation \ and modifier.type in {'ARMATURE', }: modifier.show_viewport = False modifier.show_render = False else: # disable all modifiers, # to be able to add and apply triangulate modifier later modifier.show_viewport = False modifier.show_render = False # convert to tris by using the triangulate modifier blender_mesh_object_temp.modifiers.new("temp", 'TRIANGULATE') blender_mesh_temp = blender_mesh_object_temp.to_mesh( blender_scene, True, self.options_apply_modifiers_mode) enable_edit_mode(True, blender_context) bm = bmesh.new() bm.from_mesh(blender_mesh_temp) layer_texture = bm.faces.layers.tex.get( ms3d_str['OBJECT_LAYER_TEXTURE']) if layer_texture is None: layer_texture = bm.faces.layers.tex.new( ms3d_str['OBJECT_LAYER_TEXTURE']) layer_smoothing_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) if layer_smoothing_group is None: layer_smoothing_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) layer_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_GROUP']) if layer_group is None: layer_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_GROUP']) layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV']) if layer_uv is None: if bm.loops.layers.uv: layer_uv = bm.loops.layers.uv[0] else: layer_uv = bm.loops.layers.uv.new( ms3d_str['OBJECT_LAYER_UV']) layer_deform = bm.verts.layers.deform.active layer_extra = bm.verts.layers.int.get( ms3d_str['OBJECT_LAYER_EXTRA']) if layer_extra is None: layer_extra = bm.verts.layers.int.new( ms3d_str['OBJECT_LAYER_EXTRA']) ########################## # handle vertices for bmv in bm.verts: item = blender_to_ms3d_vertices.get(bmv) if item is None: index = len(ms3d_model._vertices) ms3d_vertex = Ms3dVertex() ms3d_vertex.__index = index ms3d_vertex._vertex = self.geometry_correction( matrix_transform * bmv.co) if self.options_use_animation and layer_deform: blender_vertex_group_ids = bmv[layer_deform] if blender_vertex_group_ids: bone_weights = {} for blender_index, blender_weight \ in blender_vertex_group_ids.items(): ms3d_joint = blender_to_ms3d_bones.get( blender_mesh_object_temp.vertex_groups[\ blender_index].name) if ms3d_joint: weight = bone_weights.get( ms3d_joint.__index) if not weight: weight = 0 bone_weights[ ms3d_joint. __index] = weight + blender_weight # sort (bone_id: weight) according its weights # to skip only less important weights in the next pass bone_weights_sorted = sorted( bone_weights.items(), key=lambda item: item[1], reverse=True) count = 0 bone_ids = [] weights = [] for ms3d_index, blender_weight \ in bone_weights_sorted: if count == 0: ms3d_vertex.bone_id = ms3d_index weights.append(blender_weight) elif count == 1: bone_ids.append(ms3d_index) weights.append(blender_weight) elif count == 2: bone_ids.append(ms3d_index) weights.append(blender_weight) elif count == 3: bone_ids.append(ms3d_index) if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report( {'WARNING', 'INFO'}, ms3d_str[ 'WARNING_EXPORT_SKIP_WEIGHT']) else: # only first three weights will be supported / four bones if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report({ 'WARNING', 'INFO' }, ms3d_str[ 'WARNING_EXPORT_SKIP_WEIGHT_EX']) break count += 1 # normalize weights to 100% if self.options_normalize_weights: weight_sum = 0.0 for weight in weights: weight_sum += weight if weight_sum > 0.0: weight_normalize = 1.0 / weight_sum else: weight_normalize = 1.0 weight_sum = 100 for index, weight in enumerate(weights): if index >= count - 1 or index >= 2: # take the full rest instead of calculate, # that should fill up to exactly 100% # (in some cases it is only 99% bacaus of roulding errors) weights[index] = int(weight_sum) break normalized_weight = int( weight * weight_normalize * 100) weights[index] = normalized_weight weight_sum -= normalized_weight # fill up missing values while len(bone_ids) < 3: bone_ids.append( Ms3dSpec.DEFAULT_VERTEX_BONE_ID) while len(weights) < 3: weights.append(0) ms3d_vertex._vertex_ex_object._bone_ids = \ tuple(bone_ids) ms3d_vertex._vertex_ex_object._weights = \ tuple(weights) if layer_extra: #ms3d_vertex._vertex_ex_object.extra = bmv[layer_extra] # bm.verts.layers.int does only support signed int32 # convert signed int32 to unsigned int32 (little-endian) signed_int32 = bmv[layer_extra] bytes_int32 = signed_int32.to_bytes(4, byteorder='little', signed=True) unsigned_int32 = int.from_bytes(bytes_int32, byteorder='little', signed=False) ms3d_vertex._vertex_ex_object.extra = unsigned_int32 ms3d_model._vertices.append(ms3d_vertex) blender_to_ms3d_vertices[bmv] = ms3d_vertex ########################## # handle faces / tris for bmf in bm.faces: item = blender_to_ms3d_triangles.get(bmf) if item is None: index = len(ms3d_model._triangles) ms3d_triangle = Ms3dTriangle() ms3d_triangle.__index = index bmv0 = bmf.verts[0] bmv1 = bmf.verts[1] bmv2 = bmf.verts[2] ms3d_vertex0 = blender_to_ms3d_vertices[bmv0] ms3d_vertex1 = blender_to_ms3d_vertices[bmv1] ms3d_vertex2 = blender_to_ms3d_vertices[bmv2] ms3d_vertex0.reference_count += 1 ms3d_vertex1.reference_count += 1 ms3d_vertex2.reference_count += 1 ms3d_triangle._vertex_indices = ( ms3d_vertex0.__index, ms3d_vertex1.__index, ms3d_vertex2.__index, ) ms3d_triangle._vertex_normals = ( self.geometry_correction(bmv0.normal), self.geometry_correction(bmv1.normal), self.geometry_correction(bmv2.normal), ) ms3d_triangle._s = ( bmf.loops[0][layer_uv].uv.x, bmf.loops[1][layer_uv].uv.x, bmf.loops[2][layer_uv].uv.x, ) ms3d_triangle._t = ( 1.0 - bmf.loops[0][layer_uv].uv.y, 1.0 - bmf.loops[1][layer_uv].uv.y, 1.0 - bmf.loops[2][layer_uv].uv.y, ) ms3d_triangle.smoothing_group = bmf[layer_smoothing_group] ms3d_model._triangles.append(ms3d_triangle) ms3d_material = self.get_ms3d_material_add_if( blender_mesh, ms3d_model, blender_to_ms3d_materials, bmf.material_index) ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group]) ##EXPORT_ACTIVE_ONLY: if ms3d_group is not None: if ms3d_material is None: ms3d_group.material_index = \ Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX else: if ms3d_group.material_index is None: ms3d_group.material_index = \ ms3d_material.__index else: if ms3d_group.material_index != \ ms3d_material.__index: ms3d_group = \ self.get_ms3d_group_by_material_add_if( ms3d_model, ms3d_material) else: if ms3d_material is not None: ms3d_group = self.get_ms3d_group_by_material_add_if( ms3d_model, ms3d_material) else: ms3d_group = self.get_ms3d_group_default_material_add_if( ms3d_model) if ms3d_group is not None: ms3d_group._triangle_indices.append( ms3d_triangle.__index) ms3d_triangle.group_index = ms3d_group.__index blender_to_ms3d_triangles[bmf] = ms3d_triangle if bm is not None: bm.free() enable_edit_mode(False, blender_context) ########################## # remove the temporary data blender_scene.objects.unlink(blender_mesh_object_temp) if blender_mesh_temp is not None: blender_mesh_temp.user_clear() blender_context.blend_data.meshes.remove(blender_mesh_temp) blender_mesh_temp = None if blender_mesh_object_temp is not None: blender_mesh_temp = blender_mesh_object_temp.data.user_clear() blender_mesh_object_temp.user_clear() blender_context.blend_data.objects.remove( blender_mesh_object_temp) if blender_mesh_temp is not None: blender_mesh_temp.user_clear() blender_context.blend_data.meshes.remove(blender_mesh_temp)
def create_geometry(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones): blender_scene = blender_context.scene blender_to_ms3d_vertices = {} blender_to_ms3d_triangles = {} blender_to_ms3d_groups = {} blender_to_ms3d_materials = {} for blender_mesh_object in blender_mesh_objects: blender_mesh = blender_mesh_object.data ms3d_model._model_ex_object.joint_size = \ blender_mesh.ms3d.joint_size ms3d_model._model_ex_object.alpha_ref = blender_mesh.ms3d.alpha_ref ms3d_model._model_ex_object.transparency_mode = \ Ms3dUi.transparency_mode_to_ms3d( blender_mesh.ms3d.transparency_mode) if blender_mesh.ms3d.comment: ms3d_model._comment_object = Ms3dComment(blender_mesh.ms3d.comment) ########################## # prepare ms3d groups if available # works only for exporting active object ##EXPORT_ACTIVE_ONLY: for ms3d_local_group_index, blender_ms3d_group in enumerate( blender_mesh.ms3d.groups): ms3d_group = Ms3dGroup() ms3d_group.__index = len(ms3d_model._groups) ms3d_group.name = blender_ms3d_group.name ms3d_group.flags = Ms3dUi.flags_to_ms3d(blender_ms3d_group.flags) if blender_ms3d_group.comment: ms3d_group._comment_object = Ms3dCommentEx() ms3d_group._comment_object.comment = \ blender_ms3d_group.comment ms3d_group._comment_object.index = len(ms3d_model._groups) ms3d_group.material_index = None # to mark as not setted ms3d_model._groups.append(ms3d_group) blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group ########################## # i have to use BMesh, because there are several custom data stored. # BMesh doesn't support quads_convert_to_tris() # so, i use that very ugly way: # create a complete copy of mesh and bend object data # to be able to apply operations to it. # temporary, create a full heavy copy of the model # (object, mesh, modifiers) blender_mesh_temp = blender_mesh_object.data.copy() blender_mesh_object_temp = blender_mesh_object.copy() blender_mesh_object_temp.data = blender_mesh_temp blender_scene.objects.link(blender_mesh_object_temp) blender_scene.objects.active = blender_mesh_object_temp # apply transform if self.options_apply_transform: matrix_transform = blender_mesh_object_temp.matrix_basis else: matrix_transform = 1 # apply modifiers for modifier in blender_mesh_object_temp.modifiers: if self.options_apply_modifiers: # disable only armature modifiers and only, # when use_animation is enabled if self.options_use_animation \ and modifier.type in {'ARMATURE', }: modifier.show_viewport = False modifier.show_render = False else: # disable all modifiers, # to be able to add and apply triangulate modifier later modifier.show_viewport = False modifier.show_render = False # convert to tris by using the triangulate modifier blender_mesh_object_temp.modifiers.new("temp", 'TRIANGULATE') blender_mesh_temp = blender_mesh_object_temp.to_mesh( blender_scene, True, self.options_apply_modifiers_mode) enable_edit_mode(True, blender_context) bm = bmesh.new() bm.from_mesh(blender_mesh_temp) layer_texture = bm.faces.layers.tex.get( ms3d_str['OBJECT_LAYER_TEXTURE']) if layer_texture is None: layer_texture = bm.faces.layers.tex.new( ms3d_str['OBJECT_LAYER_TEXTURE']) layer_smoothing_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) if layer_smoothing_group is None: layer_smoothing_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) layer_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_GROUP']) if layer_group is None: layer_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_GROUP']) layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV']) if layer_uv is None: if bm.loops.layers.uv: layer_uv = bm.loops.layers.uv[0] else: layer_uv = bm.loops.layers.uv.new( ms3d_str['OBJECT_LAYER_UV']) layer_deform = bm.verts.layers.deform.active layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA']) if layer_extra is None: layer_extra = bm.verts.layers.int.new( ms3d_str['OBJECT_LAYER_EXTRA']) ########################## # handle vertices for bmv in bm.verts: item = blender_to_ms3d_vertices.get(bmv) if item is None: index = len(ms3d_model._vertices) ms3d_vertex = Ms3dVertex() ms3d_vertex.__index = index ms3d_vertex._vertex = self.geometry_correction( matrix_transform * bmv.co) if self.options_use_animation and layer_deform: blender_vertex_group_ids = bmv[layer_deform] if blender_vertex_group_ids: bone_weights = {} for blender_index, blender_weight \ in blender_vertex_group_ids.items(): ms3d_joint = blender_to_ms3d_bones.get( blender_mesh_object_temp.vertex_groups[\ blender_index].name) if ms3d_joint: weight = bone_weights.get(ms3d_joint.__index) if not weight: weight = 0 bone_weights[ms3d_joint.__index] = weight + blender_weight # sort (bone_id: weight) according its weights # to skip only less important weights in the next pass bone_weights_sorted = sorted(bone_weights.items(), key=lambda item: item[1], reverse=True) count = 0 bone_ids = [] weights = [] for ms3d_index, blender_weight \ in bone_weights_sorted: if count == 0: ms3d_vertex.bone_id = ms3d_index weights.append(blender_weight) elif count == 1: bone_ids.append(ms3d_index) weights.append(blender_weight) elif count == 2: bone_ids.append(ms3d_index) weights.append(blender_weight) elif count == 3: bone_ids.append(ms3d_index) if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_EXPORT_SKIP_WEIGHT']) else: # only first three weights will be supported / four bones if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL: self.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_EXPORT_SKIP_WEIGHT_EX']) break count += 1 # normalize weights to 100% if self.options_normalize_weights: weight_sum = 0.0 for weight in weights: weight_sum += weight if weight_sum > 0.0: weight_normalize = 1.0 / weight_sum else: weight_normalize = 1.0 weight_sum = 100 for index, weight in enumerate(weights): if index >= count-1 or index >= 2: # take the full rest instead of calculate, # that should fill up to exactly 100% # (in some cases it is only 99% bacaus of roulding errors) weights[index] = int(weight_sum) break normalized_weight = int(weight * weight_normalize * 100) weights[index] = normalized_weight weight_sum -= normalized_weight # fill up missing values while len(bone_ids) < 3: bone_ids.append(Ms3dSpec.DEFAULT_VERTEX_BONE_ID) while len(weights) < 3: weights.append(0) ms3d_vertex._vertex_ex_object._bone_ids = \ tuple(bone_ids) ms3d_vertex._vertex_ex_object._weights = \ tuple(weights) if layer_extra: #ms3d_vertex._vertex_ex_object.extra = bmv[layer_extra] # bm.verts.layers.int does only support signed int32 # convert signed int32 to unsigned int32 (little-endian) signed_int32 = bmv[layer_extra] bytes_int32 = signed_int32.to_bytes( 4, byteorder='little', signed=True) unsigned_int32 = int.from_bytes( bytes_int32, byteorder='little', signed=False) ms3d_vertex._vertex_ex_object.extra = unsigned_int32 ms3d_model._vertices.append(ms3d_vertex) blender_to_ms3d_vertices[bmv] = ms3d_vertex ########################## # handle faces / tris for bmf in bm.faces: item = blender_to_ms3d_triangles.get(bmf) if item is None: index = len(ms3d_model._triangles) ms3d_triangle = Ms3dTriangle() ms3d_triangle.__index = index bmv0 = bmf.verts[0] bmv1 = bmf.verts[1] bmv2 = bmf.verts[2] ms3d_vertex0 = blender_to_ms3d_vertices[bmv0] ms3d_vertex1 = blender_to_ms3d_vertices[bmv1] ms3d_vertex2 = blender_to_ms3d_vertices[bmv2] ms3d_vertex0.reference_count += 1 ms3d_vertex1.reference_count += 1 ms3d_vertex2.reference_count += 1 ms3d_triangle._vertex_indices = ( ms3d_vertex0.__index, ms3d_vertex1.__index, ms3d_vertex2.__index, ) ms3d_triangle._vertex_normals = ( self.geometry_correction(bmv0.normal), self.geometry_correction(bmv1.normal), self.geometry_correction(bmv2.normal), ) ms3d_triangle._s = ( bmf.loops[0][layer_uv].uv.x, bmf.loops[1][layer_uv].uv.x, bmf.loops[2][layer_uv].uv.x, ) ms3d_triangle._t = ( 1.0 - bmf.loops[0][layer_uv].uv.y, 1.0 - bmf.loops[1][layer_uv].uv.y, 1.0 - bmf.loops[2][layer_uv].uv.y, ) ms3d_triangle.smoothing_group = bmf[layer_smoothing_group] ms3d_model._triangles.append(ms3d_triangle) ms3d_material = self.get_ms3d_material_add_if( blender_mesh, ms3d_model, blender_to_ms3d_materials, bmf.material_index) ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group]) ##EXPORT_ACTIVE_ONLY: if ms3d_group is not None: if ms3d_material is None: ms3d_group.material_index = \ Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX else: if ms3d_group.material_index is None: ms3d_group.material_index = \ ms3d_material.__index else: if ms3d_group.material_index != \ ms3d_material.__index: ms3d_group = \ self.get_ms3d_group_by_material_add_if( ms3d_model, ms3d_material) else: if ms3d_material is not None: ms3d_group = self.get_ms3d_group_by_material_add_if( ms3d_model, ms3d_material) else: ms3d_group = self.get_ms3d_group_default_material_add_if( ms3d_model) if ms3d_group is not None: ms3d_group._triangle_indices.append( ms3d_triangle.__index) ms3d_triangle.group_index = ms3d_group.__index blender_to_ms3d_triangles[bmf] = ms3d_triangle if bm is not None: bm.free() enable_edit_mode(False, blender_context) ########################## # remove the temporary data blender_scene.objects.unlink(blender_mesh_object_temp) if blender_mesh_temp is not None: blender_mesh_temp.user_clear() blender_context.blend_data.meshes.remove(blender_mesh_temp) blender_mesh_temp = None if blender_mesh_object_temp is not None: blender_mesh_temp = blender_mesh_object_temp.data.user_clear() blender_mesh_object_temp.user_clear() blender_context.blend_data.objects.remove( blender_mesh_object_temp) if blender_mesh_temp is not None: blender_mesh_temp.user_clear() blender_context.blend_data.meshes.remove(blender_mesh_temp)
def create_geometry(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones): blender_scene = blender_context.scene blender_to_ms3d_vertices = {} blender_to_ms3d_triangles = {} blender_to_ms3d_groups = {} blender_to_ms3d_materials = {} for blender_mesh_object in blender_mesh_objects: blender_mesh = blender_mesh_object.data ########################## # prepare ms3d groups if available # works only for exporting active object ##EXPORT_ACTIVE_ONLY: for ms3d_local_group_index, blender_ms3d_group in enumerate(blender_mesh.ms3d.groups): ms3d_group = Ms3dGroup() ms3d_group.__index = len(ms3d_model._groups) ms3d_group.name = blender_ms3d_group.name ms3d_group.flags = Ms3dUi.flags_to_ms3d(blender_ms3d_group.flags) if blender_ms3d_group.comment: ms3d_group._comment_object = Ms3dCommentEx() ms3d_group._comment_object.comment = blender_ms3d_group.comment ms3d_group._comment_object.index = len(ms3d_model._groups) ms3d_group.material_index = None # to mark as not setted ms3d_model._groups.append(ms3d_group) blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group ########################## # i have to use BMesh, because there are several custom data stored. # BMesh doesn't support quads_convert_to_tris() # so, i use that very ugly way: # create a complete copy of mesh and bend object data # to be able to apply operations to it. # get a temporary mesh with applied modifiers if self.options.prop_apply_modifier: blender_mesh_temp = blender_mesh_object.to_mesh( blender_scene, self.options.prop_apply_modifier, self.options.prop_apply_modifier_mode ) else: blender_mesh_temp = blender_mesh_object.data.copy() # assign temporary mesh as new object data blender_mesh_object.data = blender_mesh_temp # convert to tris enable_edit_mode(True) select_all(True) if ops.mesh.quads_convert_to_tris.poll(): ops.mesh.quads_convert_to_tris() enable_edit_mode(False) enable_edit_mode(True) bm = bmesh.from_edit_mesh(blender_mesh_temp) layer_texture = bm.faces.layers.tex.get(ms3d_str["OBJECT_LAYER_TEXTURE"]) if layer_texture is None: layer_texture = bm.faces.layers.tex.new(ms3d_str["OBJECT_LAYER_TEXTURE"]) layer_smoothing_group = bm.faces.layers.int.get(ms3d_str["OBJECT_LAYER_SMOOTHING_GROUP"]) if layer_smoothing_group is None: layer_smoothing_group = bm.faces.layers.int.new(ms3d_str["OBJECT_LAYER_SMOOTHING_GROUP"]) layer_group = bm.faces.layers.int.get(ms3d_str["OBJECT_LAYER_GROUP"]) if layer_group is None: layer_group = bm.faces.layers.int.new(ms3d_str["OBJECT_LAYER_GROUP"]) layer_uv = bm.loops.layers.uv.get(ms3d_str["OBJECT_LAYER_UV"]) if layer_uv is None: if bm.loops.layers.uv: layer_uv = bm.loops.layers.uv[0] else: layer_uv = bm.loops.layers.uv.new(ms3d_str["OBJECT_LAYER_UV"]) layer_deform = bm.verts.layers.deform.active ########################## # handle vertices for bmv in bm.verts: item = blender_to_ms3d_vertices.get(bmv) if item is None: index = len(ms3d_model._vertices) ms3d_vertex = Ms3dVertex() ms3d_vertex.__index = index ms3d_vertex._vertex = ( self.matrix_scaled_coordination_system * (bmv.co + blender_mesh_object.location) )[:] if layer_deform: blender_vertex_group_ids = bmv[layer_deform] if blender_vertex_group_ids: temp_weight = 0 count = 0 for blender_index, blender_weight in blender_vertex_group_ids.items(): ms3d_joint = blender_to_ms3d_bones.get( blender_mesh_object.vertex_groups[blender_index].name ) if ms3d_joint: if count == 0: ms3d_vertex.bone_id = ms3d_joint.__index temp_weight = blender_weight elif count == 1: ms3d_vertex._vertex_ex_object.bone_ids[0] = ms3d_joint.__index ms3d_vertex._vertex_ex_object.weights[0] = temp_weight * 100 ms3d_vertex._vertex_ex_object.weights[1] = blender_weight * 100 elif count == 2: ms3d_vertex._vertex_ex_object.bone_ids[1] = ms3d_joint.__index ms3d_vertex._vertex_ex_object.weights[2] = blender_weight * 100 # elif count == 3: # ms3d_vertex._vertex_ex_object.bone_ids[2] = ms3d_joint.__index # only first three weights will be supported count += 1 if count > 3: break ms3d_model._vertices.append(ms3d_vertex) blender_to_ms3d_vertices[bmv] = ms3d_vertex ########################## # handle faces / tris for bmf in bm.faces: item = blender_to_ms3d_triangles.get(bmf) if item is None: index = len(ms3d_model._triangles) ms3d_triangle = Ms3dTriangle() ms3d_triangle.__index = index bmv0 = bmf.verts[0] bmv1 = bmf.verts[1] bmv2 = bmf.verts[2] ms3d_vertex0 = blender_to_ms3d_vertices[bmv0] ms3d_vertex1 = blender_to_ms3d_vertices[bmv1] ms3d_vertex2 = blender_to_ms3d_vertices[bmv2] ms3d_vertex0.reference_count += 1 ms3d_vertex1.reference_count += 1 ms3d_vertex2.reference_count += 1 ms3d_triangle._vertex_indices = (ms3d_vertex0.__index, ms3d_vertex1.__index, ms3d_vertex2.__index) ms3d_triangle._vertex_normals = ( (self.matrix_coordination_system * bmv0.normal)[:], (self.matrix_coordination_system * bmv1.normal)[:], (self.matrix_coordination_system * bmv2.normal)[:], ) ms3d_triangle._s = ( bmf.loops[0][layer_uv].uv.x, bmf.loops[1][layer_uv].uv.x, bmf.loops[2][layer_uv].uv.x, ) ms3d_triangle._t = ( 1.0 - bmf.loops[0][layer_uv].uv.y, 1.0 - bmf.loops[1][layer_uv].uv.y, 1.0 - bmf.loops[2][layer_uv].uv.y, ) ms3d_triangle.smoothing_group = bmf[layer_smoothing_group] ms3d_model._triangles.append(ms3d_triangle) ms3d_material = self.get_ms3d_material_add_if( blender_mesh, ms3d_model, blender_to_ms3d_materials, bmf.material_index ) ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group]) ##EXPORT_ACTIVE_ONLY: if ms3d_group is not None: if ms3d_material is None: ms3d_group.material_index = Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX else: if ms3d_group.material_index is None: ms3d_group.material_index = ms3d_material.__index else: if ms3d_group.material_index != ms3d_material.__index: ms3d_group = self.get_ms3d_group_by_material_add_if(ms3d_model, ms3d_material) else: if ms3d_material is not None: ms3d_group = self.get_ms3d_group_by_material_add_if(ms3d_model, ms3d_material) else: ms3d_group = self.get_ms3d_group_default_material_add_if(ms3d_model) if ms3d_group is not None: ms3d_group._triangle_indices.append(ms3d_triangle.__index) ms3d_triangle.group_index = ms3d_group.__index blender_to_ms3d_triangles[bmf] = ms3d_triangle if bm is not None: bm.free() enable_edit_mode(False) ########################## # restore original object data blender_mesh_object.data = blender_mesh ########################## # remove the temporary data if blender_mesh_temp is not None: blender_mesh_temp.user_clear() blender_context.blend_data.meshes.remove(blender_mesh_temp)
def create_geometry(self, blender_context, ms3d_model): ########################## # blender stuff: # create a blender Mesh blender_mesh = blender_context.blend_data.meshes.new( ms3d_model.name + ".m") blender_mesh.ms3d.name = ms3d_model.name ms3d_comment = ms3d_model.comment_object if ms3d_comment is not None: blender_mesh.ms3d.comment = ms3d_comment.comment ms3d_model_ex = ms3d_model.model_ex_object if ms3d_model_ex is not None: blender_mesh.ms3d.joint_size = ms3d_model_ex.joint_size blender_mesh.ms3d.alpha_ref = ms3d_model_ex.alpha_ref blender_mesh.ms3d.transparency_mode \ = Ms3dUi.transparency_mode_from_ms3d( ms3d_model_ex.transparency_mode) ########################## # blender stuff: # link to blender object blender_mesh_object = blender_context.blend_data.objects.new( ms3d_model.name + ".m", blender_mesh) ########################## # blender stuff: # create edge split modifire, to make sharp edges visible blender_modifier = get_edge_split_modifier_add_if(blender_mesh_object) ########################## # blender stuff: # link to blender scene blender_scene = blender_context.scene blender_scene.objects.link(blender_mesh_object) #blender_mesh_object.location = blender_scene.cursor_location enable_edit_mode(False) select_all(False) blender_mesh_object.select = True blender_scene.objects.active = blender_mesh_object ########################## # blender stuff: # create all (ms3d) groups ms3d_to_blender_group_index = {} blender_group_manager = blender_mesh.ms3d for ms3d_group_index, ms3d_group in enumerate(ms3d_model.groups): blender_group = blender_group_manager.create_group() blender_group.name = ms3d_group.name blender_group.flags = Ms3dUi.flags_from_ms3d(ms3d_group.flags) blender_group.material_index = ms3d_group.material_index ms3d_comment = ms3d_group.comment_object if ms3d_comment is not None: blender_group.comment = ms3d_comment.comment # translation dictionary ms3d_to_blender_group_index[ms3d_group_index] = blender_group.id #################################################### # begin BMesh stuff # ########################## # BMesh stuff: # create an empty BMesh bm = bmesh.new() ########################## # BMesh stuff: # create new Layers for custom data per "mesh face" layer_texture = bm.faces.layers.tex.get( ms3d_str['OBJECT_LAYER_TEXTURE']) if layer_texture is None: layer_texture = bm.faces.layers.tex.new( ms3d_str['OBJECT_LAYER_TEXTURE']) layer_smoothing_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) if layer_smoothing_group is None: layer_smoothing_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP']) layer_group = bm.faces.layers.int.get( ms3d_str['OBJECT_LAYER_GROUP']) if layer_group is None: layer_group = bm.faces.layers.int.new( ms3d_str['OBJECT_LAYER_GROUP']) ########################## # BMesh stuff: # create new Layers for custom data per "face vertex" layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV']) if layer_uv is None: layer_uv = bm.loops.layers.uv.new(ms3d_str['OBJECT_LAYER_UV']) ########################## # BMesh stuff: # create all vertices for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices): bmv = bm.verts.new( self.matrix_scaled_coordination_system * Vector(ms3d_vertex.vertex)) ########################## # blender stuff (uses BMesh stuff): # create all materials / image textures ms3d_to_blender_material = {} for ms3d_material_index, ms3d_material in enumerate( ms3d_model.materials): blender_material = blender_context.blend_data.materials.new( ms3d_material.name) # custom datas blender_material.ms3d.name = ms3d_material.name blender_material.ms3d.ambient = ms3d_material.ambient blender_material.ms3d.diffuse = ms3d_material.diffuse blender_material.ms3d.specular = ms3d_material.specular blender_material.ms3d.emissive = ms3d_material.emissive blender_material.ms3d.shininess = ms3d_material.shininess blender_material.ms3d.transparency = ms3d_material.transparency blender_material.ms3d.mode = Ms3dUi.texture_mode_from_ms3d( ms3d_material.mode) if ms3d_material.texture: blender_material.ms3d.texture = ms3d_material.texture if ms3d_material.alphamap: blender_material.ms3d.alphamap = ms3d_material.alphamap ms3d_comment = ms3d_material.comment_object if ms3d_comment is not None: blender_material.ms3d.comment = ms3d_comment.comment # blender datas blender_material.ambient = (( (ms3d_material.ambient[0] + ms3d_material.ambient[1] + ms3d_material.ambient[2]) / 3.0) * ms3d_material.ambient[3]) blender_material.diffuse_color[0] = ms3d_material.diffuse[0] blender_material.diffuse_color[1] = ms3d_material.diffuse[1] blender_material.diffuse_color[2] = ms3d_material.diffuse[2] blender_material.diffuse_intensity = ms3d_material.diffuse[3] blender_material.specular_color[0] = ms3d_material.specular[0] blender_material.specular_color[1] = ms3d_material.specular[1] blender_material.specular_color[2] = ms3d_material.specular[2] blender_material.specular_intensity = ms3d_material.specular[3] blender_material.emit = (( (ms3d_material.emissive[0] + ms3d_material.emissive[1] + ms3d_material.emissive[2]) / 3.0) * ms3d_material.emissive[3]) blender_material.specular_hardness = ms3d_material.shininess * 2.0 if (ms3d_material.transparency): blender_material.use_transparency = True blender_material.alpha = ms3d_material.transparency blender_material.specular_alpha = blender_material.alpha if (blender_material.game_settings): blender_material.game_settings.use_backface_culling = False blender_material.game_settings.alpha_blend = 'ALPHA' # diffuse texture if ms3d_material.texture: dir_name_diffuse = self.filepath_splitted[0] file_name_diffuse = path.split(ms3d_material.texture)[1] blender_image_diffuse = load_image( file_name_diffuse, dir_name_diffuse) blender_texture_diffuse = blender_context.blend_data.textures.new( name=file_name_diffuse, type='IMAGE') blender_texture_diffuse.image = blender_image_diffuse blender_texture_slot_diffuse \ = blender_material.texture_slots.add() blender_texture_slot_diffuse.texture = blender_texture_diffuse blender_texture_slot_diffuse.texture_coords = 'UV' blender_texture_slot_diffuse.uv_layer = layer_uv.name blender_texture_slot_diffuse.use_map_color_diffuse = True blender_texture_slot_diffuse.use_map_alpha = False if blender_image_diffuse is not None: self.has_textures = True else: blender_image_diffuse = None # alpha texture if ms3d_material.alphamap: dir_name_alpha = self.filepath_splitted[0] file_name_alpha = path.split(ms3d_material.alphamap)[1] blender_image_alpha = load_image( file_name_alpha, dir_name_alpha) blender_texture_alpha = blender_context.blend_data.textures.new( name=file_name_alpha, type='IMAGE') blender_texture_alpha.image = blender_image_alpha blender_texture_slot_alpha \ = blender_material.texture_slots.add() blender_texture_slot_alpha.texture = blender_texture_alpha blender_texture_slot_alpha.texture_coords = 'UV' blender_texture_slot_alpha.uv_layer = layer_uv.name blender_texture_slot_alpha.use_map_color_diffuse = False blender_texture_slot_alpha.use_map_alpha = True blender_texture_slot_alpha.use_rgb_to_intensity = True blender_material.alpha = 0 blender_material.specular_alpha = 0 # append blender material to blender mesh, to be linked to blender_mesh.materials.append(blender_material) # translation dictionary ms3d_to_blender_material[ms3d_material_index] \ = blender_image_diffuse ########################## # BMesh stuff: # create all triangles smoothing_group_blender_faces = {} for ms3d_triangle_index, ms3d_triangle in enumerate( ms3d_model.triangles): bmv_list = [] for vert_index in ms3d_triangle.vertex_indices: bmv = bm.verts[vert_index] if [[x] for x in bmv_list if x == bmv]: self.options.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_SKIP_VERTEX_DOUBLE'].format( ms3d_triangle_index)) continue bmv_list.append(bmv) if len(bmv_list) < 3: self.options.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_SKIP_LESS_VERTICES'].format( ms3d_triangle_index)) continue bmf = bm.faces.get(bmv_list) if bmf is not None: self.options.report( {'WARNING', 'INFO'}, ms3d_str['WARNING_IMPORT_SKIP_FACE_DOUBLE'].format( ms3d_triangle_index)) continue bmf = bm.faces.new(bmv_list) # blender uv custom data per "face vertex" bmf.loops[0][layer_uv].uv = Vector( (ms3d_triangle.s[0], 1.0 - ms3d_triangle.t[0])) bmf.loops[1][layer_uv].uv = Vector( (ms3d_triangle.s[1], 1.0 - ms3d_triangle.t[1])) bmf.loops[2][layer_uv].uv = Vector( (ms3d_triangle.s[2], 1.0 - ms3d_triangle.t[2])) # ms3d custom data per "mesh face" bmf[layer_smoothing_group] = ms3d_triangle.smoothing_group blender_group_id = ms3d_to_blender_group_index.get( ms3d_triangle.group_index) if blender_group_id is not None: bmf[layer_group] = blender_group_id if ms3d_triangle.group_index >= 0 \ and ms3d_triangle.group_index < len(ms3d_model.groups): ms3d_material_index \ = ms3d_model.groups[ms3d_triangle.group_index].material_index if ms3d_material_index != Ms3dSpec.NONE_GROUP_MATERIAL_INDEX: # BMFace.material_index expects... # index of material in types.Mesh.materials, # not index of material in blender_context.blend_data.materials! bmf.material_index = ms3d_material_index # apply diffuse texture image to face, to be visible in 3d view bmf[layer_texture].image = ms3d_to_blender_material.get( ms3d_material_index) else: # set material index to highes possible index # - in most cases there is no maretial assigned ;) bmf.material_index = 32766 pass # helper dictionary for post-processing smoothing_groups smoothing_group_blender_face = smoothing_group_blender_faces.get( ms3d_triangle.smoothing_group) if smoothing_group_blender_face is None: smoothing_group_blender_face = [] smoothing_group_blender_faces[ms3d_triangle.smoothing_group] \ = smoothing_group_blender_face smoothing_group_blender_face.append(bmf) ########################## # BMesh stuff: # create all sharp edges for blender to make smoothing_groups visible for ms3d_smoothing_group_index, blender_face_list \ in smoothing_group_blender_faces.items(): edge_dict = {} for bmf in blender_face_list: bmf.smooth = True for bme in bmf.edges: if edge_dict.get(bme) is None: edge_dict[bme] = 0 else: edge_dict[bme] += 1 bme.seam = (edge_dict[bme] == 0) bme.smooth = (edge_dict[bme] != 0) ########################## # BMesh stuff: # finally tranfer BMesh to Mesh bm.to_mesh(blender_mesh) bm.free() # # end BMesh stuff #################################################### return blender_mesh_object