Bones now Import but still broken

- Bones now fully import
- Bones do not import the correct size or rotations it seem though.
This commit is contained in:
Yusarina
2024-11-17 00:50:32 +00:00
parent 53bed35ade
commit e48226dab1
+108 -47
View File
@@ -125,64 +125,114 @@ def read_material(file: BufferedReader, string_build, byte_size):
return material_name, material_english_name, diffuse_color, specular_color, specular_strength, ambient_color, flag, edge_color, edge_size, texture_index, sphere_texture_index, sphere_mode, toon_sharing_flag, toon_texture_index, comment, surface_count return material_name, material_english_name, diffuse_color, specular_color, specular_strength, ambient_color, flag, edge_color, edge_size, texture_index, sphere_texture_index, sphere_mode, toon_sharing_flag, toon_texture_index, comment, surface_count
def read_bone(file: BufferedReader, string_build, byte_size): def read_bone(file: BufferedReader, string_build, byte_size):
bone_name = str(file.read(struct.unpack('<i', file.read(4))[0]), 'utf-16-le', errors='replace') try:
bone_english_name = str(file.read(struct.unpack('<i', file.read(4))[0]), 'utf-16-le', errors='replace') # Read bone name and validate
name_length = struct.unpack('<i', file.read(4))[0]
if not 0 <= name_length <= 512:
raise ValueError(f"Invalid bone name length {name_length}")
bone_name = str(file.read(name_length), 'utf-16-le', errors='replace')
# Read English name
eng_name_length = struct.unpack('<i', file.read(4))[0]
bone_english_name = str(file.read(eng_name_length), 'utf-16-le', errors='replace')
# Read position and indices
position = struct.unpack('<3f', file.read(12)) position = struct.unpack('<3f', file.read(12))
parent_bone_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0] parent_bone_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0]
layer = struct.unpack('<i', file.read(4))[0] layer = struct.unpack('<i', file.read(4))[0]
flag = struct.unpack('<H', file.read(2))[0] flag = struct.unpack('<H', file.read(2))[0]
tail_position = [None,None,None] # Initialize bone properties with defaults
tail_index = 0.0 tail_position = [0.0, 0.0, 0.0]
inherit_bone_parent_index = 0 tail_index = -1
inherit_bone_parent_index = -1
inherit_bone_parent_influence = 0.0 inherit_bone_parent_influence = 0.0
fixed_axis = [0.0,0.0,0.0] fixed_axis = [0.0, 0.0, 0.0]
local_x_vector = [0.0,0.0,0.0] local_x_vector = [0.0, 0.0, 0.0]
local_z_vector = [0.0,0.0,0.0] local_z_vector = [0.0, 0.0, 0.0]
external_key = 0 external_key = 0
ik_target_bone_index = 0.0 ik_target_bone_index = -1
ik_loop_count = -1 ik_loop_count = 0
ik_limit_radian = 0.0 ik_limit_radian = 0.0
ik_link_count = -1 ik_links = []
# Read flag-dependent data
if not (flag & 0x0001): if not (flag & 0x0001): # Connection not by offset
tail_position = struct.unpack('<3f', file.read(12)) tail_position = struct.unpack('<3f', file.read(12))
else: else:
tail_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0] tail_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0]
if flag & 0x0100 or flag & 0x0200: if flag & 0x0100 or flag & 0x0200: # Has inheritance
inherit_bone_parent_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0] inherit_bone_parent_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0]
inherit_bone_parent_influence = struct.unpack('<f', file.read(4))[0] inherit_bone_parent_influence = struct.unpack('<f', file.read(4))[0]
if flag & 0x0400: if flag & 0x0400: # Has fixed axis
fixed_axis = struct.unpack('<3f', file.read(12)) fixed_axis = struct.unpack('<3f', file.read(12))
if flag & 0x0800: if flag & 0x0800: # Has local coordinate
local_x_vector = struct.unpack('<3f', file.read(12)) local_x_vector = struct.unpack('<3f', file.read(12))
local_z_vector = struct.unpack('<3f', file.read(12)) local_z_vector = struct.unpack('<3f', file.read(12))
if flag & 0x2000: if flag & 0x2000: # Has external parent deform
external_key = struct.unpack('<i', file.read(4))[0] external_key = struct.unpack('<i', file.read(4))[0]
ik_links = [] if flag & 0x0020: # Has IK
if flag & 0x0020:
ik_target_bone_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0] ik_target_bone_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0]
ik_loop_count = struct.unpack('<i', file.read(4))[0] ik_loop_count = struct.unpack('<i', file.read(4))[0]
ik_limit_radian = struct.unpack('<f', file.read(4))[0] ik_limit_radian = struct.unpack('<f', file.read(4))[0]
ik_link_count = struct.unpack('<i', file.read(4))[0] ik_link_count = struct.unpack('<i', file.read(4))[0]
for _ in range(ik_link_count): for _ in range(ik_link_count):
ik_link_bone_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0] ik_link_bone_index = struct.unpack(replace_char(string_build, 1, '1'), file.read(byte_size))[0]
ik_link_limit_min = struct.unpack('<3f', file.read(12)) has_limits = struct.unpack('<b', file.read(1))[0]
ik_link_limit_max = struct.unpack('<3f', file.read(12)) if has_limits:
ik_links.append((ik_link_bone_index, ik_link_limit_min, ik_link_limit_max)) limit_min = struct.unpack('<3f', file.read(12))
limit_max = struct.unpack('<3f', file.read(12))
else:
limit_min = limit_max = None
ik_links.append((ik_link_bone_index, limit_min, limit_max))
return bone_name, bone_english_name, position, parent_bone_index, layer, flag, tail_position, inherit_bone_parent_index, inherit_bone_parent_influence, fixed_axis, local_x_vector, local_z_vector, external_key, ik_target_bone_index, ik_loop_count, ik_limit_radian, ik_links return bone_name, bone_english_name, position, parent_bone_index, layer, flag, tail_position, inherit_bone_parent_index, inherit_bone_parent_influence, fixed_axis, local_x_vector, local_z_vector, external_key, ik_target_bone_index, ik_loop_count, ik_limit_radian, ik_links
except Exception as e:
print(f"Error reading bone data: {str(e)}")
print(f"Current file position: {file.tell()}")
raise
def create_bones(armature_obj, bones_data, scale=0.08):
bpy.context.view_layer.objects.active = armature_obj
bpy.ops.object.mode_set(mode='EDIT')
edit_bones = []
for bone_data in bones_data:
bone = armature_obj.data.edit_bones.new(bone_data[0])
# Scale the head position
bone.head = Vector(bone_data[2]).xzy * scale
# Handle tail position with scale
if isinstance(bone_data[6], int) and bone_data[6] != -1:
target_pos = Vector(bones_data[bone_data[6]][2]).xzy * scale
bone.tail = target_pos
else:
offset = Vector(bone_data[6]).xzy * scale
bone.tail = bone.head + offset
if bone.length < 0.001:
bone.tail = bone.head + Vector((0, 0, 0.001))
edit_bones.append(bone)
# Set parent relationships
for i, bone_data in enumerate(bones_data):
if bone_data[3] != -1:
edit_bones[i].parent = edit_bones[bone_data[3]]
bpy.ops.object.mode_set(mode='OBJECT')
return edit_bones
def read_morph(file: BufferedReader, morph_struct, morph_bytesize, vertex_struct, vertex_size, bone_struct, bone_size, material_struct, material_size, rigid_struct, rigid_size): def read_morph(file: BufferedReader, morph_struct, morph_bytesize, vertex_struct, vertex_size, bone_struct, bone_size, material_struct, material_size, rigid_struct, rigid_size):
morph_name = str(file.read(struct.unpack('<i', file.read(4))[0]), 'utf-16-le', errors='replace') morph_name = str(file.read(struct.unpack('<i', file.read(4))[0]), 'utf-16-le', errors='replace')
morph_english_name = str(file.read(struct.unpack('<i', file.read(4))[0]), 'utf-16-le', errors='replace') morph_english_name = str(file.read(struct.unpack('<i', file.read(4))[0]), 'utf-16-le', errors='replace')
@@ -353,21 +403,30 @@ def import_pmx(filepath):
print("stage 8") print("stage 8")
# Read bones # Read bones
bone_count = struct.unpack('<i', file.read(4))[0] bone_count = struct.unpack('<i', file.read(4))[0]
print(f"Starting to read {bone_count} bones")
bones_read = 0
print("bone count: "+str(bone_count)) print("bone count: "+str(bone_count))
for _ in range(bone_count): for i in range(bone_count):
try:
bone_name, bone_english_name, position, parent_bone_index, layer, flag, tail_position, inherit_bone_parent_index, inherit_bone_parent_influence, fixed_axis, local_x_vector, local_z_vector, external_key, ik_target_bone_index, ik_loop_count, ik_limit_radian, ik_links = read_bone(file, bone_struct, bone_size) bone_name, bone_english_name, position, parent_bone_index, layer, flag, tail_position, inherit_bone_parent_index, inherit_bone_parent_influence, fixed_axis, local_x_vector, local_z_vector, external_key, ik_target_bone_index, ik_loop_count, ik_limit_radian, ik_links = read_bone(file, bone_struct, bone_size)
bones.append((bone_name, bone_english_name, position, parent_bone_index, layer, flag, tail_position, inherit_bone_parent_index, inherit_bone_parent_influence, fixed_axis, local_x_vector, local_z_vector, external_key, ik_target_bone_index, ik_loop_count, ik_limit_radian, ik_links)) bones.append((bone_name, bone_english_name, position, parent_bone_index, layer, flag, tail_position, inherit_bone_parent_index, inherit_bone_parent_influence, fixed_axis, local_x_vector, local_z_vector, external_key, ik_target_bone_index, ik_loop_count, ik_limit_radian, ik_links))
print(f"Successfully read bone {i}: {bone_name}")
bones_read += 1
except Exception as e:
print(f"Error reading bone {i}: {str(e)}")
print(f"Bytes read position: {file.tell()}")
break
print(f"Finished reading bones. Total bones read: {bones_read}")
# Read morphs # Read morphs
morph_count = struct.unpack('<i', file.read(4))[0] morph_count = struct.unpack('<i', file.read(4))[0]
print("morph count: "+str(morph_count)) print("morph count: "+str(morph_count))
for _ in range(morph_count): for _ in range(morph_count):
morph_name, morph_english_name, panel, morph_type, morph_data = read_morph(file, morph_struct, morph_size, vertex_struct, vertex_size, bone_struct, bone_size, material_struct, material_size, rigid_struct, rigid_size) morph_name, morph_english_name, panel, morph_type, morph_data = read_morph(file, morph_struct, morph_size, vertex_struct, vertex_size, bone_struct, bone_size, material_struct, material_size, rigid_struct, rigid_size)
morphs.append((morph_name, morph_english_name, panel, morph_type, morph_data)) morphs.append((morph_name, morph_english_name, panel, morph_type, morph_data))
@@ -459,41 +518,43 @@ def import_pmx(filepath):
modifier = obj.modifiers.new("Armature", 'ARMATURE') modifier = obj.modifiers.new("Armature", 'ARMATURE')
modifier.object = armature_obj modifier.object = armature_obj
bpy.context.view_layer.objects.active = armature_obj bpy.context.view_layer.objects.active = armature_obj
bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='EDIT')
for bone_data in bones: print("Starting bone creation...")
print(f"Total bones to create: {len(bones)}")
for i, bone_data in enumerate(bones):
try:
print(f"Creating bone {i}: {bone_data[0]}")
bone = armature.edit_bones.new(bone_data[0]) bone = armature.edit_bones.new(bone_data[0])
bone.head = bone_data[2] bone.head = bone_data[2]
if bone_data[6][0] != None: if bone_data[6][0] != None:
bone.tail = bone_data[6] bone.tail = bone_data[6]
print(f"Using defined tail position for bone {bone_data[0]}")
else: else:
bone.tail = [bone.head[0],bone.head[1],bone.head[2]+1] bone.tail = [bone.head[0], bone.head[1], bone.head[2]+0.1]
#print("fire2!") print(f"Using default tail position for bone {bone_data[0]}")
#print(bone_data)
if bone_data[3] != -1 or bone_data[3] != -1:
#print("parent bone index: " + str(bone_data[3]))
#print("parent bone name: \""+bones[bone_data[3]][0]+"\"")
#print("parent edit bone name: \""+armature.edit_bones[bones[bone_data[3]][0]].name+"\"")
#print("fire1!")
if bone_data[3] != -1:
parent_bone = armature.edit_bones[bones[bone_data[3]][0]] parent_bone = armature.edit_bones[bones[bone_data[3]][0]]
parent_bone.tail = bone.head.xyz
bone.parent = parent_bone bone.parent = parent_bone
# Set other bone properties based on the PMX data print(f"Parented bone {bone_data[0]} to {parent_bone.name}")
except Exception as e:
print(f"Error creating bone {i}: {str(e)}")
continue
print(f"Created bones: {len(armature.edit_bones)}")
print("Finished bone creation")
bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='OBJECT')
# Assign bone weights to the mesh # Assign bone weights to the mesh
for i, vertex in enumerate(vertices): for i, vertex in enumerate(vertices):
for j in range(0,len(vertex[3])): for j in range(0, len(vertex[3])):
if vertex[3][j] != -1: if vertex[3][j] != -1 and vertex[3][j] < len(bones): # Add bounds check
bone_name = bones[vertex[3][j]][0] bone_name = bones[vertex[3][j]][0]
weight = vertex[4][j] weight = vertex[4][j]