2020年10月30日金曜日

5回目のランクイン

 …実は6月も狙ったのですが、最終日に490番台になって案の定逃しまして、今回はしっかり周回もしたのですよ。
そもそも、そんなにイベントを真面目にやっていなかったので資材も余っていましたしね。
そんな訳でこの「深山」。
私としては、STGの1942に居たような居ないような?くらいの印象しか無いデス。
ワンチャン、ホーネットに搭載できないかと思って試しましたがダメでした。

で、もう一つはイタリアの駆逐艦砲。
こやつの存在意義は…
コレですね。普通に良い砲ではありますが。
多分、次のイベントでマエストラーレを大量に確保しておけば、改二になる際に持ってくるんじゃないでしょうか?



2020年10月29日木曜日

Blender でアクティブ頂点グループに影響を与えるボーンを探してみる

 リギングの調整をしていて思った事。ボーン増えすぎて頂点に影響を与えているボーンがどれか判らない。
そんな訳で、先日作ったスクリプトを改造して作ってみました。
編集モードでメッシュオブジェクトの頂点編集中に起動すると影響を与えるアーマチュアのボーンが選択状態になります。
一応2.7、2.8で動作は確認しましたが、相変わらず2.8の動作は怪しいです。

これで

こうなる

コード
# serch active vg bone
import bpy
if bpy.context.mode == 'EDIT_MESH':
    for obj in bpy.context.selected_objects:
        if obj.type != 'MESH':
            continue
        
        # vg use check
        name_armature=''
        for modifier in obj.modifiers:
            if modifier.type != 'ARMATURE':
                continue
            if not(modifier.use_vertex_groups):
                continue
            name_armature = modifier.object.name
            break
        
        if not(name_armature):
            continue
        active_vg = obj.vertex_groups.active
        obj_arm = bpy.data.objects[name_armature]
        arm = obj_arm.data
        
        # search bone loop
        for bone in arm.bones:
            if bone.name == active_vg.name:
                print(bone.name)
                bone.select=True
                break

特筆するところは
obj_arm = bpy.data.objects[name_armature]

for bone in arm.bones:
以下のループ処理ですね。
前者はアーマチュアオブジェクトを取得する際にテーブルに対して、モディファイアから取得したアーマチュアの名称をキーとして直接データを呼び出しているのに対して、後者は頂点グループ名と一致するボーンをループで探しています。
前者はモディファイアにアーマチュアを登録する際に実在する事が担保されているので、直接名前で呼び出しましたが、後者は頂点グループ名とボーン名が一致する保証は無い為、わざわざ一致するボーンが出るかを検索しています。

実はこれまで掲載してきたスクリプトは、皆2.7用アドオンに仕立て直したのですが、今後は2.8向けに修正しなくてはならないです。
その上で、リギング修正もしないと次の作業には入れない…近いようで遠いですねえ。

2020年10月26日月曜日

Blender で左右化したリギング済みオブジェクトを左側のみの状態に戻してみる

 前回、リギングがひとまず終わりまして、微調整し終わったらテクスチャ描き&2.9への移行へイクゾ―…と、思ったのですが。
私は左半分のみのモデルを作ってひたすらモデリング&リギングし、仕上げ工程で左右化しています(左右化)。
…が、ふと思った訳ですよ。左右化した後で問題が見つかったらどうするのか?と。
最後に片面で編集していたファイルまで戻ってやり直すというのが素直な手だとは思うのですが、流石に面倒過ぎる。
というわけで、左右化したオブジェクトを左片面に戻すスクリプトを書いてみた…のですが、流石に難産でした。
自分でも思い出せる気がしないので、コードを掲載すると共に解説します。
尚、2.7 2.8の両方で動作を確認していますが、2.8以降の collection の概念が入っていないので、後々不具合が出るかもしれません。

これらが
こうなる

コード

# half cut

import bpy
import bmesh

