Skip to content

Commit

Permalink
次作ツール用にコード整理
Browse files Browse the repository at this point in the history
  • Loading branch information
miu200521358 committed Sep 25, 2021
1 parent c49fd20 commit 9019165
Show file tree
Hide file tree
Showing 7 changed files with 488 additions and 681 deletions.
159 changes: 23 additions & 136 deletions src/mmd/PmxData.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1143,17 +1143,17 @@ cdef class PmxModel:
logger.warning("腕・ひじ・手首の左右ボーンが揃ってないため、%s\nモデル: %s", cannot_sizing, self.name, decoration=MLogger.DECORATION_BOX)
return False

# for bone_name in self.bones.keys():
# if ("腕IK" in bone_name or "腕IK" in bone_name or "うでIK" in bone_name or "うでIK" in bone_name or "腕XIK" in bone_name):
# # 腕IKが入ってて、かつそれが表示されてる場合、NG
# logger.warning("モデルに「腕IK」に類するボーンが含まれているため、%s\nモデル: %s", cannot_sizing, self.name, decoration=MLogger.DECORATION_BOX)
# return False
for bone_name in self.bones.keys():
if ("腕IK" in bone_name or "腕IK" in bone_name or "うでIK" in bone_name or "うでIK" in bone_name or "腕XIK" in bone_name):
# 腕IKが入ってて、かつそれが表示されてる場合、NG
logger.warning("モデルに「腕IK」に類するボーンが含まれているため、%s\nモデル: %s", cannot_sizing, self.name, decoration=MLogger.DECORATION_BOX)
return False

return True

# ボーンリンク生成
def create_link_2_top_lr(self, *target_bone_types, **kwargs):
is_defined = kwargs["is_defined"] if "is_defined" in kwargs else False
is_defined = kwargs["is_defined"] if "is_defined" in kwargs else True

for target_bone_type in target_bone_types:
left_links = self.create_link_2_top_one("左{0}".format(target_bone_type), is_defined=is_defined)
Expand All @@ -1165,150 +1165,40 @@ cdef class PmxModel:

# ボーンリンク生成
def create_link_2_top_one(self, *target_bone_names, **kwargs):
# 未定義のままで生成する
is_defined = kwargs["is_defined"] if "is_defined" in kwargs else False
tmp_links = None
is_defined = kwargs["is_defined"] if "is_defined" in kwargs else True

for target_bone_name in target_bone_names:
logger.test("create_link_2_top_one: %s", target_bone_name)
# 子からの直系ボーン
tmp_links = self.create_link_2_top(target_bone_name, tmp_links, is_defined)
links = self.create_link_2_top(target_bone_name, None, is_defined)

# # 付与親も念のため追加
# append_bone_names = []
# for lk, lv in tmp_links.items():
# if lv.getExternalRotationFlag() or lv.getExternalTranslationFlag():
# append_bone_names.append(self.bone_indexes[lv.effect_index])
# for bname in append_bone_names:
# tmp_links[bname] = self.bones[bname]

# IKを取得
ik_links_dict = self.create_ik_links(tmp_links)

reversed_links = self.reverse_links(tmp_links)

if reversed_links:
for ik_target_name, links_dict in ik_links_dict.items():
reversed_links.append_ik_links(self.bones[ik_target_name], links_dict["target"], links_dict["ik"])

if reversed_links.size() > 0:
logger.debug_info("reversed_links: %s, \n%s", self.name, reversed_links.to_log())
return reversed_links
if links and target_bone_name in links.all():
reversed_links = BoneLinks()

# リンクがある場合、反転させて返す
for lname in reversed(links.all()):
reversed_links.append(links.get(lname))

return reversed_links

# 最後まで回しても取れなかった場合、エラー
raise SizingException("ボーンリンクの生成に失敗しました。モデル「%s」に「%s」のボーンがあるか確認してください。" % (self.name, ",".join(target_bone_names)))

def reverse_links(self, links: dict, is_ik=False):
reversed_links = BoneLinks()

# if is_ik:
# total_links = {}

# for lv in links.values():
# # IKボーンリストの場合、階層+ボーン順番
# if lv.index >= 0:
# total_links[f'{lv.layer:04d}-{lv.index:04d}'] = lv

# if len(total_links.keys()) > 1:
# # ボーン順番でソート
# for tlk in sorted(list(total_links.keys())):
# # まだ登録されていない
# if total_links[tlk].index >= 0:
# reversed_links.append(total_links[tlk], total_links[tlk].layer)
# logger.test("tlk: %s, %s", tlk, total_links[tlk].name)

