Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"python-envs.defaultEnvManager": "ms-python.python:system",
"python-envs.pythonProjects": []
}
2 changes: 1 addition & 1 deletion blender_bindings/models/mdl44/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def import_mdl44(model_path: TinyPath, buffer: Buffer,
logger.error(f'Failed to import materials, caused by {t_ex}')
import traceback
traceback.print_exc()
container = import_model(content_manager, mdl, vtx, vvd, options.scale, options.create_flex_drivers)
container = import_model(content_manager, mdl, vtx, vvd, options.scale, options.create_flex_drivers, debug_stereo_balance=options.debug_stereo_balance)
if options.import_physics:
phy_buffer = content_manager.find_file(model_path.with_suffix(".phy"))
if phy_buffer is None:
Expand Down
71 changes: 58 additions & 13 deletions blender_bindings/models/mdl44/import_mdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def create_armature(mdl: MdlV44, scale=1.0, load_refpose=False):


def import_model(content_manager: ContentManager, mdl: MdlV44, vtx: Vtx, vvd: Vvd,
scale=1.0, create_drivers=False, load_refpose=False):
scale=1.0, create_drivers=False, load_refpose=False, *, debug_stereo_balance=False):
full_material_names = collect_full_material_names([mat.name for mat in mdl.materials], mdl.materials_paths,
content_manager)
[setattr(mat, 'bpy_material', get_or_create_material(mat.name, full_material_names[mat.name])) for mat in mdl.materials if mat.bpy_material is None]
Expand All @@ -95,7 +95,7 @@ def import_model(content_manager: ContentManager, mdl: MdlV44, vtx: Vtx, vvd: Vv
static_prop = mdl.header.flags & StudioHDRFlags.STATIC_PROP != 0
armature = None
vertex_anim_cache = preprocess_vertex_animation(mdl, vvd)

vert_anim_fixed_point_scale = mdl.header.vert_anim_fixed_point_scale if (mdl.header.flags & StudioHDRFlags.VERT_ANIM_FIXED_POINT_SCALE !=0 ) else 1/4096
if not static_prop:
armature = create_armature(mdl, scale)

Expand Down Expand Up @@ -167,23 +167,68 @@ def import_model(content_manager: ContentManager, mdl: MdlV44, vtx: Vtx, vvd: Vv
bone_name = mdl.bones[bone_index].name
weight_groups[bone_name].add([n], weight, 'REPLACE')

flex_names = []
flexes = []
for mesh in model.meshes:
if mesh.flexes:
flex_names.extend([mdl.flex_names[flex.flex_desc_index] for flex in mesh.flexes])
flexes.extend([(mdl.flex_names[flex.flex_desc_index], flex) for flex in mesh.flexes])

if flex_names:
if flexes:
mesh_obj.shape_key_add(name='base')
for flex_name in flex_names:
shape_key = mesh_data.shape_keys.key_blocks.get(flex_name, None) or mesh_obj.shape_key_add(
name=flex_name)
shape_key.value = 0.0
vertex_animation = vertex_anim_cache[flex_name]

model_vertices = get_slice(vertex_animation["pos"], model.vertex_offset, model.vertex_count)
flex_vertices = model_vertices[vtx_vertices] * scale
if debug_stereo_balance:
# debug tool to get stereo flex balances. i'll leave it here just in case
side_right = mesh_obj.vertex_groups.new(name='blendright')
side_left = mesh_obj.vertex_groups.new(name='blendleft')
side_all = np.zeros(model.vertex_count, dtype=np.float32)

for flex_name, flex_desc in flexes:
vertex_animation = vertex_anim_cache[flex_name]
side = get_slice(vertex_animation['side'], model.vertex_offset, model.vertex_count).ravel()
side_all = np.maximum(side_all, side)
side_all = side_all[vtx_vertices] + 0.0

shape_key.data.foreach_set("co", flex_vertices.reshape(-1))
for n, vert in enumerate(vtx_vertices):
side_right.add([n], side_all[n], 'REPLACE')
side_left.add([n], 1-side_all[n], 'REPLACE')

for flex_name, flex_desc in flexes:
vertex_animation = vertex_anim_cache[flex_name]
flex_delta = get_slice(vertex_animation["pos"], model.vertex_offset, model.vertex_count)
flex_delta = flex_delta[vtx_vertices] * scale

side = get_slice(vertex_animation["side"], model.vertex_offset, model.vertex_count)
side = side[vtx_vertices] + 0.0
wrinkle = get_slice(vertex_animation["wrinkle"], model.vertex_offset, model.vertex_count)
wrinkle = wrinkle[vtx_vertices] + 0.0 # this will have to be explained to me :P
# model.vertex_count and vtx_vertices can differ in size, so doing something like this just makes it work?
# apparently vtx_vertices has duplicate indicies, which can be observed by turning it into a set.
# i'm just following here
# -hisanimations

model_vertices = get_slice(all_vertices['vertex'], model.vertex_offset, model.vertex_count)
model_vertices = model_vertices[vtx_vertices] * scale

if flex_desc.partner_index:
partner_name = mdl.flex_names[flex_desc.partner_index]
flexes, sides = [flex_name, partner_name], [1-side, side] if not debug_stereo_balance else [1.0, 1.0]
else:
flexes, sides = [flex_name], [1.0]

for flex_name, side in zip(flexes, sides):
shape_key = mesh_data.shape_keys.key_blocks.get(flex_name, None) or mesh_obj.shape_key_add(
name=flex_name)
shape_key.data.foreach_set("co", (flex_delta*side + model_vertices).ravel())
shape_key.value = 0.0

if flex_desc.vertex_anim_type == 1:
mesh_data: bpy.types.Mesh
if wrinkle.max() > 0:
wrinkle_name = f'WR.{flex_name}.S'
if wrinkle.min() < 0:
wrinkle_name = f'WR.{flex_name}.C'
attr: bpy.types.Attribute = mesh_data.attributes.get(wrinkle_name, None) or mesh_data.attributes.new(wrinkle_name, 'FLOAT', 'POINT')
wrinkle_data = (abs(wrinkle) * vert_anim_fixed_point_scale) * side
attr.data.foreach_set('value', wrinkle_data.ravel())

if create_drivers:
create_flex_drivers(mesh_obj, mdl)
Expand Down
2 changes: 1 addition & 1 deletion blender_bindings/models/mdl49/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def import_mdl49(model_path: TinyPath, buffer: Buffer,
import traceback
traceback.print_exc()

container = import_model(content_manager, mdl, vtx, vvd, options.scale, options.create_flex_drivers)
container = import_model(content_manager, mdl, vtx, vvd, options.scale, options.create_flex_drivers, debug_stereo_balance=options.debug_stereo_balance)
if options.import_physics:
phy_buffer = content_manager.find_file(model_path.with_suffix(".phy"))
if phy_buffer is None:
Expand Down
67 changes: 47 additions & 20 deletions blender_bindings/models/mdl49/import_mdl.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@


def import_model(content_manager: ContentManager, mdl: MdlV49, vtx: Vtx, vvd: Vvd,
scale=1.0, create_drivers=False, load_refpose=False):
scale=1.0, create_drivers=False, load_refpose=False, *, debug_stereo_balance=False):
full_material_names = collect_full_material_names([mat.name for mat in mdl.materials], mdl.materials_paths, content_manager)
[setattr(mat, 'bpy_material', get_or_create_material(mat.name, full_material_names[mat.name])) for mat in mdl.materials if mat.bpy_material is None]
# ensure all MaterialV49 has its bpy_material counterpart
Expand All @@ -42,6 +42,7 @@ def import_model(content_manager: ContentManager, mdl: MdlV49, vtx: Vtx, vvd: Vv
all_vertices = vvd.lod_data[desired_lod]
extra_stuff = []
static_prop = mdl.header.flags & StudioHDRFlags.STATIC_PROP != 0
vert_anim_fixed_point_scale = mdl.header.vert_anim_fixed_point_scale if (mdl.header.flags & StudioHDRFlags.VERT_ANIM_FIXED_POINT_SCALE !=0 ) else 1/4096
armature = None
vertex_anim_cache = preprocess_vertex_animation(mdl, vvd)
if not static_prop:
Expand Down Expand Up @@ -133,37 +134,63 @@ def import_model(content_manager: ContentManager, mdl: MdlV49, vtx: Vtx, vvd: Vv

if flexes:
mesh_obj.shape_key_add(name='base')

if debug_stereo_balance:
# debug tool to get stereo flex balances. i'll leave it here just in case
side_right = mesh_obj.vertex_groups.new(name='blendright')
side_left = mesh_obj.vertex_groups.new(name='blendleft')
side_all = np.zeros(model.vertex_count, dtype=np.float32)

for flex_name, flex_desc in flexes:
vertex_animation = vertex_anim_cache[flex_name]
side = get_slice(vertex_animation['side'], model.vertex_offset, model.vertex_count).ravel()
side_all = np.maximum(side_all, side)
side_all = side_all[vtx_vertices] + 0.0

for n, vert in enumerate(vtx_vertices):
side_right.add([n], side_all[n], 'REPLACE')
side_left.add([n], 1-side_all[n], 'REPLACE')

for flex_name, flex_desc in flexes:
vertex_animation = vertex_anim_cache[flex_name]
flex_delta = get_slice(vertex_animation["pos"], model.vertex_offset, model.vertex_count)
flex_delta = flex_delta[vtx_vertices] * scale

side = get_slice(vertex_animation["side"], model.vertex_offset, model.vertex_count)
side = side[vtx_vertices] + 0.0
wrinkle = get_slice(vertex_animation["wrinkle"], model.vertex_offset, model.vertex_count)
wrinkle = wrinkle[vtx_vertices] + 0.0 # this will have to be explained to me :P
# model.vertex_count and vtx_vertices can differ in size, so doing something like this just makes it work?
# apparently vtx_vertices has duplicate indicies, which can be observed by turning it into a set.
# i'm just following here
# -hisanimations

model_vertices = get_slice(all_vertices['vertex'], model.vertex_offset, model.vertex_count)
model_vertices = model_vertices[vtx_vertices] * scale

if create_drivers and flex_desc.partner_index:
if flex_desc.partner_index:
partner_name = mdl.flex_names[flex_desc.partner_index]
partner_shape_key = (mesh_data.shape_keys.key_blocks.get(partner_name, None) or
mesh_obj.shape_key_add(name=partner_name))
partner_shape_key.value = 0.0
shape_key = (mesh_data.shape_keys.key_blocks.get(flex_name, None) or
mesh_obj.shape_key_add(name=flex_name))
shape_key.value = 0.0

balance = model_vertices[:, 0]
balance_width = (model_vertices.max() - model_vertices.min()) * (1 - (99.3 / 100))
balance = np.clip((-balance / balance_width / 2) + 0.5, 0, 1)

flex_vertices = (flex_delta * balance[:, None]) + model_vertices
shape_key.data.foreach_set("co", flex_vertices.reshape(-1))

p_balance = 1 - balance
p_flex_vertices = (flex_delta * p_balance[:, None]) + model_vertices
partner_shape_key.data.foreach_set("co", p_flex_vertices.reshape(-1))
flexes, sides = [flex_name, partner_name], [1-side, side] if not debug_stereo_balance else [1.0, 1.0]
else:
flexes, sides = [flex_name], [1.0]

for flex_name, side in zip(flexes, sides):
shape_key = mesh_data.shape_keys.key_blocks.get(flex_name, None) or mesh_obj.shape_key_add(
name=flex_name)
shape_key.data.foreach_set("co", (flex_delta*side + model_vertices).ravel())
shape_key.value = 0.0
shape_key.data.foreach_set("co", (flex_delta + model_vertices).ravel())

if flex_desc.vertex_anim_type == 1:
mesh_data: bpy.types.Mesh
if wrinkle.max() > 0:
wrinkle_name = f'WR.{flex_name}.S'
if wrinkle.min() < 0:
wrinkle_name = f'WR.{flex_name}.C'
attr: bpy.types.Attribute = mesh_data.attributes.get(wrinkle_name, None) or mesh_data.attributes.new(wrinkle_name, 'FLOAT', 'POINT')
wrinkle_data = (abs(wrinkle) * vert_anim_fixed_point_scale) * side
attr.data.foreach_set('value', wrinkle_data.ravel())


if create_drivers:
create_flex_drivers(mesh_obj, mdl)
mesh_data.validate()
Expand Down
2 changes: 1 addition & 1 deletion blender_bindings/models/mdl52/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def import_mdl52(model_path: TinyPath, buffer: Buffer,
import traceback
traceback.print_exc()

container = import_model(content_manager, mdl, vtx, vvd, vvc, options.scale)
container = import_model(content_manager, mdl, vtx, vvd, vvc, options.scale, debug_stereo_balance=options.debug_stereo_balance)
if options.import_physics:
phy_buffer = content_manager.find_file(model_path.with_suffix(".phy"))
if phy_buffer is None:
Expand Down
Loading