Bone parenting fixed, anm2 reading, menu option for anim import

This commit is contained in:
William Herald Snyder 2020-12-05 00:53:59 -05:00
parent 30bf326b9e
commit c0c978af8b
7 changed files with 89 additions and 75 deletions

View File

@ -151,9 +151,22 @@ class ImportMSH(Operator, ImportHelper):
maxlen=255, # Max internal buffer length, longer would be clamped. maxlen=255, # Max internal buffer length, longer would be clamped.
) )
animation_only: BoolProperty(
name="Import Animation Only",
description="Import animation and append as a new action to currently selected armature.",
default=False
)
def execute(self, context): def execute(self, context):
with open(self.filepath, 'rb') as input_file: with open(self.filepath, 'rb') as input_file:
extract_scene(self.filepath, read_scene(input_file)) scene = read_scene(input_file, self.animation_only)
if not self.animation_only:
extract_scene(self.filepath, scene)
else:
extract_and_apply_anim(self.filepath, scene)
return {'FINISHED'} return {'FINISHED'}
def menu_func_import(self, context): def menu_func_import(self, context):

View File

@ -17,6 +17,8 @@ def extract_anim(armature: bpy.types.Armature, root_name: str) -> Animation:
action = armature.animation_data.action action = armature.animation_data.action
anim = Animation(); anim = Animation();
root_crc = crc(root_name)
if not action: if not action:
framerange = Vector((0.0,1.0)) framerange = Vector((0.0,1.0))
else: else:
@ -27,9 +29,9 @@ def extract_anim(armature: bpy.types.Armature, root_name: str) -> Animation:
anim.end_index = num_frames - 1 anim.end_index = num_frames - 1
anim.bone_frames[root_name] = ([], []) anim.bone_frames[root_crc] = ([], [])
for bone in armature.data.bones: for bone in armature.data.bones:
anim.bone_frames[bone.name] = ([], []) anim.bone_frames[crc(bone.name)] = ([], [])
for frame in range(num_frames): for frame in range(num_frames):
@ -40,8 +42,8 @@ def extract_anim(armature: bpy.types.Armature, root_name: str) -> Animation:
rframe_dummy = RotationFrame(frame, convert_rotation_space(Quaternion())) rframe_dummy = RotationFrame(frame, convert_rotation_space(Quaternion()))
tframe_dummy = TranslationFrame(frame, Vector((0.0,0.0,0.0))) tframe_dummy = TranslationFrame(frame, Vector((0.0,0.0,0.0)))
anim.bone_frames[root_name][0].append(tframe_dummy) anim.bone_frames[root_crc][0].append(tframe_dummy)
anim.bone_frames[root_name][1].append(rframe_dummy) anim.bone_frames[root_crc][1].append(rframe_dummy)
for bone in armature.pose.bones: for bone in armature.pose.bones:
@ -56,8 +58,8 @@ def extract_anim(armature: bpy.types.Armature, root_name: str) -> Animation:
rframe = RotationFrame(frame, convert_rotation_space(rot)) rframe = RotationFrame(frame, convert_rotation_space(rot))
tframe = TranslationFrame(frame, convert_vector_space(loc)) tframe = TranslationFrame(frame, convert_vector_space(loc))
anim.bone_frames[bone.name][0].append(tframe) anim.bone_frames[crc(bone.name)][0].append(tframe)
anim.bone_frames[bone.name][1].append(rframe) anim.bone_frames[crc(bone.name)][1].append(rframe)
return anim return anim

View File

@ -98,7 +98,7 @@ class Animation:
""" Class representing 'CYCL' + 'KFR3' sections in a .msh file """ """ Class representing 'CYCL' + 'KFR3' sections in a .msh file """
name: str = "fullanimation" name: str = "fullanimation"
bone_frames: Dict[str, Tuple[List[TranslationFrame], List[RotationFrame]]] = field(default_factory=dict) bone_frames: Dict[int, Tuple[List[TranslationFrame], List[RotationFrame]]] = field(default_factory=dict)
framerate: float = 29.97 framerate: float = 29.97
start_index : int = 0 start_index : int = 0

View File

@ -84,6 +84,14 @@ class Reader:
return result[0] if num == 1 else result return result[0] if num == 1 else result
def read_quat(self):
rot = self.read_f32(4)
return Quaternion((rot[3], rot[0], rot[1], rot[2]))
def read_vec(self):
return Vector(self.read_f32(3))
def read_child(self): def read_child(self):
child = Reader(self.file, parent=self, indent=int(len(self.indent) / 2) + 1, debug=self.debug) child = Reader(self.file, parent=self, indent=int(len(self.indent) / 2) + 1, debug=self.debug)

View File

