戦国時代の怖い話というと鍋島藩の化け猫の話を思い浮かべます。
どうも、クリーク・アンド・リバー社 COYOTE 3DCG STUDIO テクニカルチーム所属、戦国大好き人間の中林です。
横断でデータを見るTAだから見えるジョイントの怖い話
弊スタジオでは、ありがたいことに多くの会社からお仕事を受注しています。
横断的にいろんなプロジェクトから相談を受けるTA(テクニカルアーティスト)ならではですが、さまざまな会社のプロジェクト単位でデータを見ることが多いです。
その中で最も目につくのが、キャラクターのジョイントに関する問題です。
ジョイントの怖い話はいくつかありますが、このブログでは左右のジョイント名に焦点を当てていきたいと思います。
ちなみに、この娘は我がTAチームのマスコットキャラクター、九十九天音(つくもあまね)ちゃんです。
参考までに、九十九天音ちゃんのジョイント数は72本です。
今は揺れ物の少ない衣装で作成していますが、九十九天音ちゃんは今後は揺れ物などをイメージした衣装も用意していく予定です。
その時には数百本単位でジョイントが増えると予想してます。
この本数でもいろんなキャラで列挙すると長くなるので、今回は比較対象を上腕のジョイントに絞ります。
左右の上腕のジョイント名を比較しよう
会社名 | キャラ名 | 右上腕 | 左上腕 |
COYOTEスタジオ | 九十九天音 | UpperArm_R | UpperArm_L |
COYOTEスタジオ | 栗川さん | upper_armR | upper_armL |
COYOTEスタジオ | ミスBB | UpperArm_R | UpperArm_L |
Maya | HumanIk | CharacterX_RightArm | CharacterX_LeftArm |
Unreal Engine | Mannequin | upperarm_r | upperarm_l |
A社 | プロジェクト➀ | RightArm | LeftArm |
A社 | プロジェクト➁ | UpperArm_R | UpperArm_L |
B社 | プロジェクト➀ | Jnt_R_Arm_00 | Jnt_R_Arm_00 |
C社 | プロジェクト➀ | joint_Arm1_R | joint_Arm1_L |
D社 | プロジェクト➀ | RightArm | LeftArm |
E社 | プロジェクト➀ | Arm_R | Arm_L |
F社 | プロジェクト➀ | RightArm | LeftArm |
G社 | プロジェクト➀ | upperArmR | upperArmL |
H社 | プロジェクト➀ | upper_arm_R | upper_arm_L |
I社 | プロジェクト➀ | uparm_r | uparm_l |
J社 | プロジェクト➀ | RArm1 | LArm1 |
L社 | プロジェクト➀ | Arm_R | Arm_L |
M社 | プロジェクト➀ | R_arm | L_arm |
M社 | プロジェクト➁ | r_arm01 | l_arm01 |
N社 | プロジェクト➀ | J_arm_L | J_arm_L |
O社 | プロジェクト➀ | arm_R_jnt | arm_L_jnt |
P社 | プロジェクト➀ | RightArm | LeftArm |
P社 | プロジェクト➁ | jnt_R_upperArm00_00 | jnt_L_upperArm00_00 |
まだまだデータはありますが、かなりバラエティに富んでいますね。
同じ名前がある程度出るまで意地になってリストアップしましたが、ほとんど同じ名前はありませんでした。
怖いことに同じクライアントのキャラデータでもジョイント名はバラバラです。
本来なら「共通点を見つけてジョイント名のルールを統一しませんか?」という内容でブログを書こうと思っていたのですが、困ったことに目論見が外れてしまいました。
とはいえ、さまざまなジョイント名を比較してみると、興味深い点もあります。
大文字・小文字を区別すると大変なので、この項では小文字に統一します。
【rightとleft
】
と 【rとl
】
の2パターンに分かれる
最も分かりやすい違いは当然、こちらの左右を全部書くか短縮するかの違いです。
前者のメリットは、置換がしやすい点です。
後者は置換がしにくい問題がありますが、その点については後ほど触れます。
ただし、前者は手動でジョイントを命名する際に手間がかかるためか、少数派になっています。
【rightとleft】を使うと高確率で先頭に来るという特典があったので残念です。
ジョイントを明示するかどうかの違い
「j、joint、jnt」 という命名が見られますが、これらはすべてジョイントを表していると考えられます。
ただ、全体的に見るとあまり主流ではないようです。
最近では、ジョイント名はこれを付けなくても、その名前がジョイントであると認識される傾向にあります。
個人的には、Mayaのコンストレイントを使うと自動で「joint_arm1_r_pointConstraint1」という名前が付くので、ジョイントなのかコンストレイントなのか分からなくなるため、避けたいです。
しかし、なんでこれを付ける時だけはみんな先頭に持ってくるんだだろう……。
上腕の名前の差
【upperarm】と【arm(Xの数値)】と大きく2つに大別されます。
同じ【arm】系の子階層を見ると、【arm0⇒arm1⇒arm2】というパターンと【arm⇒forearm⇒hand】というパターンがあり、数字の有無によって前腕の命名ルールが変わってきます。
これは、時代の変遷が影響しているのではないかと予想しています。
ジョイント数が増えていく過渡期において、上腕や前腕を細かく分類する前の命名ルールが、そのまま残っているのではないでしょうか。
長年続くプロジェクトではジョイント名を変更する機会がなく、使い続けられるケースもありそうです。
他にもキャメルケースやスネークケースでは収まらない、大文字と_(アンダーバー)の違いなども多く見て取れます。
Mayaがオブジェクト名に-(ハイフン)が使えていたら、もっと複雑な命名になっていたかもしれません。
LRの名前を比較して処理をして欲しい、汎用的に!!
TAによく求められるのは、「左右のジョイント名を比較して、汎用的に処理するツールを作れないか?」という相談です。
専用ツールならLRの文字位置が固定されているため簡単ですが、汎用化すると難易度が跳ね上がります。
例えば、単純にlrの文字を置換してしまうと「l_leg」をrに置換すると「r_reg」 になりますし、「r_ring」 をlに置換すると「l_lling」 になってしまいます。
このような問題があるため、ジョイント名の置換は一筋縄ではいきません。
僕個人としては、素直に汎用化しないで専用ツールをお勧めします。
それでも汎用的に!! に答える方法例
あくまで個人的には専用ツールをお勧めしても、やはり依頼者からはそこを何とか汎用でできないかに答えることもあります。
ここでは既に名前の付けられた左右の比較例で紹介します。
単純なはrightとleftは省きます。
import re
def checkJointLR():
compDict = {}
for joint in cmds.ls(type = "joint"):
# lかrが含まれない物は対象外
if not re.search(r'[lr]', joint, re.IGNORECASE):
continue
# lかrを記号に置換
comp = re.sub(r'[lr]', '@', joint, flags=re.IGNORECASE)
# 記号名で辞書に登録、itemはジョイント名をリスト化
if comp in compDict:
compDict[comp].append(joint)
else:
compDict[comp] = [joint]
# 基本的にアイテムが2つならlrに分かれている。
pairList = []
for jointPair in compDict.values():
if len(jointPair) == 2:
pairList.append(jointPair)
pairJointList = checkJointLR()
print(pairJointList)
ジョイント名にlかrが含まれていたら@マークなどの記号に置き換えます。
「UpperLeg_L」と「UpperLeg_R」なら「Uppe@@eg_@」の名前が2つになります。
仮に「HairTail01」などがあれば「Hai@Tai@01」は1つだけです。
記号名を辞書型のKeyにして同じ名前があれば、itemのリストに追加していきます。
よほど、複雑な名前にしなければ2つのpairは左右のジョイント名になります。
今回は簡易的に書きましたが、より正しいか判断をするなら、
➀左右のジョイントの座標を比較する。
➁一文字ずつ比較をしてlとrの違いの場所を特定する。
これらの方法でより確実に左右のジョイント名の組み合わせを取得できます。
あくまで一例だけど、僕はこの方法を重宝してます。
ジョイント名で対応しきれなかった「migi」と「hidari」問題
ジョイント名の統一には、それなりに対応してきたつもりですが、正直に言うと「migi」と「hidari」の命名にはお手上げでした。
試しに、いくつかの国の「左右」を表す単語を調べてみました。
フランス語:「gauche ⇔ droite」
イタリア語:「sinistra ⇔ destra」
スペイン語:「izquierda ⇔ derecha」
中国語 :「zuǒ ⇔ yòu」
ドイツ語・オランダ語:「links ⇔ rechts」
ドイツ語やオランダ語のように【lとr】で解決する言語もありますが、ほとんどの言語では単語自体がまったく異なります。
こうなると、ローカル言語まで対応範囲に含めるのは現実的ではありません。
「どこまでサポートすればいいんだ…?」と、考えれば考えるほど沼にハマりそうです。
やはり、ジョイント名の命名ルールは、シンプルかつ共通化しやすいものにするのがベストですね。
本当に怖いのは人型じゃないジョイント名
人型は法則がないようで、それなりにあります。
しかし、四足歩行の動物やモンスターになると複雑になります。
これをルールを作らずに適当に名前を詰めずに進めて、後工程のプログラマーさんが絶望する光景は幾度となく見てます。
前足はfrontArm? frontLeg? frontUpperLeg? frontForeLeg? maeAshi!!!!!
僕のTAの立場からの意見だけど今の時代はルールを決めるだけでは足りないと考えています。
ルールに沿ってジョイント名を自動で付けるツールの提供も必須だと思います。
上図はAutodesk Day 2024での講演用に作成した資料です。
MELをPythonに移行しよう!ハイポリ時代のツール高速化
主に頂点のことを言及してますが、アサインされているジョイント数も書いてあります。
最近はジョイントの数はスマホでも500本以上、ハイポリだと1000本を超えるものも出てきます。
人体でも体幹ジョイントの9倍~20倍以上が人型以外のジョイントと言っても過言ではありません。
指のジョイントすら設定されてない30本以下の時代とは明らかに時代は変わっています。
これを間違いなくルール通りにジョイント名を設定できる人がいたら僕は尊敬します。
ぜひ、ジョイント命名ツールを作成するなどして、アーティストの手を煩わせずに機械的かつ自動的に命名を任せましょう。
更なるゲームのジョイントの怖い話
実は横断でデータで見られるからこそ分かる、ジョイントの更なる怖い話にジョイントの方向の問題があります。
こちらについては別の機会に伝えられたらと思います。
これから比べれば、まだまだ名前の問題は生易しいかもしれません。