STRP importing, Teancum's highsinger and xizor break implying adaptations needed for ZETools-exported MSHs

This commit is contained in:
Will Snyder 2020-12-04 03:33:46 -05:00
commit 3dda2a0d77
9 changed files with 198 additions and 114 deletions

View File

@ -100,15 +100,15 @@ class ExportMSH(Operator, ExportHelper):
default=True default=True
) )
export_animated: BoolProperty( export_with_animation: BoolProperty(
name="Export Animated Object", name="Export With Animation",
description="Always check if the object will be animated.", description="Includes animation data extracted from the action currently set on armature.",
default=False default=False
) )
export_skeleton_only: BoolProperty( export_as_skeleton: BoolProperty(
name="Export Skeleton", name="Export Objects As Skeleton",
description="Check if you intend to export skeleton data only.", description="Check if you intend to export skeleton data for consumption by ZenAsset.",
default=False default=False
) )
@ -122,9 +122,9 @@ class ExportMSH(Operator, ExportHelper):
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,
skel_only=self.export_skeleton_only skel_only=self.export_as_skeleton,
export_anim=self.export_with_animation
), ),
is_animated=self.export_animated
) )
return {'FINISHED'} return {'FINISHED'}

View File

@ -12,7 +12,7 @@ from .msh_utilities import *
from .msh_model_gather import * from .msh_model_gather import *
def extract_anim(armature: bpy.types.Armature) -> Animation: 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();
@ -27,19 +27,23 @@ def extract_anim(armature: bpy.types.Armature) -> Animation:
anim.end_index = num_frames - 1 anim.end_index = num_frames - 1
anim.bone_transforms["DummyRoot"] = [] anim.bone_frames[root_name] = ([], [])
for bone in armature.data.bones: for bone in armature.data.bones:
anim.bone_transforms[bone.name] = [] anim.bone_frames[bone.name] = ([], [])
for frame in range(num_frames): for frame in range(num_frames):
#if frame % 10 == 0:
# print("Sample frame {}:".format(frame))
frame_time = framerange.x + frame * increment frame_time = framerange.x + frame * increment
bpy.context.scene.frame_set(frame_time) bpy.context.scene.frame_set(frame_time)
anim.bone_transforms["DummyRoot"].append(ModelTransform())
rframe_dummy = RotationFrame(frame, convert_rotation_space(Quaternion()))
tframe_dummy = TranslationFrame(frame, Vector((0.0,0.0,0.0)))
anim.bone_frames[root_name][0].append(tframe_dummy)
anim.bone_frames[root_name][1].append(rframe_dummy)
for bone in armature.pose.bones: for bone in armature.pose.bones:
transform = bone.matrix transform = bone.matrix
@ -49,13 +53,11 @@ def extract_anim(armature: bpy.types.Armature) -> Animation:
loc, rot, _ = transform.decompose() loc, rot, _ = transform.decompose()
xform = ModelTransform() rframe = RotationFrame(frame, convert_rotation_space(rot))
xform.rotation = convert_rotation_space(rot) tframe = TranslationFrame(frame, convert_vector_space(loc))
xform.translation = convert_vector_space(loc)
#if frame % 10 == 0: anim.bone_frames[bone.name][0].append(tframe)
# print("\t{:10}: loc {:15} rot {:15}".format(bone.name, vec_to_str(xform.translation), quat_to_str(xform.rotation))) anim.bone_frames[bone.name][1].append(rframe)
anim.bone_transforms[bone.name].append(xform)
return anim return anim

View File