@ -15,7 +15,7 @@ model_counter = 0
mndx_remap = {} mndx_remap = {}
def read_scene(input_file) -> Scene: def read_scene(input_file, anim_only=False) -> Scene:
scene = Scene() scene = Scene()
scene.models = [] scene.models = []
@ -37,6 +37,7 @@ def read_scene(input_file) -> Scene:
with hedr.read_child() as msh2: with hedr.read_child() as msh2:
if not anim_only:
materials_list = [] materials_list = []
while (msh2.could_have_child()): while (msh2.could_have_child()):
@ -68,7 +69,7 @@ def read_scene(input_file) -> Scene:
elif "ANM2" in next_header: elif "ANM2" in next_header:
with hedr.read_child() as anm2: with hedr.read_child() as anm2:
_read_anm2(anm2, scene.models) scene.animation = _read_anm2(anm2)
else: else:
hedr.skip_bytes(1) hedr.skip_bytes(1)
@ -250,9 +251,8 @@ def _read_tran(tran: Reader) -> ModelTransform:
tran.skip_bytes(12) #ignore scale tran.skip_bytes(12) #ignore scale
rot = tran.read_f32(4) xform.rotation = tran.read_quat()
xform.rotation = Quaternion((rot[3], rot[0], rot[1], rot[2])) xform.translation = tran.read_vec()
xform.translation = Vector(tran.read_f32(3))
print(tran.indent + "Rot: {} Loc: {}".format(str(xform.rotation), str(xform.translation))) print(tran.indent + "Rot: {} Loc: {}".format(str(xform.rotation), str(xform.translation)))
@ -381,11 +381,9 @@ def _read_segm(segm: Reader, materials_list: List[Material]) -> GeometrySegment:
def _read_anm2(anm2: Reader, models): def _read_anm2(anm2: Reader) -> Animation:
hash_dict = {} anim = Animation()
for model in models:
hash_dict[crc(model.name)] = model.name
while anm2.could_have_child(): while anm2.could_have_child():
@ -402,14 +400,26 @@ def _read_anm2(anm2: Reader, models):
for _ in range(num_bones): for _ in range(num_bones):
kfr3.read_u32() bone_crc = kfr3.read_u32()
frames = ([],[])
frametype = kfr3.read_u32() frametype = kfr3.read_u32()
num_loc_frames = kfr3.read_u32() num_loc_frames = kfr3.read_u32()
num_rot_frames = kfr3.read_u32() num_rot_frames = kfr3.read_u32()
kfr3.skip_bytes(16 * num_loc_frames + 20 * num_rot_frames) for i in range(num_loc_frames):
frames[0].append(TranslationFrame(kfr3.read_u32(), kfr3.read_vec()))
for i in range(num_rot_frames):
frames[1].append(RotationFrame(kfr3.read_u32(), kfr3.read_quat()))
anim.bone_frames[bone_crc] = frames
else:
anm2.skip_bytes(1)
return anim

View File

@ -251,15 +251,15 @@ def _write_bln2(bln2: Writer, anim: Animation):
bones = anim.bone_frames.keys() bones = anim.bone_frames.keys()
bln2.write_u32(len(bones)) bln2.write_u32(len(bones))
for boneName in bones: for bone_crc in bones:
bln2.write_u32(crc(boneName), 0) bln2.write_u32(bone_crc, 0)
def _write_skl2(skl2: Writer, anim: Animation): def _write_skl2(skl2: Writer, anim: Animation):
bones = anim.bone_frames.keys() bones = anim.bone_frames.keys()
skl2.write_u32(len(bones)) skl2.write_u32(len(bones))
for boneName in bones: for bone_crc in bones:
skl2.write_u32(crc(boneName), 0) #default values from docs skl2.write_u32(bone_crc, 0) #default values from docs
skl2.write_f32(1.0, 0.0, 0.0) skl2.write_f32(1.0, 0.0, 0.0)
''' '''
@ -284,8 +284,8 @@ def _write_anm2(anm2: Writer, anim: Animation):
kfr3.write_u32(len(anim.bone_frames)) kfr3.write_u32(len(anim.bone_frames))
for boneName in anim.bone_frames: for bone_crc in anim.bone_frames:
kfr3.write_u32(crc(boneName)) kfr3.write_u32(bone_crc)
kfr3.write_u32(0) #what is keyframe type? kfr3.write_u32(0) #what is keyframe type?
translation_frames, rotation_frames = anim.bone_frames[boneName] translation_frames, rotation_frames = anim.bone_frames[boneName]

View File

@ -18,44 +18,25 @@ import os
#def import_anim(scene : Scene):
def parent_object_to_bone(obj, armature, bone_name): def parent_object_to_bone(obj, armature, bone_name):
bpy.ops.object.select_all(action='DESELECT') worldmat = obj.matrix_world
armature.select_set(True)
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='EDIT')
armature.data.edit_bones.active = armature.data.edit_bones[bone_name]
bpy.ops.object.mode_set(mode='OBJECT')
obj.parent = None
obj.parent = armature
obj.parent_type = 'BONE'
obj.parent_bone = bone_name
bpy.ops.object.select_all(action='DESELECT') obj.matrix_basis = Matrix()
bpy.context.view_layer.objects.active = None obj.matrix_parent_inverse = Matrix()
obj.matrix_world = worldmat
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.parent_clear(type="CLEAR_KEEP_TRANSFORM")
bpy.context.view_layer.objects.active = None
obj.select_set(True)
armature.select_set(True)
bpy.context.view_layer.objects.active = armature
bpy.ops.object.mode_set(mode='POSE')
armature.pose.bones[bone_name].bone.select = True
bpy.ops.object.parent_set(type="BONE")
armature.pose.bones[bone_name].bone.select = False
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.select_all(action='DESELECT')