Menu anim export option, minor reorg
This commit is contained in:
parent
1bf6b6f9ab
commit
ff3a517312
|
@ -97,14 +97,24 @@ class ExportMSH(Operator, ExportHelper):
|
||||||
default=True
|
default=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export_anims: BoolProperty(
|
||||||
|
name="Export Animations",
|
||||||
|
description="Action export test",
|
||||||
|
default=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
|
||||||
with open(self.filepath, 'wb') as output_file:
|
with open(self.filepath, 'wb') as output_file:
|
||||||
save_scene(
|
save_scene(
|
||||||
output_file=output_file,
|
output_file=output_file,
|
||||||
scene=create_scene(
|
scene=create_scene(
|
||||||
generate_triangle_strips=self.generate_triangle_strips,
|
generate_triangle_strips=self.generate_triangle_strips,
|
||||||
apply_modifiers=self.apply_modifiers,
|
apply_modifiers=self.apply_modifiers,
|
||||||
export_target=self.export_target))
|
export_target=self.export_target),
|
||||||
|
separate_anims=self.export_anims
|
||||||
|
)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
|
@ -35,12 +35,8 @@ def gather_animdata(armature: bpy.types.Armature) -> List[Animation]:
|
||||||
for bone in armature.pose.bones:
|
for bone in armature.pose.bones:
|
||||||
|
|
||||||
xform = ModelTransform()
|
xform = ModelTransform()
|
||||||
xform.translation = convert_vector_space(bone.location)
|
xform.translation = to_skeleton_vector_space(bone.location)
|
||||||
xform.translation.x *= -1.0
|
xform.rotation = to_skeleton_rotation_space(bone.rotation_quaternion)
|
||||||
xform.rotation = convert_rotation_space(bone.rotation_quaternion)
|
|
||||||
xform.rotation.x *= -1.0
|
|
||||||
xform.rotation.y *= -1.0
|
|
||||||
xform.rotation.z *= -1.0
|
|
||||||
|
|
||||||
anim_data.bone_transforms[bone.name].append(xform)
|
anim_data.bone_transforms[bone.name].append(xform)
|
||||||
|
|
||||||
|
@ -48,6 +44,32 @@ def gather_animdata(armature: bpy.types.Armature) -> List[Animation]:
|
||||||
return [anim_data]
|
return [anim_data]
|
||||||
|
|
||||||
|
|
||||||
|
def get_basepose(armature: bpy.types.Armature) -> Animation:
|
||||||
|
|
||||||
|
anim_data = Animation();
|
||||||
|
anim_data.name = "basepose"
|
||||||
|
|
||||||
|
bpy.context.scene.frame_set(0.0)
|
||||||
|
|
||||||
|
anim_data.bone_transforms[armature.parent.name] = []
|
||||||
|
for bone in armature.data.bones:
|
||||||
|
anim_data.bone_transforms[bone.name] = []
|
||||||
|
|
||||||
|
for frame in range(2):
|
||||||
|
|
||||||
|
anim_data.bone_transforms[armature.parent.name].append(ModelTransform()) #for testing
|
||||||
|
|
||||||
|
for bone in armature.pose.bones:
|
||||||
|
|
||||||
|
xform = ModelTransform()
|
||||||
|
xform.translation = to_skeleton_vector_space(bone.location)
|
||||||
|
xform.rotation = to_skeleton_rotation_space(bone.rotation_quaternion)
|
||||||
|
|
||||||
|
anim_data.bone_transforms[bone.name].append(xform)
|
||||||
|
|
||||||
|
|
||||||
|
return anim_data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,6 @@ class Model:
|
||||||
class Animation:
|
class Animation:
|
||||||
""" Class representing 'CYCL' + 'KFR3' sections in a .msh file """
|
""" Class representing 'CYCL' + 'KFR3' sections in a .msh file """
|
||||||
|
|
||||||
name: str = "open"
|
name: str = "wiggle"
|
||||||
bone_transforms: Dict[str, List[ModelTransform]] = field(default_factory=dict)
|
bone_transforms: Dict[str, List[ModelTransform]] = field(default_factory=dict)
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ def gather_models(apply_modifiers: bool, export_target: str) -> List[Model]:
|
||||||
|
|
||||||
if obj.type == "ARMATURE":
|
if obj.type == "ARMATURE":
|
||||||
models_list += expand_armature(obj)
|
models_list += expand_armature(obj)
|
||||||
|
continue
|
||||||
|
|
||||||
local_translation, local_rotation, _ = obj.matrix_local.decompose()
|
local_translation, local_rotation, _ = obj.matrix_local.decompose()
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ def gather_models(apply_modifiers: bool, export_target: str) -> List[Model]:
|
||||||
model.transform.translation = convert_vector_space(local_translation)
|
model.transform.translation = convert_vector_space(local_translation)
|
||||||
|
|
||||||
if obj.type in MESH_OBJECT_TYPES:
|
if obj.type in MESH_OBJECT_TYPES:
|
||||||
|
mesh = obj.to_mesh()
|
||||||
model.geometry = create_mesh_geometry(mesh, obj.vertex_groups)
|
model.geometry = create_mesh_geometry(mesh, obj.vertex_groups)
|
||||||
obj.to_mesh_clear()
|
obj.to_mesh_clear()
|
||||||
|
|
||||||
|
@ -353,7 +355,7 @@ def expand_armature(obj: bpy.types.Object) -> List[Model]:
|
||||||
transform = bone.parent.matrix_local.inverted() @ transform
|
transform = bone.parent.matrix_local.inverted() @ transform
|
||||||
model.parent = bone.parent.name
|
model.parent = bone.parent.name
|
||||||
else:
|
else:
|
||||||
model.parent = obj.name
|
model.parent = "DummyRoot" # obj.name
|
||||||
|
|
||||||
local_translation, local_rotation, _ = transform.decompose()
|
local_translation, local_rotation, _ = transform.decompose()
|
||||||
|
|
||||||
|
@ -365,12 +367,3 @@ def expand_armature(obj: bpy.types.Object) -> List[Model]:
|
||||||
bones.append(model)
|
bones.append(model)
|
||||||
|
|
||||||
return bones
|
return bones
|
||||||
|
|
||||||
def convert_vector_space(vec: Vector) -> Vector:
|
|
||||||
return Vector((-vec.x, vec.z, vec.y))
|
|
||||||
|
|
||||||
def convert_scale_space(vec: Vector) -> Vector:
|
|
||||||
return Vector(vec.xzy)
|
|
||||||
|
|
||||||
def convert_rotation_space(quat: Quaternion) -> Quaternion:
|
|
||||||
return Quaternion((-quat.w, quat.x, -quat.z, -quat.y))
|
|
||||||
|
|
|
@ -114,3 +114,26 @@ def is_model_name_unused(name: str, models: List[Model]) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def convert_vector_space(vec: Vector) -> Vector:
|
||||||
|
return Vector((-vec.x, vec.z, vec.y))
|
||||||
|
|
||||||
|
def convert_scale_space(vec: Vector) -> Vector:
|
||||||
|
return Vector(vec.xzy)
|
||||||
|
|
||||||
|
def convert_rotation_space(quat: Quaternion) -> Quaternion:
|
||||||
|
return Quaternion((-quat.w, quat.x, -quat.z, -quat.y))
|
||||||
|
|
||||||
|
|
||||||
|
def to_skeleton_vector_space(vec : Vector):
|
||||||
|
vnew = convert_vector_space(vec)
|
||||||
|
vnew.x *= -1.0
|
||||||
|
return vnew
|
||||||
|
|
||||||
|
def to_skeleton_rotation_space(quat : Quaternion):
|
||||||
|
qnew = convert_rotation_space(quat)
|
||||||
|
qnew.x *= -1.0
|
||||||
|
qnew.y *= -1.0
|
||||||
|
qnew.z *= -1.0
|
||||||
|
return qnew
|
||||||
|
|
|
@ -10,7 +10,7 @@ from .msh_utilities import *
|
||||||
|
|
||||||
from .crc import *
|
from .crc import *
|
||||||
|
|
||||||
def save_scene(output_file, scene: Scene):
|
def save_scene(output_file, scene: Scene, separate_anims: bool):
|
||||||
""" Saves scene to the supplied file. """
|
""" Saves scene to the supplied file. """
|
||||||
|
|
||||||
with Writer(file=output_file, chunk_id="HEDR") as hedr:
|
with Writer(file=output_file, chunk_id="HEDR") as hedr:
|
||||||
|
@ -26,12 +26,15 @@ def save_scene(output_file, scene: Scene):
|
||||||
material_index = _write_matl_and_get_material_index(matl, scene)
|
material_index = _write_matl_and_get_material_index(matl, scene)
|
||||||
|
|
||||||
for index, model in enumerate(scene.models):
|
for index, model in enumerate(scene.models):
|
||||||
|
if separate_anims and (model.model_type not in {ModelType.NULL, ModelType.BONE}):
|
||||||
|
continue
|
||||||
with msh2.create_child("MODL") as modl:
|
with msh2.create_child("MODL") as modl:
|
||||||
_write_modl(modl, model, index, material_index, model_index)
|
_write_modl(modl, model, index, material_index, model_index)
|
||||||
|
|
||||||
with hedr.create_child("ANM2") as anm2: #simple for now
|
if separate_anims:
|
||||||
for anim in scene.anims:
|
with hedr.create_child("ANM2") as anm2: #simple for now
|
||||||
_write_anm2(anm2, anim)
|
for anim in scene.anims:
|
||||||
|
_write_anm2(anm2, anim)
|
||||||
|
|
||||||
with hedr.create_child("CL1L"):
|
with hedr.create_child("CL1L"):
|
||||||
pass
|
pass
|
||||||
|
@ -205,7 +208,32 @@ def _write_segm(segm: Writer, segment: GeometrySegment, material_index: Dict[str
|
||||||
for index in islice(strip, 2, len(strip)):
|
for index in islice(strip, 2, len(strip)):
|
||||||
strp.write_u16(index)
|
strp.write_u16(index)
|
||||||
|
|
||||||
|
'''
|
||||||
|
SKINNING CHUNKS
|
||||||
|
'''
|
||||||
|
def _write_wght(wght: Writer, weights: List[List[VertexWeight]]):
|
||||||
|
wght.write_u32(len(weights))
|
||||||
|
|
||||||
|
for weight_list in weights:
|
||||||
|
weight_list += [VertexWeight(0.0, 0)] * 4
|
||||||
|
weight_list = sorted(weight_list, key=lambda w: w.weight, reverse=True)
|
||||||
|
weight_list = weight_list[:4]
|
||||||
|
|
||||||
|
total_weight = max(sum(map(lambda w: w.weight, weight_list)), 1e-5)
|
||||||
|
|
||||||
|
for weight in weight_list:
|
||||||
|
wght.write_i32(weight.bone)
|
||||||
|
wght.write_f32(weight.weight / total_weight)
|
||||||
|
|
||||||
|
def _write_envl(envl: Writer, model: Model, model_index: Dict[str, int]):
|
||||||
|
envl.write_u32(len(model.bone_map))
|
||||||
|
|
||||||
|
for bone_name in model.bone_map:
|
||||||
|
envl.write_u32(model_index[bone_name])
|
||||||
|
|
||||||
|
'''
|
||||||
|
ANIMATION CHUNKS
|
||||||
|
'''
|
||||||
def _write_anm2(anm2: Writer, anim: Animation):
|
def _write_anm2(anm2: Writer, anim: Animation):
|
||||||
|
|
||||||
with anm2.create_child("CYCL") as cycl:
|
with anm2.create_child("CYCL") as cycl:
|
||||||
|
@ -240,22 +268,4 @@ def _write_anm2(anm2: Writer, anim: Animation):
|
||||||
kfr3.write_f32(xform.rotation.x, xform.rotation.y, xform.rotation.z, xform.rotation.w)
|
kfr3.write_f32(xform.rotation.x, xform.rotation.y, xform.rotation.z, xform.rotation.w)
|
||||||
|
|
||||||
|
|
||||||
def _write_wght(wght: Writer, weights: List[List[VertexWeight]]):
|
|
||||||
wght.write_u32(len(weights))
|
|
||||||
|
|
||||||
for weight_list in weights:
|
|
||||||
weight_list += [VertexWeight(0.0, 0)] * 4
|
|
||||||
weight_list = sorted(weight_list, key=lambda w: w.weight, reverse=True)
|
|
||||||
weight_list = weight_list[:4]
|
|
||||||
|
|
||||||
total_weight = max(sum(map(lambda w: w.weight, weight_list)), 1e-5)
|
|
||||||
|
|
||||||
for weight in weight_list:
|
|
||||||
wght.write_i32(weight.bone)
|
|
||||||
wght.write_f32(weight.weight / total_weight)
|
|
||||||
|
|
||||||
def _write_envl(envl: Writer, model: Model, model_index: Dict[str, int]):
|
|
||||||
envl.write_u32(len(model.bone_map))
|
|
||||||
|
|
||||||
for bone_name in model.bone_map:
|
|
||||||
envl.write_u32(model_index[bone_name])
|
|
||||||
|
|
Loading…
Reference in New Issue