# logger.test("reverse_links:%s, \n%s", self.name, reversed_links.to_log())

# return reversed_links
# else:
total_links = {}

for lv in links.values():
# 直系ボーンリストの場合、ボーン順番
total_links[f'{lv.index:04d}'] = lv

layers = []
for lidx, lv in enumerate(links.values()):
layers.append(lv.layer)

# 直系リストは変形階層別にレイヤー生成
target_layers = [min(layers)]
if len(layers) > 1:
target_layers.append(max(layers))

for layer in range(max(layers) + 1):
total_links = {}
for lv in links.values():
if lv.index >= 0 and layer == lv.layer:
total_links[f'{lv.index:04d}'] = lv

# ボーン順番でソート
for tlk in sorted(list(total_links.keys())):
if total_links[tlk].index >= 0:
reversed_links.append(total_links[tlk], layer)

logger.test("tlk: %s-%s, %s, index: %s", layer, tlk, total_links[tlk].name, total_links[tlk].index)

logger.test("reverse_links:%s, \n%s", self.name, reversed_links.to_log())

return reversed_links

# return None

def create_ik_links(self, links: dict):
ik_links_dict = {}

for dl in links.values():
if dl.name in ["全ての親", "センター", "グルーブ"]:
# 移動系は無視
continue

for b in self.bones.values():
if b.getIkFlag() and (dl.index in [i.bone_index for i in b.ik.link] or b.parent_index == dl.index):
link_bone_names = []

# 自分のINDEXがIK系列に含まれている場合、IKボーンのボーンリンクを保持
ik_target_dicts = self.create_link_2_top(b.name, None, False)

# ボーンリンクに、ターゲットとリンクを含める
link_dicts = {}
for i in b.ik.link:
one_link_dicts = self.create_link_2_top(self.bones[self.bone_indexes[i.bone_index]].name, None, False)
for k, v in one_link_dicts.items():
if k not in link_dicts:
link_dicts[k] = v
# if v.layer < b.layer:
# ik_target_dicts[k] = v
link_bone_names.append(self.bones[self.bone_indexes[i.bone_index]].name)
# ターゲットの位置を捕捉するために、追加
link_dicts[self.bone_indexes[b.ik.target_index]] = self.bones[self.bone_indexes[b.ik.target_index]]
ik_target_dicts[self.bone_indexes[b.ik.target_index]] = self.bones[self.bone_indexes[b.ik.target_index]]

for link_bone_name in link_bone_names:
ik_links_dict[link_bone_name] = {"target": self.reverse_links(ik_target_dicts, is_ik=True), "ik": self.reverse_links(link_dicts, is_ik=True)}

return ik_links_dict

# リンク生成
def create_link_2_top(self, target_bone_name: str, links: dict, is_defined: bool):
def create_link_2_top(self, target_bone_name: str, links: BoneLinks, is_defined: bool):
if not links:
# まだリンクが生成されていない場合、順序保持辞書生成
links = {}
links = BoneLinks()

if target_bone_name not in self.bones: # and target_bone_name not in self.PARENT_BORN_PAIR:
if target_bone_name not in self.bones and target_bone_name not in self.PARENT_BORN_PAIR:
# 開始ボーン名がなければ終了
logger.test("target_bone_name not in bones: %s", target_bone_name)
return links

logger.test("create_link_2_top start: %s", target_bone_name)

start_type_bone = target_bone_name
if target_bone_name.startswith("") or target_bone_name.startswith(""):
# 左右から始まってたらそれは除く
start_type_bone = target_bone_name[1:]

# 自分をリンクに登録
links[target_bone_name] = self.bones[target_bone_name]
links.append(self.bones[target_bone_name])

parent_name = None
if is_defined:
Expand All @@ -1325,24 +1215,21 @@ cdef class PmxModel:
# 未定義でよい場合
if self.bones[target_bone_name].parent_index >= 0:
# 親ボーンが存在している場合
logger.test("parent_index: %s -> %s", self.bones[target_bone_name].parent_index, self.bone_indexes[self.bones[target_bone_name].parent_index])
parent_name = self.bone_indexes[self.bones[target_bone_name].parent_index]

