def get_ms3d_group_by_material_add_if(self, ms3d_model, ms3d_material): if ms3d_material.__index < 0 \ or ms3d_material.__index >= len(ms3d_model.materials): return None markerName = "MaterialGroup.{}".format(ms3d_material.__index) markerComment = "MaterialGroup({})".format(ms3d_material.name) for ms3d_group in ms3d_model._groups: if ms3d_group.name == markerName \ and ms3d_group._comment_object \ and ms3d_group._comment_object.comment == markerComment: return ms3d_group ms3d_group = Ms3dGroup() ms3d_group.__index = len(ms3d_model._groups) ms3d_group.name = markerName ms3d_group._comment_object = Ms3dCommentEx() ms3d_group._comment_object.comment = markerComment ms3d_group._comment_object.index = len(ms3d_model._groups) ms3d_group.material_index = ms3d_material.__index ms3d_model._groups.append(ms3d_group) return ms3d_group
def get_ms3d_group_default_material_add_if(self, ms3d_model): markerName = "MaterialGroupDefault" markerComment = "group without material" for ms3d_group in ms3d_model._groups: if ms3d_group.material_index == \ Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX \ and ms3d_group.name == markerName \ and ms3d_group._comment_object \ and ms3d_group._comment_object.comment == markerComment: return ms3d_group ms3d_group = Ms3dGroup() ms3d_group.__index = len(ms3d_model._groups) ms3d_group.name = markerName ms3d_group._comment_object = Ms3dCommentEx() ms3d_group._comment_object.comment = markerComment ms3d_group._comment_object.index = len(ms3d_model._groups) ms3d_group.material_index = Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX ms3d_model._groups.append(ms3d_group) return ms3d_group
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)