if bpy.context.mode == 'OBJECT':
    for obj_arm in bpy.context.selected_objects:
        if obj_arm.type != 'ARMATURE':
            continue
            
        print(obj_arm.name)
        
        # all object loop
        for obj in bpy.data.objects:
            if obj.type != 'MESH':
                continue
            
            # vg use check
            bEfected = False
            for modifier in obj.modifiers:
                if modifier.type != 'ARMATURE':
                    continue
                if not(modifier.use_vertex_groups):
                    continue
                if obj_arm.name != modifier.object.name:
                    continue
                bEfected = True
                break
            
            if not(bEfected):
                continue
            
            # remove right vg
            for vg in obj.vertex_groups:
                name = vg.name
                if name[len(name)-2:] == '.R':
                    obj.vertex_groups.remove(vg)

            # reset seams
            for vertex in obj.data.vertices:
                if vertex.co.x == 0:
                    for group in vertex.groups:
                        vg = obj.vertex_groups[group.group]
                        name = vg.name
                        if name[len(name)-2:] == '.L':
                            weight = vg.weight(vertex.index)
                            vg.add([vertex.index],weight*2,'REPLACE')

            # remove vertex
            me = obj.data
            bm = bmesh.new()
            bm.from_mesh(me)
            
            for v in bm.verts:
                if v.co.x < 0:
                    bm.verts.remove(v)
            bm.to_mesh(me)
            bm.free()
            
        # remove right side bone & rename left side bone
        bpy.ops.object.mode_set(mode='EDIT')

        arm = obj_arm.data
        for bone in arm.bones:
            name = bone.name
            if name[len(name)-2:] == '.R':
                remove_bone = arm.edit_bones[name]
                arm.edit_bones.remove(remove_bone)
            elif name[len(name)-2:] == '.L':
                bone.name = name[0:len(name)-2]

        bpy.ops.object.mode_set(mode='OBJECT')

使用方法は「リギングに使用したアーマチュアをオブジェクトモードで選択して」実行。

まずしょっぱなですが、アーマチュアの検索ループが入ります。
当初、リギングされたメッシュオブジェクト主体で作っていたのですが、1アーマチュアに複数オブジェクトという可能性がある訳ですよ。
これまで体だけ作ってきましたが、コレに服などを着せる場合、別オブジェクトで作る可能性があるわけですからね。

  • all object loop
と、いうわけで、アーマチュア選択ループの中に全オブジェクト検索ループが入ります。
ひとまずメッシュオブジェクト以外は省きます。

  • vg use check
リギングを行ったメッシュオブジェクトか?の判別です。
使用モディファイアの内、アーマチュア属性のものを拾います。
その後、頂点グループを使用しているか?影響を与えているアーマチュアの名前が一致するか?を判定していきます。

  • remove right vg
「右側」を意味する、語尾が .R の頂点グループをひたすら削除します。

  • reset seams
ミラーモディファイアで左右化したモデルは合わせ目で左右の頂点グループの影響度(~.R ~.L に左右化した頂点グループ)を半々で受けます。
右側の影響度に関しては、一つ前の処理で右側の頂点グループそのものを削除したので影響度は無いのですが、左側は倍にセットし直す必要があります。

…のですが、コレは大ハマりしました。
当初頂点グループの影響度はこんな感じのパラメータだと思っていたんですよね。
が、実際はこんな感じ。
…頂点グループの方が主体。
最初はなんでこんな面倒くさい事になってるんだと思いましたけど、冷静に考えてみると判りますね。
頂点は物体を示す最小単位な訳です、当然、立体に関わるパラメータは全て頂点にも紐づけられます。
私でも判る範囲で考えるなら、テクスチャUV、頂点法線、頂点カラー…
当初の私の予想通りだと、機能追加する度に頂点の処理を追加していく事になって頂点処理担当が忙殺される事は間違いないです。
なので、追加した機能の方で極力完結する後者のような設計になったんでしょうね。