if not parent_name:
logger.test("not parent_name: %s", self.bones[target_bone_name].parent_index)
logger.test("create_link_2_top: %s, %s, \n%s", self.name, target_bone_name, links)
# 親ボーンがボーンインデックスリストになければ終了
return links

logger.test("target_bone_name: %s, parent_name: %s, start_type_bone: %s", target_bone_name, parent_name, start_type_bone)
logger.test("target_bone_name: %s. parent_name: %s, start_type_bone: %s", target_bone_name, parent_name, start_type_bone)

# 親をたどる
try:
return self.create_link_2_top(parent_name, links, is_defined)
except RecursionError:
raise SizingException("ボーンリンクの生成に失敗しました。\nモデル「%s」の「%s」ボーンで以下を確認してください。\n" % (self.name, target_bone_name) \
raise SizingException("ボーンリンクの生成に失敗しました。\nモデル「{0}」の「{1}」ボーンで以下を確認してください。\n" \
+ "・同じ名前のボーンが複数ないか(ボーンのINDEXがズレるため、サイジングに失敗します)\n" \
+ "・親ボーンに自分の名前と同じ名前のボーンが指定されていないか\n※ PMXEditorの「PMXデータの状態検証」から確認できます。")
+ "・親ボーンに自分の名前と同じ名前のボーンが指定されていないか\n※ PMXEditorの「PMXデータの状態検証」から確認できます。".format(self.name, target_bone_name))

# 子孫ボーンリスト取得
def get_child_bones(self, target_bone: Bone, bone_list=None):
Expand Down
68 changes: 34 additions & 34 deletions src/mmd/PmxReader.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,34 +729,34 @@ def read_data(self):
pmx.bones[leg_center_bone.name] = leg_center_bone
pmx.bone_indexes[leg_center_bone.index] = leg_center_bone.name

# ボーンの並び替え
tmp_bones = {}
tmp_bone_indexes = {}
for k, v in pmx.bones.items():
tmp_bones[k] = v.copy()
tmp_bone_indexes[v.index] = k

root_bone = (list(pmx.bones.values())[0]).copy()
root_bone.index = -1
root_bone.is_sizing = True

pmx.bones = {}
pmx.bone_indexes = {}
pmx.bones[root_bone.name] = root_bone
pmx.bone_indexes[root_bone.index] = root_bone.name
index = -2
for is_ik in [False, True]:
index = self.sort_bones(pmx, tmp_bones, tmp_bone_indexes, root_bone.index, is_ik, index)

for bv in pmx.bones.values():
if bv.tail_index >= 0:
bv.tail_index = pmx.bones[tmp_bone_indexes[bv.tail_index]].index
if bv.effect_index >= 0:
bv.effect_index = pmx.bones[tmp_bone_indexes[bv.effect_index]].index
if bv.ik:
bv.ik.target_index = pmx.bones[tmp_bone_indexes[bv.ik.target_index]].index
for n in range(len(bv.ik.link)):
bv.ik.link[n].bone_index = pmx.bones[tmp_bone_indexes[bv.ik.link[n].bone_index]].index
# # ボーンの並び替え
# tmp_bones = {}
# tmp_bone_indexes = {}
# for k, v in pmx.bones.items():
# tmp_bones[k] = v.copy()
# tmp_bone_indexes[v.index] = k

# root_bone = (list(pmx.bones.values())[0]).copy()
# root_bone.index = -1
# root_bone.is_sizing = True

# pmx.bones = {}
# pmx.bone_indexes = {}
# pmx.bones[root_bone.name] = root_bone
# pmx.bone_indexes[root_bone.index] = root_bone.name
# index = -2
# for is_ik in [False, True]:
# index = self.sort_bones(pmx, tmp_bones, tmp_bone_indexes, root_bone.index, is_ik, index)

# for bv in pmx.bones.values():
# if bv.tail_index >= 0:
# bv.tail_index = pmx.bones[tmp_bone_indexes[bv.tail_index]].index
# if bv.effect_index >= 0:
# bv.effect_index = pmx.bones[tmp_bone_indexes[bv.effect_index]].index
# if bv.ik:
# bv.ik.target_index = pmx.bones[tmp_bone_indexes[bv.ik.target_index]].index
# for n in range(len(bv.ik.link)):
# bv.ik.link[n].bone_index = pmx.bones[tmp_bone_indexes[bv.ik.link[n].bone_index]].index

logger.debug_info("bones: %s", ", ".join([f"{b.index:04d}-{b.parent_index:04d}[{b.name}]" for b in pmx.bones.values()]))

