def create_animation(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones): ########################## # setup scene blender_scene = blender_context.scene ms3d_model.animation_fps = blender_scene.render.fps * blender_scene.render.fps_base ms3d_model.number_total_frames = (blender_scene.frame_end - blender_scene.frame_start) + 1 ms3d_model.current_time = (blender_scene.frame_current - blender_scene.frame_start) / ( blender_scene.render.fps * blender_scene.render.fps_base ) # return ### not ready yet for blender_mesh_object in blender_mesh_objects: blender_bones = None for blender_modifier in blender_mesh_object.modifiers: if blender_modifier.type == "ARMATURE" and blender_modifier.object.pose: blender_bones = blender_modifier.object.data.bones break for blender_bone_oject in blender_bones: ms3d_joint = Ms3dJoint() ms3d_joint.__index = len(ms3d_model._joints) blender_ms3d_joint = blender_bone_oject.ms3d blender_bone = blender_bone_oject ms3d_joint.flags = Ms3dUi.flags_to_ms3d(blender_ms3d_joint.flags) if blender_ms3d_joint.comment: ms3d_joint._comment_object = Ms3dCommentEx() ms3d_joint._comment_object.comment = blender_ms3d_joint.comment ms3d_joint._comment_object.index = ms3d_joint.__index ms3d_joint.joint_ex_object._color = blender_ms3d_joint.color[:] if blender_ms3d_joint.name: ms3d_joint.name = blender_ms3d_joint.name else: ms3d_joint.name = blender_bone.name if blender_bone.parent: if blender_ms3d_joint.name: ms3d_joint.parent_name = blender_bone.parent.ms3d.name else: ms3d_joint.parent_name = blender_bone.parent.name ms3d_joint_vector = blender_bone.head * self.matrix_scaled_coordination_system blender_bone_euler = blender_bone.matrix.to_euler("XZY") else: ms3d_joint_vector = blender_bone.head * self.matrix_scaled_coordination_system blender_bone_euler = blender_bone.matrix.to_euler("XZY") ms3d_joint._position = ms3d_joint_vector[:] ms3d_joint._rotation = (Vector(blender_bone_euler[:]) * self.matrix_scaled_coordination_system)[:] ms3d_model._joints.append(ms3d_joint) blender_to_ms3d_bones[blender_bone.name] = ms3d_joint
def create_animation(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones): ########################## # setup scene blender_scene = blender_context.scene if not self.options_use_animation: ms3d_model.animation_fps = 24 ms3d_model.number_total_frames = 1 ms3d_model.current_time = 0 return frame_start = blender_scene.frame_start frame_end = blender_scene.frame_end frame_total = (frame_end - frame_start) + 1 frame_step = blender_scene.frame_step frame_offset = 0 fps = blender_scene.render.fps * blender_scene.render.fps_base time_base = 1.0 / fps base_bone_correction = Matrix.Rotation(pi / 2, 4, 'Z') for blender_mesh_object in blender_mesh_objects: blender_bones = None blender_action = None blender_nla_tracks = None # note: only one armature modifier/parent will be handled. # if the parent is an armature, it will be handled irrespective # of existence of any armature modifier # question: maybe it is better to handle # all existing armature sources (parent / modifier) # as a merged animation... # what is best practice in case of multiple animation sources? # take parent to account if it is an armature if blender_mesh_object.parent and \ blender_mesh_object.parent_type == 'ARMATURE' and \ blender_mesh_object.parent.pose: blender_bones = blender_mesh_object.parent.data.bones blender_pose_bones = blender_mesh_object.parent.pose.bones if blender_mesh_object.parent.animation_data: blender_action = \ blender_mesh_object.parent.animation_data.action blender_nla_tracks = \ blender_mesh_object.parent.animation_data.nla_tracks # apply transform if self.options_apply_transform: matrix_transform = blender_mesh_object.parent.matrix_basis else: matrix_transform = 1 # search for animation modifier else: for blender_modifier in blender_mesh_object.modifiers: if blender_modifier.type == 'ARMATURE' \ and blender_modifier.object.pose: blender_bones = blender_modifier.object.data.bones blender_pose_bones = blender_modifier.object.pose.bones if blender_modifier.object.animation_data: blender_action = \ blender_modifier.object.animation_data.action blender_nla_tracks = \ blender_modifier.object.animation_data.nla_tracks # apply transform if self.options_apply_transform: matrix_transform = blender_modifier.object.matrix_basis else: matrix_transform = 1 break # skip animation/bone handling, if no animation data is available if blender_bones is None \ and (blender_action is None and blender_nla_tracks is None): continue ########################## # bones blender_bones_ordered = [] self.build_blender_bone_dependency_order(blender_bones, blender_bones_ordered) for blender_bone_name in blender_bones_ordered: blender_bone_oject = blender_bones[blender_bone_name] ms3d_joint = Ms3dJoint() ms3d_joint.__index = len(ms3d_model._joints) blender_bone_ms3d = blender_bone_oject.ms3d blender_bone = blender_bone_oject ms3d_joint.flags = Ms3dUi.flags_to_ms3d( blender_bone_ms3d.flags) if blender_bone_ms3d.comment: ms3d_joint._comment_object = Ms3dCommentEx() ms3d_joint._comment_object.comment = \ blender_bone_ms3d.comment ms3d_joint._comment_object.index = ms3d_joint.__index ms3d_joint.joint_ex_object._color = blender_bone_ms3d.color[:] ms3d_joint.name = blender_bone.name if blender_bone.parent: ms3d_joint.parent_name = blender_bone.parent.name ms3d_joint.__matrix = matrix_difference( matrix_transform * blender_bone.matrix_local, matrix_transform * blender_bone.parent.matrix_local) else: ms3d_joint.__matrix = base_bone_correction \ * matrix_transform * blender_bone.matrix_local mat = ms3d_joint.__matrix loc = mat.to_translation() rot = mat.to_euler('XZY') ms3d_joint._position = self.joint_correction(loc) ms3d_joint._rotation = self.joint_correction(rot) ms3d_model._joints.append(ms3d_joint) blender_to_ms3d_bones[blender_bone.name] = ms3d_joint ########################## # animation frames = None frames_location = set() frames_rotation = set() frames_scale = set() if blender_action: self.fill_keyframe_sets(blender_action.fcurves, frames_location, frames_rotation, frames_scale, 0) if blender_nla_tracks: for nla_track in blender_nla_tracks: if nla_track.mute: continue for strip in nla_track.strips: if strip.mute: continue frame_correction = strip.frame_start \ - strip.action_frame_start self.fill_keyframe_sets(strip.action.fcurves, frames_location, frames_rotation, frames_scale, frame_correction) frames = set(frames_location) frames = frames.union(frames_rotation) frames = frames.union(frames_scale) if not self.options_shrink_to_keys: frames = frames.intersection( range(blender_scene.frame_start, blender_scene.frame_end + 1)) frames_sorted = list(frames) frames_sorted.sort() if self.options_shrink_to_keys and len(frames_sorted) >= 2: frame_start = frames_sorted[0] frame_end = frames_sorted[len(frames_sorted) - 1] frame_total = (frame_end - frame_start) + 1 frame_offset = frame_start - 1 if self.options_bake_each_frame: frames_sorted = range(int(frame_start), int(frame_end + 1), int(frame_step)) frame_temp = blender_scene.frame_current for current_frame in frames_sorted: blender_scene.frame_set(current_frame) current_time = (current_frame - frame_offset) * time_base for blender_bone_name in blender_bones_ordered: blender_bone = blender_bones[blender_bone_name] blender_pose_bone = blender_pose_bones[blender_bone_name] ms3d_joint = blender_to_ms3d_bones[blender_bone_name] m1 = blender_bone.matrix_local.inverted() if blender_pose_bone.parent: m2 = blender_pose_bone.parent.matrix_channel.inverted() else: m2 = 1 m3 = blender_pose_bone.matrix.copy() m = ((m1 * m2) * m3) loc = m.to_translation() rot = m.to_euler('XZY') ms3d_joint.translation_key_frames.append( Ms3dTranslationKeyframe(current_time, self.joint_correction(loc))) ms3d_joint.rotation_key_frames.append( Ms3dRotationKeyframe(current_time, self.joint_correction(rot))) blender_scene.frame_set(frame_temp) ms3d_model.animation_fps = fps if ms3d_model.number_joints > 0: ms3d_model.number_total_frames = int(frame_total) ms3d_model.current_time = ((blender_scene.frame_current \ - blender_scene.frame_start) + 1) * time_base else: ms3d_model.number_total_frames = 1 ms3d_model.current_time = 0
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_animation(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones): ########################## # setup scene blender_scene = blender_context.scene if not self.options_use_animation: ms3d_model.animation_fps = 24 ms3d_model.number_total_frames = 1 ms3d_model.current_time = 0 return frame_start = blender_scene.frame_start frame_end = blender_scene.frame_end frame_total = (frame_end - frame_start) + 1 frame_step = blender_scene.frame_step frame_offset = 0 fps = blender_scene.render.fps * blender_scene.render.fps_base time_base = 1.0 / fps base_bone_correction = Matrix.Rotation(pi / 2, 4, 'Z') for blender_mesh_object in blender_mesh_objects: blender_bones = None blender_action = None blender_nla_tracks = None for blender_modifier in blender_mesh_object.modifiers: if blender_modifier.type == 'ARMATURE' \ and blender_modifier.object.pose: blender_bones = blender_modifier.object.data.bones blender_pose_bones = blender_modifier.object.pose.bones if blender_modifier.object.animation_data: blender_action = \ blender_modifier.object.animation_data.action blender_nla_tracks = \ blender_modifier.object.animation_data.nla_tracks # apply transform if self.options_apply_transform: matrix_transform = blender_modifier.object.matrix_basis else: matrix_transform = 1 break if blender_bones is None \ and (blender_action is None and blender_nla_tracks is None): continue ########################## # bones blender_bones_ordered = [] self.build_blender_bone_dependency_order( blender_bones, blender_bones_ordered) for blender_bone_name in blender_bones_ordered: blender_bone_oject = blender_bones[blender_bone_name] ms3d_joint = Ms3dJoint() ms3d_joint.__index = len(ms3d_model._joints) blender_bone_ms3d = blender_bone_oject.ms3d blender_bone = blender_bone_oject ms3d_joint.flags = Ms3dUi.flags_to_ms3d(blender_bone_ms3d.flags) if blender_bone_ms3d.comment: ms3d_joint._comment_object = Ms3dCommentEx() ms3d_joint._comment_object.comment = \ blender_bone_ms3d.comment ms3d_joint._comment_object.index = ms3d_joint.__index ms3d_joint.joint_ex_object._color = blender_bone_ms3d.color[:] ms3d_joint.name = blender_bone.name if blender_bone.parent: ms3d_joint.parent_name = blender_bone.parent.name ms3d_joint.__matrix = matrix_difference( matrix_transform * blender_bone.matrix_local, matrix_transform * blender_bone.parent.matrix_local) else: ms3d_joint.__matrix = base_bone_correction \ * matrix_transform * blender_bone.matrix_local mat = ms3d_joint.__matrix loc = mat.to_translation() rot = mat.to_euler('XZY') ms3d_joint._position = self.joint_correction(loc) ms3d_joint._rotation = self.joint_correction(rot) ms3d_model._joints.append(ms3d_joint) blender_to_ms3d_bones[blender_bone.name] = ms3d_joint ########################## # animation frames = None frames_location = set() frames_rotation = set() frames_scale = set() if blender_action: self.fill_keyframe_sets( blender_action.fcurves, frames_location, frames_rotation, frames_scale, 0) if blender_nla_tracks: for nla_track in blender_nla_tracks: if nla_track.mute: continue for strip in nla_track.strips: if strip.mute: continue frame_correction = strip.frame_start \ - strip.action_frame_start self.fill_keyframe_sets( strip.action.fcurves, frames_location, frames_rotation, frames_scale, frame_correction) frames = set(frames_location) frames = frames.union(frames_rotation) frames = frames.union(frames_scale) if not self.options_shrink_to_keys: frames = frames.intersection(range( blender_scene.frame_start, blender_scene.frame_end + 1)) frames_sorted = list(frames) frames_sorted.sort() if self.options_shrink_to_keys and len(frames_sorted) >= 2: frame_start = frames_sorted[0] frame_end = frames_sorted[len(frames_sorted)-1] frame_total = (frame_end - frame_start) + 1 frame_offset = frame_start - 1 if self.options_bake_each_frame: frames_sorted = range(int(frame_start), int(frame_end + 1), int(frame_step)) frame_temp = blender_scene.frame_current for current_frame in frames_sorted: blender_scene.frame_set(current_frame) current_time = (current_frame - frame_offset) * time_base for blender_bone_name in blender_bones_ordered: blender_bone = blender_bones[blender_bone_name] blender_pose_bone = blender_pose_bones[blender_bone_name] ms3d_joint = blender_to_ms3d_bones[blender_bone_name] m1 = blender_bone.matrix_local.inverted() if blender_pose_bone.parent: m2 = blender_pose_bone.parent.matrix_channel.inverted() else: m2 = 1 m3 = blender_pose_bone.matrix.copy() m = ((m1 * m2) * m3) loc = m.to_translation() rot = m.to_euler('XZY') ms3d_joint.translation_key_frames.append( Ms3dTranslationKeyframe( current_time, self.joint_correction(loc) ) ) ms3d_joint.rotation_key_frames.append( Ms3dRotationKeyframe( current_time, self.joint_correction(rot) ) ) blender_scene.frame_set(frame_temp) ms3d_model.animation_fps = fps if ms3d_model.number_joints > 0: ms3d_model.number_total_frames = int(frame_total) ms3d_model.current_time = ((blender_scene.frame_current \ - blender_scene.frame_start) + 1) * time_base else: ms3d_model.number_total_frames = 1 ms3d_model.current_time = 0
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)