@ -2,7 +2,7 @@
saved to a .msh file. """ saved to a .msh file. """
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import List, Tuple from typing import List, Tuple, Dict
from enum import Enum from enum import Enum
from mathutils import Vector, Quaternion from mathutils import Vector, Quaternion
@ -52,7 +52,6 @@ class GeometrySegment:
triangles: List[List[int]] = field(default_factory=list) triangles: List[List[int]] = field(default_factory=list)
triangle_strips: List[List[int]] = None triangle_strips: List[List[int]] = None
weights: List[List[Tuple[int, float]]] = None
@dataclass @dataclass
class CollisionPrimitive: class CollisionPrimitive:
@ -80,14 +79,27 @@ class Model:
collisionprimitive: CollisionPrimitive = None collisionprimitive: CollisionPrimitive = None
@dataclass
class RotationFrame:
index : int = 0
rotation : Quaternion = field(default_factory=Quaternion)
@dataclass
class TranslationFrame:
index : int = 0
translation : Vector = field(default_factory=Vector)
@dataclass @dataclass
class Animation: 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_transforms: Dict[str, List[ModelTransform]] = field(default_factory=dict) bone_frames: Dict[str, 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
end_index : int = 0 end_index : int = 0

View File

@ -14,7 +14,7 @@ SKIPPED_OBJECT_TYPES = {"LATTICE", "CAMERA", "LIGHT", "SPEAKER", "LIGHT_PROBE"}
MESH_OBJECT_TYPES = {"MESH", "CURVE", "SURFACE", "META", "FONT", "GPENCIL"} MESH_OBJECT_TYPES = {"MESH", "CURVE", "SURFACE", "META", "FONT", "GPENCIL"}
MAX_MSH_VERTEX_COUNT = 32767 MAX_MSH_VERTEX_COUNT = 32767
def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool) -> List[Model]: def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool) -> Tuple[List[Model], bpy.types.Object]:
""" Gathers the Blender objects from the current scene and returns them as a list of """ Gathers the Blender objects from the current scene and returns them as a list of
Model objects. """ Model objects. """
@ -23,6 +23,8 @@ def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool
models_list: List[Model] = [] models_list: List[Model] = []
armature_found = None
for uneval_obj in select_objects(export_target): for uneval_obj in select_objects(export_target):
if uneval_obj.type in SKIPPED_OBJECT_TYPES and uneval_obj.name not in parents: if uneval_obj.type in SKIPPED_OBJECT_TYPES and uneval_obj.name not in parents:
continue continue
@ -36,6 +38,7 @@ def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool
if obj.type == "ARMATURE": if obj.type == "ARMATURE":
models_list += expand_armature(obj) models_list += expand_armature(obj)
armature_found = obj
continue continue
model = Model() model = Model()
@ -44,7 +47,6 @@ def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool
model.hidden = get_is_model_hidden(obj) model.hidden = get_is_model_hidden(obj)
transform = obj.matrix_local transform = obj.matrix_local
transform_reset = Matrix.Identity(4)
if obj.parent_bone: if obj.parent_bone:
model.parent = obj.parent_bone model.parent = obj.parent_bone
@ -52,18 +54,8 @@ def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool
# matrix_local, when called on an armature child also parented to a bone, appears to be broken. # matrix_local, when called on an armature child also parented to a bone, appears to be broken.
# At the very least, the results contradict the docs... # At the very least, the results contradict the docs...
armature_relative_transform = obj.parent.matrix_world.inverted() @ obj.matrix_world armature_relative_transform = obj.parent.matrix_world.inverted() @ obj.matrix_world
bone_relative_transform = obj.parent.data.bones[obj.parent_bone].matrix_local.inverted() @ armature_relative_transform transform = obj.parent.data.bones[obj.parent_bone].matrix_local.inverted() @ armature_relative_transform
transform = bone_relative_transform
'''
# Since the transforms of direct bone children are discarded by ZEngine (but not ZEditor), we apply the transform
# before geometry extraction, then apply the inversion after.
if obj.type in MESH_OBJECT_TYPES:
obj.data.transform(bone_relative_transform)
transform_reset = bone_relative_transform.inverted()
transform = Matrix.Identity(4)
'''
else: else:
if obj.parent is not None: if obj.parent is not None:
if obj.parent.type == "ARMATURE": if obj.parent.type == "ARMATURE":
@ -95,8 +87,6 @@ def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool
if obj.vertex_groups: if obj.vertex_groups:
model.bone_map = [group.name for group in obj.vertex_groups] model.bone_map = [group.name for group in obj.vertex_groups]
obj.data.transform(transform_reset)
if get_is_collision_primitive(obj): if get_is_collision_primitive(obj):
model.collisionprimitive = get_collision_primitive(obj) model.collisionprimitive = get_collision_primitive(obj)
@ -104,7 +94,9 @@ def gather_models(apply_modifiers: bool, export_target: str, skeleton_only: bool
models_list.append(model) models_list.append(model)
return models_list
return (models_list, armature_found)
def create_parents_set() -> Set[str]: def create_parents_set() -> Set[str]:

View File

@ -3,12 +3,13 @@ import io
import struct import struct
class Reader: class Reader:
def __init__(self, file, parent=None, indent=0): def __init__(self, file, parent=None, indent=0, debug=False):
self.file = file self.file = file
self.size: int = 0 self.size: int = 0
self.size_pos = None self.size_pos = None
self.parent = parent self.parent = parent
self.indent = " " * indent #for print debugging self.indent = " " * indent #for print debugging
self.debug = debug
def __enter__(self): def __enter__(self):
@ -19,7 +20,8 @@ class Reader:
padding_length = 4 - (self.size % 4) if self.size % 4 > 0 else 0 padding_length = 4 - (self.size % 4) if self.size % 4 > 0 else 0
self.end_pos = self.size_pos + padding_length + self.size + 8 self.end_pos = self.size_pos + padding_length + self.size + 8
#print(self.indent + "Begin " + self.header + ", Size: " + str(self.size) + ", Pos: " + str(self.size_pos)) if self.debug:
print(self.indent + "Begin " + self.header + ", Size: " + str(self.size) + ", Pos: " + str(self.size_pos))
return self return self
@ -28,7 +30,9 @@ class Reader:
if self.size > self.MAX_SIZE: if self.size > self.MAX_SIZE:
raise OverflowError(f".msh file overflowed max size. size = {self.size} MAX_SIZE = {self.MAX_SIZE}") raise OverflowError(f".msh file overflowed max size. size = {self.size} MAX_SIZE = {self.MAX_SIZE}")
#print(self.indent + "End " + self.header) if self.debug:
print(self.indent + "End " + self.header)
self.file.seek(self.end_pos) self.file.seek(self.end_pos)
@ -84,7 +88,7 @@ class Reader:
def read_child(self): def read_child(self):
child = Reader(self.file, parent=self, indent=int(len(self.indent) / 2) + 1) child = Reader(self.file, parent=self, indent=int(len(self.indent) / 2) + 1, debug=self.debug)
return child return child
@ -95,7 +99,13 @@ class Reader:
def peak_next_header(self): def peak_next_header(self):
buf = self.read_bytes(4); buf = self.read_bytes(4);
self.file.seek(-4,1) self.file.seek(-4,1)
return buf.decode("utf-8") try:
result = buf.decode("utf-8")
except:
result = ""
return result
def could_have_child(self): def could_have_child(self):

View File

@ -6,7 +6,7 @@ from typing import List, Dict
from copy import copy from copy import copy
import bpy import bpy
from mathutils import Vector from mathutils import Vector
from .msh_model import Model from .msh_model import Model, Animation
from .msh_model_gather import gather_models from .msh_model_gather import gather_models
from .msh_model_utilities import sort_by_parent, has_multiple_root_models, reparent_model_roots, get_model_world_matrix from .msh_model_utilities import sort_by_parent, has_multiple_root_models, reparent_model_roots, get_model_world_matrix
from .msh_model_triangle_strips import create_models_triangle_strips from .msh_model_triangle_strips import create_models_triangle_strips
@ -44,9 +44,11 @@ class Scene:
materials: Dict[str, Material] = field(default_factory=dict) materials: Dict[str, Material] = field(default_factory=dict)
models: List[Model] = field(default_factory=list) models: List[Model] = field(default_factory=list)
animation: Animation = None
skeleton: List[int] = field(default_factory=list) skeleton: List[int] = field(default_factory=list)
def create_scene(generate_triangle_strips: bool, apply_modifiers: bool, export_target: str, skel_only: bool) -> Scene: def create_scene(generate_triangle_strips: bool, apply_modifiers: bool, export_target: str, skel_only: bool, export_anim: bool) -> Scene:
""" Create a msh Scene from the active Blender scene. """ """ Create a msh Scene from the active Blender scene. """
scene = Scene() scene = Scene()
@ -55,7 +57,7 @@ def create_scene(generate_triangle_strips: bool, apply_modifiers: bool, export_t
scene.materials = gather_materials() scene.materials = gather_materials()
scene.models = gather_models(apply_modifiers=apply_modifiers, export_target=export_target, skeleton_only=skel_only) scene.models, armature_obj = gather_models(apply_modifiers=apply_modifiers, export_target=export_target, skeleton_only=skel_only)
scene.models = sort_by_parent(scene.models) scene.models = sort_by_parent(scene.models)
if generate_triangle_strips: if generate_triangle_strips:
@ -71,12 +73,17 @@ def create_scene(generate_triangle_strips: bool, apply_modifiers: bool, export_t
scene.materials = remove_unused_materials(scene.materials, scene.models) scene.materials = remove_unused_materials(scene.materials, scene.models)
#creates a dummy basepose if no Action is selected
if "Armature" in bpy.context.scene.objects.keys():
scene.anims = [extract_anim(bpy.context.scene.objects["Armature"])]
root = scene.models[0] root = scene.models[0]
if export_anim:
if armature_obj is not None:
scene.animation = extract_anim(armature_obj, root.name)
else:
raise Exception("Export Error: Could not find an armature object from which to export an animation!")
if skel_only and root.model_type == ModelType.NULL: if skel_only and root.model_type == ModelType.NULL:
# For ZenAsset
inject_dummy_data(root) inject_dummy_data(root)
return scene return scene

View File

@ -12,6 +12,8 @@ from .crc import *
model_counter = 0 model_counter = 0
mndx_remap = {}
def read_scene(input_file) -> Scene: def read_scene(input_file) -> Scene:
@ -19,10 +21,13 @@ def read_scene(input_file) -> Scene:
scene.models = [] scene.models = []
scene.materials = {} scene.materials = {}
global mndx_remap
mndx_remap = {}
global model_counter global model_counter
model_counter = 0 model_counter = 0
with Reader(file=input_file) as hedr: with Reader(file=input_file, debug=True) as hedr:
while hedr.could_have_child(): while hedr.could_have_child():
@ -54,8 +59,7 @@ def read_scene(input_file) -> Scene:
scene.models.append(_read_modl(modl, materials_list)) scene.models.append(_read_modl(modl, materials_list))
else: else:
with hedr.read_child() as unknown: msh2.skip_bytes(1)
pass
elif "SKL2" in next_header: elif "SKL2" in next_header:
with hedr.read_child() as skl2: with hedr.read_child() as skl2:
@ -67,16 +71,28 @@ def read_scene(input_file) -> Scene:
_read_anm2(anm2, scene.models) _read_anm2(anm2, scene.models)
else: else:
with hedr.read_child() as null: hedr.skip_bytes(1)
pass
if scene.skeleton: if scene.skeleton:
print("Skeleton models: ") print("Skeleton models: ")
for model in scene.models: for model in scene.models:
if crc(model.name) in scene.skeleton: for i in range(len(scene.skeleton)):
if crc(model.name) == scene.skeleton[i]:
print("\t" + model.name) print("\t" + model.name)
if model.model_type == ModelType.SKIN:
scene.skeleton.pop(i)
break
for model in scene.models:
if model.geometry:
for seg in model.geometry:
if seg.weights:
for weight_set in seg.weights:
for vweight in weight_set:
vweight.bone = mndx_remap[vweight.bone]
return scene return scene
@ -135,7 +151,7 @@ def _read_matd(matd: Reader) -> Material:
mat.texture3 = tx3d.read_string() mat.texture3 = tx3d.read_string()
else: else:
matd.skip_bytes(4) matd.skip_bytes(1)
return mat return mat
@ -154,9 +170,14 @@ def _read_modl(modl: Reader, materials_list: List[Material]) -> Model:
elif "MNDX" in next_header: elif "MNDX" in next_header:
with modl.read_child() as mndx: with modl.read_child() as mndx:
index = mndx.read_u32()
global model_counter global model_counter
if mndx.read_u32() - 1 != model_counter: print(mndx.indent + "MNDX doesn't match counter, expected: {} found: {}".format(model_counter, index))
print("MODEL INDEX DIDNT MATCH COUNTER!")
global mndx_remap
mndx_remap[index] = model_counter
model_counter += 1 model_counter += 1
elif "NAME" in next_header: elif "NAME" in next_header:
@ -191,18 +212,20 @@ def _read_modl(modl: Reader, materials_list: List[Material]) -> Model:
elif "ENVL" in next_header_geom: elif "ENVL" in next_header_geom:
with geom.read_child() as envl: with geom.read_child() as envl:
num_indicies = envl.read_u32() num_indicies = envl.read_u32()
envelope += [envl.read_u32() - 1 for _ in range(num_indicies)] envelope += [envl.read_u32() for _ in range(num_indicies)]
else: else:
with geom.read_child() as null: geom.skip_bytes(1)
pass #with geom.read_child() as null:
#pass
for seg in model.geometry: for seg in model.geometry:
if seg.weights: if seg.weights and envelope:
for weight_set in seg.weights: for weight_set in seg.weights:
for i in range(len(weight_set)): for i in range(len(weight_set)):
weight = weight_set[i] vertex_weight = weight_set[i]
weight_set[i] = (envelope[weight[0]], weight[1]) index = vertex_weight.bone
weight_set[i] = VertexWeight(vertex_weight.weight, envelope[vertex_weight.bone])
elif "SWCI" in next_header: elif "SWCI" in next_header:
prim = CollisionPrimitive() prim = CollisionPrimitive()
@ -214,10 +237,9 @@ def _read_modl(modl: Reader, materials_list: List[Material]) -> Model:
model.collisionprimitive = prim model.collisionprimitive = prim
else: else:
with modl.read_child() as null: modl.skip_bytes(1)
pass
print("Reading model " + model.name + " of type: " + str(model.model_type)[10:]) print(modl.indent + "Read model " + model.name + " of type: " + str(model.model_type)[10:])
return model return model
@ -293,11 +315,45 @@ def _read_segm(segm: Reader, materials_list: List[Material]) -> GeometrySegment:
geometry_seg.triangles.append(ndxt.read_u16(3)) geometry_seg.triangles.append(ndxt.read_u16(3))
elif "STRP" in next_header: elif "STRP" in next_header:
with segm.read_child() as strp: strips : List[List[int]] = []
pass
if segm.read_u16 != 0: #trailing 0 bug https://schlechtwetterfront.github.io/ze_filetypes/msh.html#STRP with segm.read_child() as strp:
segm.skip_bytes(-2) num_indicies = strp.read_u32()
num_indicies_read = 0
curr_strip = []
previous_flag = False
if num_indicies > 0:
index, index1 = strp.read_u16(2)
curr_strip = [index & 0x7fff, index1 & 0x7fff]
num_indicies_read += 2
for i in range(num_indicies - 2):
index = strp.read_u16(1)
if index & 0x8000 > 0:
index = index & 0x7fff
if previous_flag:
previous_flag = False
curr_strip.append(index)
strips.append(curr_strip[:-2])
curr_strip = curr_strip[-2:]
continue
else:
previous_flag = True
else:
previous_flag = False
curr_strip.append(index)
geometry_seg.triangle_strips = strips
#if segm.read_u16 != 0: #trailing 0 bug https://schlechtwetterfront.github.io/ze_filetypes/msh.html#STRP
# segm.skip_bytes(-2)
elif "WGHT" in next_header: elif "WGHT" in next_header:
with segm.read_child() as wght: with segm.read_child() as wght:
@ -312,13 +368,12 @@ def _read_segm(segm: Reader, materials_list: List[Material]) -> GeometrySegment:
value = wght.read_f32() value = wght.read_f32()
if value > 0.000001: if value > 0.000001:
weight_set.append((index,value)) weight_set.append(VertexWeight(value,index))
geometry_seg.weights.append(weight_set) geometry_seg.weights.append(weight_set)
else: else:
with segm.read_child() as null: segm.skip_bytes(1)
pass
return geometry_seg return geometry_seg

View File

@ -8,13 +8,10 @@ from .msh_material import *
from .msh_writer import Writer from .msh_writer import Writer
from .msh_utilities import * from .msh_utilities import *
<<<<<<< HEAD
from .crc import * from .crc import *
def save_scene(output_file, scene: Scene, is_animated: bool):
=======
def save_scene(output_file, scene: Scene): def save_scene(output_file, scene: Scene):
>>>>>>> mshread
""" 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:
@ -36,16 +33,15 @@ def save_scene(output_file, scene: Scene):
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)
if is_animated: if scene.animation is not None:
with hedr.create_child("SKL2") as skl2: with hedr.create_child("SKL2") as skl2:
_write_skl2(skl2, scene) _write_skl2(skl2, scene.animation)
with hedr.create_child("BLN2") as bln2: with hedr.create_child("BLN2") as bln2:
_write_bln2(bln2, scene) _write_bln2(bln2, scene.animation)
with hedr.create_child("ANM2") as anm2: #simple for now with hedr.create_child("ANM2") as anm2: #simple for now
for anim in scene.anims: _write_anm2(anm2, scene.animation)
_write_anm2(anm2, anim)
with hedr.create_child("CL1L"): with hedr.create_child("CL1L"):
pass pass
@ -251,23 +247,23 @@ def _write_envl(envl: Writer, model: Model, model_index: Dict[str, int]):
''' '''
SKELETON CHUNKS SKELETON CHUNKS
''' '''
def _write_bln2(bln2: Writer, scene: Scene): def _write_bln2(bln2: Writer, anim: Animation):
bones = scene.anims[0].bone_transforms.keys() bones = anim.bone_frames.keys()
bln2.write_u32(len(bones)) bln2.write_u32(len(bones))
for boneName in bones: for boneName in bones:
bln2.write_u32(crc(boneName), 0) bln2.write_u32(crc(boneName), 0)
def _write_skl2(skl2: Writer, scene: Scene): def _write_skl2(skl2: Writer, anim: Animation):
bones = scene.anims[0].bone_transforms.keys() bones = anim.bone_frames.keys()
skl2.write_u32(len(bones)) skl2.write_u32(len(bones))
for boneName in bones: for boneName in bones:
skl2.write_u32(crc(boneName), 0) #default values skl2.write_u32(crc(boneName), 0) #default values from docs
skl2.write_f32(1.0, 0.0, 0.0) #from docs skl2.write_f32(1.0, 0.0, 0.0)
''' '''
ANIMATION CHUNK ANIMATION CHUNKS
''' '''
def _write_anm2(anm2: Writer, anim: Animation): def _write_anm2(anm2: Writer, anim: Animation):
@ -286,19 +282,21 @@ def _write_anm2(anm2: Writer, anim: Animation):
with anm2.create_child("KFR3") as kfr3: with anm2.create_child("KFR3") as kfr3:
kfr3.write_u32(len(anim.bone_transforms.keys())) kfr3.write_u32(len(anim.bone_frames))
for boneName in anim.bone_transforms.keys(): for boneName in anim.bone_frames:
kfr3.write_u32(crc(boneName)) kfr3.write_u32(crc(boneName))
kfr3.write_u32(0) #what is keyframe type? kfr3.write_u32(0) #what is keyframe type?
num_frames = 1 + anim.end_index - anim.start_index translation_frames, rotation_frames = anim.bone_frames[boneName]
kfr3.write_u32(num_frames, num_frames) #basic testing
for i, xform in enumerate(anim.bone_transforms[boneName]): kfr3.write_u32(len(translation_frames), len(rotation_frames))
kfr3.write_u32(i)
kfr3.write_f32(xform.translation.x, xform.translation.y, xform.translation.z) for frame in translation_frames:
kfr3.write_u32(frame.index)
kfr3.write_f32(frame.translation.x, frame.translation.y, frame.translation.z)
for frame in rotation_frames:
kfr3.write_u32(frame.index)
kfr3.write_f32(frame.rotation.x, frame.rotation.y, frame.rotation.z, frame.rotation.w)
for i, xform in enumerate(anim.bone_transforms[boneName]):
kfr3.write_u32(i)
kfr3.write_f32(xform.rotation.x, xform.rotation.y, xform.rotation.z, xform.rotation.w)

View File

@ -79,7 +79,7 @@ def extract_refined_skeleton(scene: Scene):
if seg.weights: if seg.weights:
for weight_set in seg.weights: for weight_set in seg.weights:
for weight in weight_set: for weight in weight_set:
model_weighted_to = scene.models[weight[0]] model_weighted_to = scene.models[weight.bone]
if crc(model_weighted_to.name) not in scene.skeleton: if crc(model_weighted_to.name) not in scene.skeleton:
scene.skeleton.append(crc(model_weighted_to.name)) scene.skeleton.append(crc(model_weighted_to.name))
@ -164,7 +164,14 @@ def extract_models(scene: Scene, materials_map):
else: else:
full_texcoords += [(0.0,0.0) for _ in range(len(seg.positions))] full_texcoords += [(0.0,0.0) for _ in range(len(seg.positions))]
if seg.triangles:
faces += [tuple([ind + offset for ind in tri]) for tri in seg.triangles] faces += [tuple([ind + offset for ind in tri]) for tri in seg.triangles]
else:
for strip in seg.triangle_strips:
for i in range(len(strip) - 2):
face = tuple([offset + strip[j] for j in range(i,i+3)])
print("strip face: " + str(face))
faces.append(face)
offset += len(seg.positions) offset += len(seg.positions)
@ -199,13 +206,13 @@ def extract_models(scene: Scene, materials_map):
for offset in weights_offsets: for offset in weights_offsets:
for i, weight_set in enumerate(weights_offsets[offset]): for i, weight_set in enumerate(weights_offsets[offset]):
for weight in weight_set: for weight in weight_set:
index = weight[0] index = weight.bone
if index not in vertex_groups_indicies: if index not in vertex_groups_indicies:
model_name = scene.models[index].name model_name = scene.models[index].name
vertex_groups_indicies[index] = new_obj.vertex_groups.new(name=model_name) vertex_groups_indicies[index] = new_obj.vertex_groups.new(name=model_name)
vertex_groups_indicies[index].add([offset + i], weight[1], 'ADD') vertex_groups_indicies[index].add([offset + i], weight.weight, 'ADD')
''' '''
Assign Materials - will do per segment later... Assign Materials - will do per segment later...
@ -277,8 +284,8 @@ def extract_scene(filepath: str, scene: Scene):
skel = extract_refined_skeleton(scene) skel = extract_refined_skeleton(scene)
armature = refined_skeleton_to_armature(skel, model_map) armature = refined_skeleton_to_armature(skel, model_map)
for model in scene.models:
reparent_obj = None reparent_obj = None
for model in scene.models:
if model.model_type == ModelType.SKIN: if model.model_type == ModelType.SKIN:
if model.parent: if model.parent:
@ -314,8 +321,9 @@ def extract_scene(filepath: str, scene: Scene):
for model in scene.models: for model in scene.models:
if model.name in bpy.data.objects: if model.name in bpy.data.objects:
if model.hidden and len(bpy.data.objects[model.name].children) == 0: obj = bpy.data.objects[model.name]
bpy.data.objects[model.name].hide_set(True) if get_is_model_hidden(obj) and len(obj.children) == 0:
obj.hide_set(True)