Expand Down Expand Up @@ -847,15 +847,15 @@ def read_data(self):
for _ in range(display_count):
display_type = self.read_int(1)
if display_type == 0:
born_idx = self.read_bone_index_size()
display_slot.references.append(born_idx)
bone_idx = self.read_bone_index_size()
display_slot.references.append((display_type, bone_idx))
# ボーン表示ON
for v in pmx.bones.values():
if v.index == born_idx:
if v.index == bone_idx:
v.display = True
elif display_type == 1:
morph_idx = self.read_morph_index_size()
display_slot.references.append(morph_idx)
display_slot.references.append((display_type, morph_idx))
# モーフ表示ON
for v in pmx.morphs.values():
if v.index == morph_idx:
Expand Down Expand Up @@ -1203,7 +1203,7 @@ def read_uint(self, format_size):
else:
raise MParseException("read_uint format_sizeエラー {0}".format(format_size))

return self.unpack(format_size, format_type)
return int(self.unpack(format_size, format_type))

# 小数の解凍
def read_float(self, format_size=4):
Expand All @@ -1214,7 +1214,7 @@ def read_float(self, format_size=4):
else:
raise MParseException("read_float format_sizeエラー {0}".format(format_size))

return self.unpack(format_size, format_type)
return float(self.unpack(format_size, format_type))

# 解凍して、offsetを更新する
def unpack(self, format_size, format):
Expand Down
19 changes: 13 additions & 6 deletions src/mmd/VmdData.pxd
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
#
cimport numpy as np
from module.MMath cimport MRect, MVector2D, MVector3D, MVector4D, MQuaternion, MMatrix4x4 # noqa


Expand All @@ -10,7 +11,7 @@ cdef class LowPassFilter:
cdef __setAlpha(self, double alpha)
cdef double c__call__(self, double value, double timestamp, double alpha)
cdef double lastValue(self)
cdef double skip(self, double value)
cdef double skip(self, double value, double timestamp, double alpha)

cdef class OneEuroFilter:
cdef double __freq
Expand All @@ -22,7 +23,6 @@ cdef class OneEuroFilter:
cdef double __lasttime
cdef double __alpha(self, double cutoff)
cdef double c__call__(self, double x, double timestamp)
cdef c_skip(self, double x, str timestamp)

cdef class VmdBoneFrame:
cdef public str name
Expand Down Expand Up @@ -71,12 +71,19 @@ cdef class VmdMotion:

cdef c_smooth_bf(self, int data_set_no, str bone_name, bint is_rot, bint is_mov, double limit_degrees, int start_fno, int end_fno, bint is_show_log)

cdef c_smooth_filter_bf(self, int data_set_no, str bone_name, bint is_rot, bint is_mov, int loop, dict config, int start_fno, int end_fno, bint is_show_log)
cdef c_smooth_filter_bf(self, int data_set_no, str bone_name, bint is_rot, bint is_mov, int loop, dict mconfig, int start_fno, int end_fno, bint is_show_log)

cdef c_remove_unnecessary_bf(self, int data_set_no, str bone_name, bint is_rot, bint is_mov, \
double offset, double rot_diff_limit, double mov_diff_limit, int start_fno, int end_fno, bint is_show_log, bint is_force)
cdef list c_remove_unnecessary_bf(self, int data_set_no, str bone_name, bint is_rot, bint is_mov, \
double offset, double rot_diff_limit, double mov_diff_limit, int start_fno, int end_fno, bint is_show_log, bint is_force, bint is_sub_remove,
dict rot_diff_value_dict, dict mx_diff_value_dict, dict my_diff_value_dict, dict mz_diff_value_dict, list infections)

cdef c_regist_bf(self, VmdBoneFrame bf, str bone_name, int fno, bint copy_interpolation)
cdef tuple c_get_infections(self, int data_set_no, str bone_name, bint is_rot, bint is_mov, np.ndarray fnos, list active_fnos)

# cdef dict c_smooth_values(self, dict values, int delimiter)

cdef dict c_smooth_values(self, dict value_dict, dict config)

cdef c_regist_bf(self, VmdBoneFrame bf, str bone_name, int fno, bint copy_interpolation, bint key)

cdef VmdBoneFrame c_calc_bf(self, str bone_name, int fno, bint is_key, bint is_read, bint is_reset_interpolation)

Expand Down
Loading

0 comments on commit 9019165

Please sign in to comment.