…で、そっちの設計思想は理解するのですが、もう一つ
vg.add([vertex.index],weight*2,'REPLACE')
…コレは酷い
これは頂点に対する加重値を2倍にしているのですが…
値の変更の関数は普通 set だろうに、なぜ add 関数にパラメータで REPLACE にしておけばおkとか言ういい加減な作りにしたのか。
なんでこんな不可解なネーミングを許したのかまったく理解できませんでした。

  • remove vertex
オブジェクトから右側の頂点を全削除する処理なのですが…
一つ前の処理で
for vertex in obj.data.vertices:
と書いており、obj.data.vertices の中から右側の頂点だけ削除すれば良いじゃないかと当初は思っていました。
が、コレは動作しません。
obj.data の内容を一旦 BMesh に書き写してから BMesh 上で右側の頂点を削除して書き戻す必要があります。
正直、どうしてこんな処理になっているのかは解りませんが、作法だと思う事にしました。

  • remove right side bone & rename left side bone
最後は右サイドのボーンを削除し、左サイドのボーンをリネーム(~.L から .L の無い名前に変更)する処理。
特筆する部分もあまり無いのですが、ボーンの削除は編集モードでないとできない為、処理の最初に編集モードにセットし、最後にオブジェクトモードに戻しています。
尚、左側のボーンを変名した為、関連して頂点グループ名の ~.L だったものも変名されます。
この為、ボーン変名の前に影響を受ける全メッシュオブジェクトの処理を終えておく必要があります。


いや、難産でしたし、どうしてこんなに面倒くさい作りになってるんだろう?と何度も悩みましたが…
最初にスクリプトを書いたときはコードを書いていて吐き気がする程でしたが、今回は設計思想や開発陣の配置など内部的な事が薄っすら見えてそれなりに楽しめました。
次のステップへの弾みになると良いのですが。

2020年10月14日水曜日

脚部のリギング

 前回腕の捻りを作りまして、その際に「捻る」動作のリギング法が判ったので、ふとももに応用する事になったのですが…。
気付けば大腿部からつま先まで全てに修正を入れる事になりました…

  • 太腿
先ずはボーン数の比較
before

after


はい、別物ですね。むしろ以前のボーンは良くあんな少数で破綻しなかったなと思います。
で、これを動かしてみる。


開脚時に一定以上の角度を開脚すると腰の外側に周辺の肉を引き込むようにボーンを組んだのですが…少し不自然かも。
ただ、こうしないとシルエットが崩れるんですよねえ。


レッグカールをさせていますが、本来は踵がお尻に付かない想定です。上腕筋が付きすぎると自分の肩が掴めなくなるように、ハムストリングを鍛えすぎるとお尻に踵がつきません。
ただ、正座のようにむりやり膝の靭帯を伸ばせば付くので、この曲げ方は限界よりやや曲がっています。

このため、ややきついポリゴンの干渉がありますが、スルーしています。
ひかがみ(内膝)は膝が伸びた状態だと両端の腱より間の肉が浮きますが、コレは上下の骨の接合部が内側から肉を押し上げているかららしいです。
ただ、形状(というか動き方)が特殊なので曲げると見た目上へこむのですが…この動きは膝の曲げに対して係数をとる為のストレッチボーンを作り、これの伸縮をコピーする形で制御ボーンを作っていきました。
完全に膝が曲がるとふくらはぎが潰れますが、これは膝の曲げから係数をとってふくらはぎ等のボーンを稼働させているだけで、セルフコリジョンなどは一切していません。
やり方は以前記述しています。

  • 足首
以前は角度決め打ちでしたが、今回から目標ボーンを追従する形にしました。
何年か前に適当に作ったアキレス腱関係を改善していますが…手首や足首はリストバンド状の筋膜があって、複数の筋腱を束ねています。
これのお陰で動かしても形をある程度保っているのですが…リギングでバカ正直にボーンに割り付けると動かしたボーンにつられて変形し、型崩れを起こします。
このため、アキレス腱をふくらはぎ側と踵側に分け、接点を足首の曲角度に合わせてずらすようにボーンを組みました。

又、足首を内側に曲げると連動で親指が浮き、外側に曲げると小指が浮く(つまり捻られる)ようにしました。
足首の上下曲げは任意にできますけど、捻りはできないですからね。
本当は地面の平行面に合わせて、足の裏の角度を調整する処理を作ろうかと考えましたが辞めました。
地面が常に平行とは限らないですし、都度変えた方が良いかなと。

  • つま先

親指の付け根の関節だけ目標ボーンを追従する形をとっています。
そして、目標ボーンの拡縮を行うと親指の先端の拡縮ボーンが伸縮し、その伸縮に親指の指先が連動する形で曲がります。


又、親指以外のボーンはもっと顕著で、付け根、先端用の2本の指揮ボーンの拡縮に合わせて、指4本が連動するため、2本のボーンで4本の指の開閉を行っています。


拡縮ボーンを使って指を曲げるという処理は、かなり昔トニーマレン著の教書に載っていた気がするのですが…IKでやっていたのでしたっけ?
※追記 多分、トニーマレン著『3Dキャラクターアニメーション Blender 』です
既に今年の頭に教書を大量処分したので確認できませんが、足の指程度ならこういうざっくりとした処理でも良いかなと思いました。

今後は、一旦顔の作りを顎の骨だけ実装しつつ顔無し状態に戻し、微調整後に顔の作成に入りたいですね。
顔は、多ノードレンダリング前提で、なおかつトゥーン調を目指す為、全く別次元の技術が必要になっていきそうです。
やる事が変わる節目ですので、2.79から一気に2.9系に移行する予定です。
あと、多ノード処理はもう10年近くやっていないので、又勉強のやり直しです…先は長いなあ。

2020年10月5日月曜日

最新の Linux Mint で旧 Blender を標準に使う

 …お前は何を言っているんだ。と思われそうですが。
Linux Mint の標準ツールで Blender をダウンロードすると当然安定板の最新版が落ちてきますが…お察しの通り、私は未だに 2.79b を使っています。
慣れない操作でリギングしたくないからで、テクスチャ描きに移行したタイミングで 2.8 に変えたい、というかもう 2.9 がリリースされている。
流石に Mint20 もリリースされて半年経ちましたし、リリースされていない32ビット機ならともかく、64ビット機で使用しない訳にはいかない。なにより Mint20 にしていない関係で Geany 上の Python3 の挙動が怪しい。
…という訳で、先日メインのノートを Mint20 に移行しましてレガシーな Blender を使うのですが…

コレはひとまず Blender のダウンロードページから Previous Versions を選べば、凍結された旧バージョンの Blender 一式を落としてこれまして。

助かる事に展開してできたディレクトリの Bleder をクリックするだけで、ライブラリの依存関係を考えずに起動してくれます。


じゃあコレを .blend の標準起動アプリに設定すれば良いわけなんですけど、当然インストーラを経ていないので候補に挙がりません。

ひとまず、展開したディレクトリ名が長いので短くし、適当なディレクトリに移動し、ターミナルでコマンドで起動。
※例では、home のユーザーディレクトリに移動させ、展開したディレクトリ名を blender-2.79b に変名している

コマンドでの起動を確認したら、起動コマンドをコピーしまして。
これを~アプリケーションとして記憶するにチェックをし、「コマンドを直接指定する」に登録。

これにて無事 2.79b が標準で起動するようになります。
…いや、当然だろ?って言われそうなんですけど、当初リポジトリから旧バージョンを引っ張ってきてライブラリの互換性に問題が起きて…ってな事を繰り返していまして。
難しく考え過ぎたな、という反省を込めての忘備録です。