挿絵画家になろう(その10)


「挿絵画家になろう(その10)」です。
これまでBlenderのアドオン、MB-Labの啓蒙として記事を連ねてきました。
MB-Labを使って秀逸な少女キャラクターのメッシュオブジェクトを生成し、VRoidStudioの髪をインポートして装着させ、そこそこの服を着せ、キャラクターのマテリアルも弄れるようになり、表情も変更できるようになり、同梱のポーズを組み合わせて新しいポーズも作れるようになりました。

今回は前回に引き続き、襟付きのワンピースを作ります。
今回はキャラクターの体のメッシュを利用して服を作成します。

Anime_female(F_AN02)でキャラクターを生成します。

服のベースはdefaultのキャラクターから作ります。
ポーズをt-poseにします。

t-poseにするのは服の作りやすさからです。
最終的なシルエットの美しさはa-poseから作ったほうが良いのですが、腕や足の角度があるので細かな修正が難しくなるのです。

あとはdefaultのままFinalizeするのですが、接頭語だけは分かりやすい名前を指定します。
ここではmannequin_gilr_1としておきます。

このキャラクターのメッシュの一部を素材として加工することにより服を作ります。
ただしMB-Labで生成したメッシュには各種のmodifierが適用されていて、メッシュ流用時に悪影響が出ます。
Modifierの影響を外す方法はいくつかあるのですが、ここでは簡便に一旦Waveフォーマットでエクスポートすることとします。
Obj形式は複雑なエフェクト類が一切無いのでModifierの影響が全てなくなります。

適当な名前を付けてエクスポートします。
ここではmannequingirl1.objとしておきます。
必ず「選択物のみ」にチェックを入れます。
これを忘れるとカメラやランプなどの余計なものが混入します。

Objファイルのエクスポート後、このBlenderプロジェクトはしばらく使わないので保存しておきます。
ここではmannequin_girl_1_base.blendとしておきます。

mannequin_girl_1_base.blendは暫く使わないので閉じてしまって構いません。

Blenderで新規のプロジェクトを開きます。
そして mannequingirl1.obj をインポートします。

単なるメッシュオブジェクトとしての mannequin_girl_1_body_MBLab_anime_femaleが読み込まれます。

このメッシュオブジェクトを素材にしていくわけです。
メッシュオブジェクトを目的に応じてコピーします。
目的とは原型ベース、メッシュ間引き用、ワーク用等です。

一つは原型ベースとして確保しておきます。
プロパティシェルフの[レンダーレイヤー]ボタン(二枚の重なった書類のボタン)を押下します。

オブジェクトモードになっていることを確認して mannequin_girl_1_body_MBLab_anime_female を右クリックで選択します。
[shift+d]キーを押して mannequin_girl_1_body_MBLab_anime_female をコピーします。
マウスを動かすとコピーされていることがわかります。

[esc]キーを押すと移動がキャンセルされます。
この状態ではコピーした方の mannequin_girl_1_body_MBLab_anime_female.001が選択されています。
[m]キーを押すとレイヤーの移動となります。

左上の枠がdefaultのレイヤなのでそれ以外の枠を選択します。
ここでは上段左から5番目のレイヤを選択します。
プロパティシェルフの[オブジェクト]で mannequin_girl_1_body_MBLab_anime_female.001 をmaterial_baseにリネームしておきます。

material_base を編集します。
5番目のレイヤ、編集モードであることを確認します。
3Dビューのシェーディングはソリッドとします。
服の素材として不要な部分を消していきます。
先ずは首から上。
首の一部分を[alt]キーを押しながら右クリックでラインの選択を行います。

頂点を削除します。

首から上が分離します。
首から上のメッシュにマウスオーバーさせて[l]キーを押下して選択していきます。

歯茎や舌のメッシュが残りますが同様に削除していきます。

首から上が消えたら、次は体の半分を消します。
意図はミラーモデファイアで左右対称にするためです。
ちなみにdefaultのメッシュは意外なことに左右対称ではありません。

ライン選択→頂点の削除→メッシュの選択→頂点の削除で右半分を削除します。

どんどん消します。
なんか楽しくなってきます。

黒いマテリアルだと作業しにくいので適当な色に変えます。

現状のメッシュは目が細かすぎるので間引きます。
具体的な作業としては一本置きにライン選択をして「削除」→「辺の溶解」を行います。

これで素材ベースとしてはいい感じになりました。
ミラーモデファイアを適用します。
オブジェクトモードに戻り、プロパティシェルフのモデファイア―からミラーを選択します。

XをチェックしてX軸で左右対称にします。

このまま「適用」ボタンをクリックして適用します。

プロパティシェルフのレンダーレイヤ―を選択し、レイヤーのシーンで1番目のレイヤを重ねます。
([shift]キーを押しながら左クリックすると複数のレイヤを選択できます。)

素材ベースはメッシュを間引いているのでオリジナルより若干小さくなっています。
素材ベースを体より大きくするために法線方向に拡大します。
material_baseオブジェクトが選択されていることを確認してから編集モードに切り替えます。
オブジェクトにマウスオーバーさせて[a]キーを押して全選択します。

[alt+s]キーを押し法線方向への拡大とし、[↓]を三回ほど押します。

膨らみました。
ギリギリを狙うよりは体から明確に服が離れる程度にするほうが良いと思います。

ここからはメッシュを変形させていきます。
テンキーの[3]キーを押して真横からのビューにします。

この先の作業は基本的に一番下のラインを[e]キーで延長、拡大、回転で調整しながら下に伸ばしていきます。

上半身側の一番下のラインを[alt]キーを押しながら右クリックして選択します。

[e]キー→[z]キーを順番に押し、[下]キーを押して服を下に伸ばします。

基本、[e]キーには[z]を組み合わせて下へだけ延長、[s]キーや[g]キーも[x][y][z]と組み合わせて方向を管理してゆきます。
正直ここは経験が要りますが、そんなに難しくはありません。
後でモデファイア―をかけますのでシルエットを整えることに専念します。

とりあえず以下のように変形させました。

イメージとしては体の線を強調させすぎず、スカートがやや広がるワンピースです。

襟もつけましょう。
首の一番上の線を選択し、[e]キー、[s]キーを順番に押してマウスで広げます。

適当な大きさに広がったら[enter]キーで確定させます。
辺ループカットで適当なサイズに分割します。

襟の前部分のメッシュを削除します。

袖も加工します。
両手分の袖を同時に作りたいので再度半分を消し、ミラーモデファイア―を適用します。

袖を作ります。

襟を整え、ミラーモデファイアを適用します。

次にUVマップ用のシームを付けていきます。
シームとはUVマップ展開したときに島として分離したい境界線です。
ワンピースのデザインとして、前回に合わせて襟と袖口は白、その他は紫ということにしましょう。
シームを付けたい線を選択します。
ある程度部分に分けないと[スマートUV展開]で微少な島が量産されてしまい苦労します。

[ctrl+e]キーを押して辺のメニューを出し、[シームを付ける]をクリックします。
シームを付けた所が赤い線になります。

[a]キーで全選択して[u]キーを押下し、UVメニューを出します。
[スマートUV展開]をクリックします。
[島の余白]は0.01(1cm)程度にします。

UV画像エディターでUVを確認します。

新規画像は全面黒かと思います。
UVマップには一見どこの部位か分からないほど細かく島が生成されています。
服の造形がテキトウであるため、エッジが多く、分割されてしまうのです。
これを避けるにはスムースな造形を心掛ける必要があります。
しかしそれは「簡単に早く作る」という造形意図に反するので悩ましいところです。

複雑なUVマップなので、単純にいくつかの色を塗るだけならまだ良いのですが、縞模様の服を作りたい場合などは苦労することでしょう。

UVマップ用の新規画像を開き、とりあえず[onepiece]と名前をつけます。
全体を紫で埋めたのち、袖と襟を白く塗ります。

マテリアルの設定で、[onepiece]の画像を割り当てます。

色が反映されます。

後はクロスモデファイアを適用します。

mannequin_girl1_MBLab_anime_femalにコリジョンモデファイアをかけます。

onepieceのほうにクロスモデファイアをかけます。

仕上がりは以下のような感じです。

ライティングが悪いのでマネキンではなく、デフォルトキャラクターに着せてみましょう。

胸の形など、必要以上にはボディラインが強調されず、でも体形に沿った綺麗なシルエットになっています。
これは縫合スプリングが前後左右への締め付けが発生するのに対して、重力による布の落下しかないためです。

縫合スプリングを用いる方法より、こちらの方法の方が シルエットをコントロールするのが圧倒的に楽です。
襟の形も、少々の風や乱流があっても然程は乱れません。
襟足の高いデザインでもある程度はコントロール可能です。
服の造形はシルエットを制御する程度のクオリティで良く、後はクロスモデファイアがいい感じに整形してくれてしまいます。

以上の作業ですが、慣れると一着三十分程度で行えます。
途中までの成果物があればキャラクターごとに流用可能なので、シルエットの直しや、襟の形の直し等であればさらに短時間で新しい服を生成可能です。

デメリットは以下。
・UVマップの島が複雑。
・キャラクターごとに作りなおす必要がある。
・メッシュのライセンスを考慮する必要がある。

MB-Labのメッシュを流用するので、当然ライセンスに関してはMB-Labのライセンスの影響を受けると考えたほうがよいでしょう。
服を配布したい場合や3Dゲーム等に使う場合はMB-Labのライセンス条項に従うべきかと。

以上前回と今回で、アプローチの違う二つの方法で、ほぼ同じ形状の襟付き長袖ワンピースを作成しました。
どちらにもメリット・デメリット、得意・不得意があることがお分かり頂けたかと存じます。
どちらが正解というものでもなく、組み合わせていけばよいのだと思います
とはいえ、もっと簡単な方法はないものかと……。

と、いうことで今回は終わりです。
時間があれば[その11]を書きたいと思います。


挿絵画家になろう(その9)


「挿絵画家になろう(その9)」です。
これまでBlenderのアドオン、MB-Labの啓蒙として記事を連ねてきました。
MB-Labを使って秀逸な少女キャラクターのメッシュオブジェクトを生成し、VRoidStudioの髪をインポートして装着させ、そこそこの服を着せ、キャラクターのマテリアルも弄れるようになり、表情も変更できるようになり、同梱のポーズを組み合わせて新しいポーズも作れるようになりました。

で、やはりネックは服なんですよね。
その2」でネット上の情報をもとに縫合スプリング機能を使って簡易的な袖なしTシャツを作る方法を紹介しました。
また「その4」ではワンピースを作る方法を紹介しました。
でも襟は無いし、半そでだしで多分これだけでは満足できないですよね?

私としても服を自由に、そして簡単に作る方法を模索し続けているのです。
でも、無料の良いソリューションを見つけることができていません。
もしご存じの方がいらっしゃったら是非ぜひお教えください。

縫合スプリングを使う方法は、私自身、あまり良い方法とは思っていません。
Tシャツなどの簡単なものならば良いのです。
しかしやってみると分かるのですが、少しでも凝ろうとすると難易度が跳ね上がっていきます。

私も縫合スプリングを知った当初は、実際のドレスシャツの型紙から各パーツを作れば良い、なんて考えていました。
しかしパーツの数が増えると、縫合線を結ぶ事自体が難しくなります。
襟や袖を離れたところから縫合しようとすると移動の途中で変形してしまい、もとの形状が失われてしまいます。
綺麗に縫合するには変形後の形状を合わせる必要があり、複雑な形にするにはかなりの研究が必要です。

実際の縫製用型紙を作るのも難しいのでしょうが、縫合スプリングではまた別の難しさがあるのだと思います。

縫合スプリングで複雑な服を作るには、それはそれで深く険しい道なのだと思います。

それでも、単純な形状ではそれっぽい服を作成できるのが縫合スプリングの良さだと思います。
今回と次回で、同じような襟付きの長袖ワンピースを別の方法で作成していき、差を見ていきたいと思います。

ということで今回は縫合スプリングを使った方法です。
変形前の素材を以下に置いておきます。
clothe_onepiece_spring_mat.zip

この素材はMB-LabのAnime_Female(F_AN02)のデフォルトキャラクターに合わせて作成しました。
ZIPファイルには以下のファイルが梱包されています。
clothe_onepiece_spring_mat.obj
clothe_onepiece_spring_mat.mtl
onepiece_txt.png

MB-Labで適当なキャラクターを生成して後にインポートしてください。
次のアニメーションのように首に丸い輪っかを通すようにして全体を整えます。

マテリアルの設定は以下のようにします。

UVマップが非常にシンプルです。
縫合スプリングで服を作成する場合、元の形状が平面であるため、[スマートUV投影]でもほぼメッシュ通りの分かりやすいUVマップとなります。
色を塗るにしても、柄を書き入れるにしても非常に便利です。
これはスプリング縫合方式のメリットの一つです。

さて、パラメータにもよりますが、仕上がりは以下のようになります。

クロスモデファイアを使う場合、通常では[クロスフィールドの重み]をデフォルトにしておくと、いい感じに乱れます。
この乱れがリアルな皺を作ったり、縫合を徐々に密なものにしてくれたりしているわけです。
しかし、襟がある場合は少しの乱れでも大きく暴れてしまい、意図した所に収まらなくなります。
許容できないので、[重力]、[全て]、[力]、[空気抵抗]のみ1にして、他は0にします。
その他、[クロス]の[空気抵抗]も0にします。
このように、小さなパーツを含む場合は、気を付けなければならない所が多くなります。

風等の乱れがまったくないため、クロスモデファイアをかけ続けても、変化は少ないです。
縫合もあまりきちっとはされません。
縫合しきれなかった部分が筋となって、地肌が見えてしまっています。
これは手動で縫うか、レンダリング画像を2Dペイントツールで補正すれば良いでしょう。

いかがでしょうか?
複雑さとシンプルさの微妙なバランスに苦心しました。

正直な話、襟の造形のために他の部分を犠牲にしている感があります。
襟を含めて一度で造形するより、襟なしで一旦クロスモデファイアをかけたあとに、改めて襟を作りこんだほうが良いかと思います。

今回の作例では襟のメッシュは以下のようになっています。

この円形の襟の部分を変更すれば別の襟にすることが(理屈上)できます。
とは言え、スプリングによって引っ張られてしまい、完成後の造形予想は難しいものがあります。
特に襟足の高い造形は非常に難しいです。

ワンピースをマリアに適用してみました。
デフォルトのキャラクターと体形が違いすぎて、素直には適用できません。
同じ比率では首が太すぎ、かつ短すぎでBodyに干渉してしまいます。
首が乗っている四角形の外枠の形を変えないよう気を付けながら、ワンピースの首を太く、短くしてBodyと干渉しないように変形させて適用しています。

結局、同じ服をグラマーな大人キャラクター、スレンダーな子供キャラクタ―で共有するのは、色々難しい課題があります。
スレンダーボディに合わせると、必要以上にボディラインが強調された服になってしまいます。
グラマーボディに合わせると、胸が余った服になってしまいます。
結局はキャラクターごとに服をワンメイクで作る必要があるのでしょうか?
それでも縫合スプリングは元のメッシュが単純なため、ターゲットに合わせこむ手数は少なくて済みます。

と、いうことで今回は終わりです。
時間があれば[その10]を書きたいと思います。


ツールの話をしよう~コマンドライン翻訳


このブログを見てらっしゃる方はtwitterのFFの方がメインであろうかと思います。
つまりは小説関連のご同胞ですよね?
皆さん、翻訳・辞書ツールを使っていらっしゃると思います。
今回は私が使っている Windows10 PC上でのコマンドラインで動作する翻訳・辞書ツールをご紹介しようと思います。

その名もtranslate-shellです。
soimort/translate-shell: Command-line translator … – GitHub

このツールはコマンドラインからgoogle翻訳等のWEBアプリを使って、翻訳したり辞書をひいたりしてくれる超便利なソフトです。
小説の執筆をしているときに、ちょっと「この英単語、どういう意味だっけ?」とか、「英語タイトルなんにしよう?」とか思うことありますよね。
それでいちいちChromeを立ち上げてgoogle翻訳を開くってめんどくさいですよね?
そんなとき、コマンドラインからバシャバシャっと入力して辞書を引いたり翻訳できたら便利だと思いません?
私はすごく思います。

例えば和英翻訳ならばこんな感じ。

kuyo@DESKTOP-8O0L9BP:~$ je '腹が減った'
腹が減った
(Haragahetta)

I am hungry

Translations of 腹が減った
[ 日本語 -> English ]

腹が減った
    I am hungry, hungry
kuyo@DESKTOP-8O0L9BP:~$

例えば英和翻訳ならばこんな感じ。

kuyo@DESKTOP-8O0L9BP:~$ ej 'Never let me go'
Never let me go

私を離さないで
(Watashi o hanasanaide)

Translations of Never let me go
[ English -> 日本語 ]

Never let me go
    私を離さないで, 私を手放すことはありません, 私は手放すことはありません
kuyo@DESKTOP-8O0L9BP:~$

例えば和英辞書ならばこんな感じ。

kuyo@DESKTOP-8O0L9BP:~$ je -d 'きょうだい'
きょうだい
(Kyō dai)

Siblings

Translations of きょうだい
[ 日本語 -> English ]
kuyo@DESKTOP-8O0L9BP:~$

例えば英和辞書ならこんな感じ。

kuyo@DESKTOP-8O0L9BP:~$ ej 'Sibling'
Sibling
/ˈsibliNG/

兄弟姉妹
(Keiteishimai)

Translations of Sibling
[ English -> 日本語 ]

Sibling
    兄弟姉妹, 兄弟
kuyo@DESKTOP-8O0L9BP:~$

英英辞書的にも使えます。

kuyo@DESKTOP-8O0L9BP:~$ ej -d 'love'
love
/ləv/

愛
(Ai)

Definitions of love
[ English -> 日本語 ]

verb
    feel a deep romantic or sexual attachment to (someone).
        - "Though you tried to deny it, you must trust your heart that deep inside you love him."
    Synonyms: care very much for, feel deep affection for, hold very dear, adore, think the world of, be devoted to, dote on, idolize, worship, be in love with, be infatuated with, be smitten with, be besotted with, be mad/crazy/nuts/wild about, have a crush on, carry a torch for

noun
    an intense feeling of deep affection.
        - "My brother, and his real, strong love for me that was able to pull me back into the world I know."
    Synonyms: deep affection, fondness, tenderness, warmth, intimacy, attachment, endearment, devotion, adoration, doting, idolization, worship, passion, ardor, desire, lust, yearning, infatuation, besottedness

    a person or thing that one loves.
        - "By the end of the trip I knew she had two loves ; her son and her carpets."
    Synonyms: beloved, loved one, love of one's life, dear, dearest, dear one, darling, sweetheart, sweet, angel, honey, lover, inamorato, inamorata, amour, paramour

    (in tennis, squash, and some other sports) a score of zero; nil.
        - "To come back from two sets to love and win it is an awesome feeling."

Synonyms
    verb
        - care very much for, feel deep affection for, hold very dear, adore, think the world of, be devoted to, dote on, idolize, worship, be in love with, be infatuated with, be smitten with, be besotted with, be mad/crazy/nuts/wild about, have a crush on, carry a torch for
        - like very much, delight in, enjoy greatly, have a passion for, take great pleasure in, derive great pleasure from, relish, savor, have a weakness for, be partial to, have a soft spot for, have a taste for, be taken with, get a kick out of, have a thing about, be mad/crazy/nuts/wild about, be hooked on, get off on
        - enjoy
        - have intercourse, eff, hump, get laid, make out, have sex, do it, fuck, bed, make love, jazz, sleep together, bang, screw, bonk, be intimate, know, lie with, have it off, sleep with

    noun
        - relationship, love affair, romance, liaison, affair of the heart, amour
        - beloved, loved one, love of one's life, dear, dearest, dear one, darling, sweetheart, sweet, angel, honey, lover, inamorato, inamorata, amour, paramour
        - best wishes, regards, good wishes, greetings, kind/kindest regards
        - liking of/for, enjoyment of, appreciation of/for, taste for, delight for/in, relish of, passion for, zeal for, appetite for, zest for, enthusiasm for, keenness for, fondness for, soft spot for, weakness for, bent for, proclivity for, inclination for, disposition for, partiality for, predilection for, penchant for
        - compassion, care, caring, regard, solicitude, concern, friendliness, friendship, kindness, charity, goodwill, sympathy, kindliness, altruism, unselfishness, philanthropy, benevolence, fellow feeling, humanity
        - deep affection, fondness, tenderness, warmth, intimacy, attachment, endearment, devotion, adoration, doting, idolization, worship, passion, ardor, desire, lust, yearning, infatuation, besottedness
        - love life, lovemaking, making love, sexual love
        - passion
        - dear, dearest, beloved, honey
        - sexual love

Examples
    - In short, how can there be love for the country without love for the people?

    - they were both in love with her

    - babies fill parents with intense feelings of love

    - Ian drinks his coffee and talks enthusiastically about his love of singing.

    - people who love democracy

    - I guess Michael and I were trying to find a way to express our brotherly love for one another.

    - So passionate is my love of opera, that I crave any activity that extends my time in the Arts Centre.

    - Years later he has combined his love for zoology with his appreciation of the female form.

    - She dwells on her charming manner, love of clothes, loyalty to her brother and, in later life, to her adoptive city.

    - you're such a love!

    - "Emily, my dear," said the spinster aunt, with a patronising air, "don't talk so loud, love."

    - You did that? I love it!

    - He lost his ambition and forgot everything but his love for this unworthy woman.

    - Brotherly love comes at a price, it seems.

    - He truly did love her, and deep down he knew his family would too, but he was still nervous.

    - All the very very best to you Tom, and lots of love from Charlie.

    - I had a great interest and love of music, and music was always a part of the family, but no one had ever pursued it.

    - Looking forward to seeing you soon, Lots of love, Grannie

    - We also send our best love to you and the children all wish that they were going on the same ship as their Father.

    - Each one is very powerful, but none of them is as strong as your love for your daughter.

    - do you love me?

    - We have always happy together and our love for each other has been strong and growing for sometime now.

    - we share a love of music

    - Try falling in love with someone who is from a different country and speaks a different language.

    - She did not overtly try to attract Edgar, but he was still falling in love with her.

    - My love for her was as strong as ever, as it is now, at this very moment.

    - I'd love a cup of tea

    - It's alright my love you are safe with me.

    - I had to try to put my intense passionate love for him to the side and be his friend.

    - their love for their country
kuyo@DESKTOP-8O0L9BP:~$

どうですか?
便利でしょう?
これはLinuxのShellとかで動作するコマンドなのですが、Windows10にインストールすることも可能です。
ただ、多少手順がめんどくさいので順を追って説明しますね。

Windows10上のコマンドラインと言ってもDOS窓でもなければ、PowerShellでもありません。
WSLです。

WSLはWindows Subsystem for Linuxの略で、マイクロソフトが提供する、Windows10上で動作するLinuxなんですね。
コマンドライン上でLinuxの様々なツールが使えてしまうというスグレモノです。

先ずはWSLのインストールから始めます。
WHLのインストールのために、まずWHLを許可します。
コントロールパネルを開きます。

[プログラム]をクリックします。

[プログラムと機能]をクリックします。

左ペインにある[Windowsの機能の有効化または無効化]をクリックします。

リストの下のほうにある[Windows Subsystem for Linux]のチェックを入れて[OK]をクリックします。

暫く待つと完了します。

PCの再起動を求められるので再起動します。

スタートメニューから[Microsoft Store]を起動します。

検索から[WSL]を探します。

LinuxのDistributionを選びます。
特に好みが無ければUbuntuが良いでしょう。

[入手]をクリック。
インストールされます。

[起動]をクリックするとWSLのコマンドラインが開きます。

暫く待つとuser nameを聞いてきます。

ここで自分の作成したいuser nameを入力します。
私はkuyoにしました。

次にuserのpasswordを聞いてきます。
ローカルの話なので適当に覚えやすいpasswordを設定します。

確認のためにもう一度passwordを入力します。

これでWSLのインストールはおしまいです。
Windows上に仮想的なLinuxが立ち上がったことになります。
しかもUbuntuですからaptで欲しいツールを簡単にインストールすることができます。

ちなみにこのLInux環境のrootディレクトリは以下になります。

C:\Users\%USERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\

kuyoのhomeは以下ですね。

C:\Users\%USERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home\kuyo

ではWSLのコマンドターミナルから必要なツールをインストールします。
先ずはaptのupdate。

kuyo@DESKTOP-8O0L9BP:~$ sudo apt update
[sudo] password for kuyo:

passwordを聞いてくるので先ほど設定したものを入力します。

導入にはいくつかのツールが必要です。
具体的にはgit, gawk, makeが必要なのでインストールします。

kuyo@DESKTOP-8O0L9BP:~$ sudo apt install git
kuyo@DESKTOP-8O0L9BP:~$ sudo apt install gawk

gitとgawkが必要ですが既に最新のものが入っていました。
makeもインストールします。

kuyo@DESKTOP-8O0L9BP:~$ sudo apt install make
kuyo@DESKTOP-8O0L9BP:~$ sudo apt install make-guile

途中”Do you want to continue? [Y/n] Y”と聞いてきますのでyと[enter]キーを押します。
ネットへの接続が必要です。

次にtranslate-shellをダウンロードします。

kuyo@DESKTOP-8O0L9BP:~$ git clone https://github.com/soimort/translate-shell

ディレクトリを移動します。

kuyo@DESKTOP-8O0L9BP:~$ cd translate-shell

makeしてinstallします。

kuyo@DESKTOP-8O0L9BP:~/translate-shell$ make
[OK] Task build completed.
kuyo@DESKTOP-8O0L9BP:~/translate-shell$ sudo make install
[OK] Task build completed.
[OK] translate-shell installed.
kuyo@DESKTOP-8O0L9BP:~/translate-shell$

以上でインストールはおしまいです。
transというコマンドがインストールされました。
使い方は以下で分かります。

kuyo@DESKTOP-8O0L9BP:~$ trans --help
Usage:  trans [OPTIONS] [SOURCES]:[TARGETS] [TEXT]...

Information options:
    -V, -version
        Print version and exit.
    -H, -help
        Print help message and exit.
    -M, -man
        Show man page and exit.
    -T, -reference
        Print reference table of languages and exit.
    -R, -reference-english
        Print reference table of languages (in English names) and exit.
    -L CODES, -list CODES
        Print details of languages and exit.
    -S, -list-engines
        List available translation engines and exit.
    -U, -upgrade
        Check for upgrade of this program.

Translator options:
    -e ENGINE, -engine ENGINE
        Specify the translation engine to use.

Display options:
    -verbose
        Verbose mode. (default)
    -b, -brief
        Brief mode.
    -d, -dictionary
        Dictionary mode.
    -identify
        Language identification.
    -show-original Y/n
        Show original text or not.
    -show-original-phonetics Y/n
        Show phonetic notation of original text or not.
    -show-translation Y/n
        Show translation or not.
    -show-translation-phonetics Y/n
        Show phonetic notation of translation or not.
    -show-prompt-message Y/n
        Show prompt message or not.
    -show-languages Y/n
        Show source and target languages or not.
    -show-original-dictionary y/N
        Show dictionary entry of original text or not.
    -show-dictionary Y/n
        Show dictionary entry of translation or not.
    -show-alternatives Y/n
        Show alternative translations or not.
    -w NUM, -width NUM
        Specify the screen width for padding.
    -indent NUM
        Specify the size of indent (number of spaces).
    -theme FILENAME
        Specify the theme to use.
    -no-theme
        Do not use any other theme than default.
    -no-ansi
        Do not use ANSI escape codes.
    -no-autocorrect
        Do not autocorrect. (if defaulted by the translation engine)
    -no-bidi
        Do not convert bidirectional texts.
    -bidi
        Always convert bidirectional texts.
    -no-warn
        Do not write warning messages to stderr.
    -dump
        Print raw API response instead.

Audio options:
    -p, -play
        Listen to the translation.
    -speak
        Listen to the original text.
    -n VOICE, -narrator VOICE
        Specify the narrator, and listen to the translation.
    -player PROGRAM
        Specify the audio player to use, and listen to the translation.
    -no-play
        Do not listen to the translation.
    -no-translate
        Do not translate anything when using -speak.
    -download-audio
        Download the audio to the current directory.
    -download-audio-as FILENAME
        Download the audio to the specified file.

Terminal paging and browsing options:
    -v, -view
        View the translation in a terminal pager.
    -pager PROGRAM
        Specify the terminal pager to use, and view the translation.
    -no-view, -no-pager
        Do not view the translation in a terminal pager.
    -browser PROGRAM
        Specify the web browser to use.
    -no-browser
        Do not open the web browser.

Networking options:
    -x HOST:PORT, -proxy HOST:PORT
        Use HTTP proxy on given port.
    -u STRING, -user-agent STRING
        Specify the User-Agent to identify as.
    -4, -ipv4, -inet4-only
        Connect only to IPv4 addresses.
    -6, -ipv6, -inet6-only
        Connect only to IPv6 addresses.

Interactive shell options:
    -I, -interactive, -shell
        Start an interactive shell.
    -E, -emacs
        Start the GNU Emacs front-end for an interactive shell.
    -no-rlwrap
        Do not invoke rlwrap when starting an interactive shell.

I/O options:
    -i FILENAME, -input FILENAME
        Specify the input file.
    -o FILENAME, -output FILENAME
        Specify the output file.

Language preference options:
    -l CODE, -hl CODE, -lang CODE
        Specify your home language.
    -s CODES, -sl CODES, -source CODES, -from CODES
        Specify the source language(s), joined by '+'.
    -t CODES, -tl CODES, -target CODES, -to CODES
        Specify the target language(s), joined by '+'.

Text preprocessing options:
    -j, -join-sentence
        Treat all arguments as one single sentence.

Other options:
    -no-init
        Do not load any initialization script.

See the man page trans(1) for more information.
kuyo@DESKTOP-8O0L9BP:~$

ただしこのままでは使いにくいので ~/.bashrc に以下の二行を付け加えます。

alias ej="trans -sl=en -tl=ja"
alias je="trans -sl=ja -tl=en"

テキストエディッタはnanoというものが標準でインストールされているのでそれを使います。
もちろんvimをインストールするのでも良いし、以下のファイルをWindowsのテキストエディッタで直接編集するのでも構いません。

C:\Users\%USERNAME%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home\kuyo\.bashrc

編集できましたら一度exitコマンドで抜けます。

kuyo@DESKTOP-8O0L9BP:~$ exit   

再度の起動はスタートメニューから行えます。
Ubuntuならば以下のようなアプリが増えています。

いかがでしょうか?
手順は多いのですが、意外と簡単にインストールすることができました。
これで快適な執筆ライフがおくれますね。

WSLは単にtranslate-shellのためだけではなく、様々なツールを使うことができます。
例えば電卓。
bcというコマンドがあります。
これはコマンドラインで計算ができるというスグレモノです。

小説を執筆しているときに距離だとか時間の確認に電卓が欲しい場合がありますが、これもコマンドラインで用が足りてしまうわけです。
変数も使えるし、上下カーソルで履歴も拾えるので普通の電卓よりも高機能だったりします。
終了は quit と入力して[enter]キーを押します。

ご同胞の諸兄姉の執筆ライフが少しでも充実されんことを心より祈りつつ。


挿絵画家になろう(その8)


「挿絵画家になろう(その8)」です。
Blenderのアドオン、MB-Labの啓蒙です。
MB-Labを使って秀逸な少女キャラクターのメッシュオブジェクトを生成し、VRoidStudioの髪をインポートして装着させ、そこそこの服を着せ、キャラクターのマテリアルも弄れるようになり、更に表情も変更できるようになりました。

今回はポーズについてです。
しかしながらMB-LabのキャラクターはBlenderの人型モデルなので単にポーズをつけるだけならばBlenderの操作方法を学べばよいことになります。
ググればポーズのつけかたを解説しているサイトがいくつもあるので今更私が説明する必要もないでしょう。
難しいですが慣れるとわりと自由にポーズを付けられるようになります。

ではあるものの、我らがMB-Labにはポーズライブラリが付属します。
Blenderで人型キャラクターのポーズ付けに挫折した人でもポーズライブラリから選択し、ポーズをつけることができます。
らくちんですね。

ただ決められたポーズだけでは、挿絵を欲する同胞の諸兄姉は満足できないでしょう。
そんな諸兄姉にポーズライブラリを組み合わせて新しいポーズを作成する方法を展開しましょう。
Blenderの知識が要らない代わりにスクリプト言語の知識が必要になってきます。
諸兄姉はPythonの知識がありますよね?
あるといいな。
無くても、今回は言語的な知識はなくても良いように記事を書く予定です。
以前の記事』にPythonのインストールに書いてますので参考にしてください。

MB-LabはBlenderのアドオンなのですが、Windows10の場合、難しい事をしなければ通常以下にインストールされます。

C:\Users\%USERNAME%\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\addons\manuelbastionilab

MB-Labで生成されるキャラクターの雛形は以下のBlender Projectファイルに収められています。

C:\Users\%USERNAME%\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\addons\manuelbastionilab\data
humanoid_library.blend

このファイルを開くと分かるのですが、メッシュやアーマチュア、マテリアル、その他が定義されています。

基本ポーズはAポーズですね。
で、ポーズライブラリは以下のディレクトリになります。

C:\Users\%USERNAME%\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\addons\manuelbastionilab\data\poses

このディレクトリには以下の三つのディレクトリがあります。
female_poses
male_poses
rest_poses

rest_poseのディレクトリには以下のファイルがあります。
a-pose.json
a-pose.json
lambda-pose.json
lambda-pose.json
lambda-pose.json

このファイル名、どこかで見たことがありますね。
そうです、MB-LabのRest Poseの選択肢です。

各ポーズはjson形式というテキストファイルで記述されています。
試しにa-pose.jsonの中身を確認してみましょう。
テキストファイルなので普通にテキストエディッタで開けば見ることができます。
しかし改行がないので若干見にくいので次のようなスクリプトを使って解析します。

import json

pose = './a-pose.json'

with open(pose) as f_b:
    df_b = json.load(f_b)
    for w in df_b:
        print(w," = ",df_b[w])

jsonのファイルはKeyとValueの対を定義するリスト構造となっています。
このスクリプトはKeyとValueの対を表示します。
結果は以下のようになります。

thumb02_L  =  [1.0, 0.0, 0.0, 0.0]
calf_twist_R  =  [1.0, 0.0, 0.0, 0.0]
ring03_L  =  [1.0, 0.0, 0.0, 0.0]
thumb02_R  =  [1.0, 0.0, 0.0, 0.0]
pinky00_L  =  [1.0, 0.0, 0.0, 0.0]
pinky02_R  =  [1.0, 0.0, 0.0, 0.0]
ring00_R  =  [1.0, 0.0, 0.0, 0.0]
breast_L  =  [1.0, 0.0, 0.0, 0.0]
ring02_R  =  [1.0, 0.0, 0.0, 0.0]
lowerarm_R  =  [1.0, 0.0, 0.0, 0.0]
middle02_L  =  [1.0, 0.0, 0.0, 0.0]
neck  =  [1.0, 0.0, 0.0, 0.0]
ring02_L  =  [1.0, 0.0, 0.0, 0.0]
middle03_L  =  [1.0, 0.0, 0.0, 0.0]
ring00_L  =  [1.0, 0.0, 0.0, 0.0]
pelvis  =  [1.0, 0.0, 0.0, 0.0]
ring01_R  =  [1.0, 0.0, 0.0, 0.0]
thigh_R  =  [1.0, 0.0, 0.0, 0.0]
index02_R  =  [1.0, 0.0, 0.0, 0.0]
upperarm_L  =  [1.0, 0.0, 0.0, 0.0]
clavicle_R  =  [1.0, 0.0, 0.0, 0.0]
pinky02_L  =  [1.0, 0.0, 0.0, 0.0]
index01_R  =  [1.0, 0.0, 0.0, 0.0]
middle00_L  =  [1.0, 0.0, 0.0, 0.0]
calf_twist_L  =  [1.0, 0.0, 0.0, 0.0]
thigh_twist_L  =  [1.0, 0.0, 0.0, 0.0]
upperarm_twist_L  =  [1.0, 0.0, 0.0, 0.0]
middle02_R  =  [1.0, 0.0, 0.0, 0.0]
hand_R  =  [1.0, 0.0, 0.0, 0.0]
ring01_L  =  [1.0, 0.0, 0.0, 0.0]
toes_R  =  [1.0, 0.0, 0.0, 0.0]
index03_R  =  [1.0, 0.0, 0.0, 0.0]
lowerarm_L  =  [1.0, 0.0, 0.0, 0.0]
spine03  =  [1.0, 0.0, 0.0, 0.0]
lowerarm_twist_L  =  [1.0, 0.0, 0.0, 0.0]
middle01_R  =  [1.0, 0.0, 0.0, 0.0]
index00_R  =  [1.0, 0.0, 0.0, 0.0]
spine01  =  [1.0, 0.0, 0.0, 0.0]
foot_L  =  [1.0, 0.0, 0.0, 0.0]
index02_L  =  [1.0, 0.0, 0.0, 0.0]
thumb01_R  =  [1.0, 0.0, 0.0, 0.0]
pinky03_L  =  [1.0, 0.0, 0.0, 0.0]
ring03_R  =  [1.0, 0.0, 0.0, 0.0]
thumb03_R  =  [1.0, 0.0, 0.0, 0.0]
index01_L  =  [1.0, 0.0, 0.0, 0.0]
middle00_R  =  [1.0, 0.0, 0.0, 0.0]
lowerarm_twist_R  =  [1.0, 0.0, 0.0, 0.0]
breast_R  =  [1.0, 0.0, 0.0, 0.0]
foot_R  =  [1.0, 0.0, 0.0, 0.0]
middle01_L  =  [1.0, 0.0, 0.0, 0.0]
upperarm_R  =  [1.0, 0.0, 0.0, 0.0]
pinky01_R  =  [1.0, 0.0, 0.0, 0.0]
middle03_R  =  [1.0, 0.0, 0.0, 0.0]
hand_L  =  [1.0, 0.0, 0.0, 0.0]
pinky01_L  =  [1.0, 0.0, 0.0, 0.0]
head  =  [1.0, 0.0, 0.0, 0.0]
spine02  =  [1.0, 0.0, 0.0, 0.0]
calf_R  =  [1.0, 0.0, 0.0, 0.0]
thigh_L  =  [1.0, 0.0, 0.0, 0.0]
clavicle_L  =  [1.0, 0.0, 0.0, 0.0]
upperarm_twist_R  =  [1.0, 0.0, 0.0, 0.0]
index03_L  =  [1.0, 0.0, 0.0, 0.0]
thumb03_L  =  [1.0, 0.0, 0.0, 0.0]
calf_L  =  [1.0, 0.0, 0.0, 0.0]
root  =  [1.0, 0.0, 0.0, 0.0]
toes_L  =  [1.0, 0.0, 0.0, 0.0]
pinky03_R  =  [1.0, 0.0, 0.0, 0.0]
pinky00_R  =  [1.0, 0.0, 0.0, 0.0]
index00_L  =  [1.0, 0.0, 0.0, 0.0]
thumb01_L  =  [1.0, 0.0, 0.0, 0.0]
thigh_twist_R  =  [1.0, 0.0, 0.0, 0.0]

ポーズデーターファイルはボーンとその回転量を表す四つの実数の組のリストデーターなのです。
対応するボーンは以下のように実際に使われているアーマチュアのボーン名と一致します。

ボーンは親のボーンがあって子のボーンは親の位置と回転量に影響をうけます。
親子関係のツリー構造は以下のようになっています。

root:すべてのボーンの親
└pelvis:腰
  ├thigh_R:太腿
  │├thigh_twist_R
  │└calf_R:脛
  │  ├calf_twist_R
  │  └foot_R:足の甲
  │    └toes_R:爪先
  ├thigh_L:太腿
  │├thigh_twist_L
  │└calf_L:脛
  │  ├calf_twist_L
  │  └foot_L:足の甲
  │    └toes_L:爪先
  └spine01:脊椎
    └spine02
      └pine03
        ├neck:首
        │└head:頭
        ├breast_R:乳房
        ├breast_L:乳房
        ├clavicle_R:鎖骨
        │└upperarm_R:上腕
        │  ├upperarm_twist_R
        │  └lowerarm_R:下腕
        │    ├lowerarm_twist_R
        │    └hand_R:手首
        │     ├thumb01_R:親指
        │     │└thumb02_R
        │     │  └thumb03_R
        │     ├index00_R:人差し指
        │     │└index01_R
        │     │  └index02_R
        │     │    └index03_R
        │     ├middle00_R:中指
        │     │└middle01_R
        │     │  └middle02_R
        │     │    └middle03_R
        │     ├ring00_R:薬指
        │     │└ring01_R
        │     │  └ring02_R
        │     │    └ring03_R
        │     └pinky00_R:小指
        │       └pinky01_R
        │         └pinky02_R
        │           └pinky03_R
        └clavicle_L:鎖骨
          └upperarm_L:上腕
            ├upperarm_twist_L
            └lowerarm_L:下腕
              ├lowerarm_twist_L
              └hand_L:手首
                ├thumb01_L:親指
                │└thumb02_L
                │  └thumb03_L
                ├index00_L:人差し指
                │└index01_L
                │  └index02_L
                │    └index03_L
                ├middle00_L:中指
                │└middle01_L
                │  └middle02_L
                │    └middle03_L
                ├ring00_L:薬指
                │└ring01_L
                │  └ring02_L
                │    └ring03_L
                └pinky00_L:小指
                  └pinky01_L
                    └pinky02_L
                      └pinky03_L

面白いことに 親の位置と回転量に影響をうけるものの、子の相対的な回転は子自身の回転量によってのみ決まります。
つまり、肩の位置がどれだけ変わろうが、腕の回転量は影響を受けないということです。

ボーンの回転量はQuaternionという形式の四つの実数のリストによって表現されます。
Quaternion が何であるのかはさておいて、回転を意味する以上はどのポジションからの回転かが重要です。
答えを言えばa-poseを基準とする回転です。
なので、a-pose.jsonはすべての要素が[1.0, 0.0, 0.0, 0.0]、回転なしと定義されています。

さて、ここからが本題なのですが Quaternion で表現する任意の二つの回転量は球面線形補間ができるのです。
つまり二つのポーズの中間のポーズを計算によって求めることができてしまうのです。
実際にやってみましょう。

次のスクリプトをpose_slerp.pyとして保存してください。
スクリプトの意味を理解する必要はとりあえずはありません。

import sys
import json
import numpy
from pyquaternion import Quaternion

if __name__ == '__main__':
    args = sys.argv
    if 2 <= len(args):
        base_pose = args[1]
    else:
        print("no base pose!")
        exit()
    if 3 <= len(args):
        reference_pose = args[2]
    else:
        print("no reference_pose!")
        exit()
    if 4 <= len(args):
        amount = args[3]
    else:
        print("no amount!",args[3])
        exit()
    if 5 <= len(args):
        out_pose = args[4]
    else:
        out_pose = './output.json'

with open(base_pose) as f_b:
    print("Base pose",base_pose, "is loaded")
    df_b = json.load(f_b)

with open(reference_pose) as f_r:
    print("Reference pose",reference_pose, "is loaded")
    df_r = json.load(f_r)

for w in df_b:
    q1 = Quaternion(df_b[w])
    q2 = Quaternion(df_r[w])
    q3 = Quaternion.slerp(q1, q2, float(amount))
    df_b[w] = q3.elements.tolist()

f_out = open(out_pose, 'w')
f_out.write(json.dumps(df_b))
print("Output pose file is",out_pose)

pyquaternionというモジュールが必要です。
以下のようにしてインストールしてください。

python -m pip install pyquaternion

同じディレクトリに以下のポーズライブラリファイルを保存します。
 a-pose.json
 shojo_classic01.json

コマンドラインから以下を実行します。

python pose_slerp.py a-pose.json shojo_classic01.json 0.50 output.json

コマンドの意味は以下です。
python <実行スクリプト名> <ベースポーズファイル名> <ターゲットポーズファイル名> <補間の割合> <出力ポーズファイル名>

<補間の割合>は0~1の実数を指定してください。
0.5でちょうど中間の補間となります。

output.jsonという新しいポーズファイルができるので、MB-Labのポーズとしてloadすれば、生成したポーズを読み込むことができます。
次のアニメーションは0.00~1.00まで0.05刻みで変化させ、一枚ずつMB-Labに読み込ませたものです。

いかがでしょうか?
任意の二つのポーズから、二つのポーズを補完する新しいポーズを生成できるのです。
MB-Labにはたくさんの魅力的なポーズが用意されています。
※ただしfemaleに限る
更に新しく作ったポーズと別のポーズを組み合わせることも可能。
つまり組み合わせは無限。
「あのポーズとこのポーズを組み合わせれば」と夢が膨らむと思いませんか?

とはいえ、これでも自作小説に挿絵を欲する諸兄姉には満足いただけないかもしれません。
「ポーズは分かった。でも手が思うようにポージングできない」
「手指のボーンって、なにげに全体の半分以上あって収取つかないんですけれど」
そう思われるでしょう。

ごもっともです。
体のポーズに引きずられて、手を思うように変形させることができません。
手のポーズが思い通りにならないのは困ります。
手は口ほどにものをいうのですから。
指差し、ピース、サムアップ、ブーイング、グー、チョキ、パー。
フレミングの左手の法則。
シーンに応じて手のポーズを付けなければなりませんよね?

大丈夫です。
ソリューションを用意してあります。
Quaternion では部分の差し替えができるのです。
任意のポーズの任意のボーンだけの回転量を移植できるのです。
手はHand_R,Hand_Lを親とする一連のボーンツリーで構成されています。
よって他のポーズファイルの手の構成を移植することができます。
実際にやってみましょう。

次のスクリプトをpose_copy_hands.pyとして保存してください。
スクリプトの意味を理解する必要はとりあえずはありません。
ただすごくベタなスクリプトなので逆になにをやっているかは想像できると思います。

import sys
import json

if __name__ == '__main__':
    args = sys.argv
    if 2 <= len(args):
        base_pose = args[1]
    else:
        print("no base pose!")
        exit()
    if 3 <= len(args):
        reference_pose = args[2]
    else:
        print("no reference_pose!")
        exit()
    if 4 <= len(args):
        out_pose = args[3]
    else:
        out_pose = './output.json'

with open(base_pose) as f_b:
    print("Base pose",base_pose, "is loaded")
    df_b = json.load(f_b)

with open(reference_pose) as f_r:
    print("Reference pose",reference_pose, "is loaded")
    df_r = json.load(f_r)

df_b['hand_R']      = df_r['hand_R']      
df_b['thumb01_R']   = df_r['thumb01_R']   
df_b['thumb02_R']   = df_r['thumb02_R']   
df_b['thumb03_R']   = df_r['thumb03_R']   
df_b['index00_R']   = df_r['index00_R']   
df_b['index01_R']   = df_r['index01_R']   
df_b['index02_R']   = df_r['index02_R']   
df_b['index03_R']   = df_r['index03_R']   
df_b['middle00_R']  = df_r['middle00_R']  
df_b['middle01_R']  = df_r['middle01_R']  
df_b['middle02_R']  = df_r['middle02_R']  
df_b['middle03_R']  = df_r['middle03_R']  
df_b['ring00_R']    = df_r['ring00_R']    
df_b['ring01_R']    = df_r['ring01_R']    
df_b['ring02_R']    = df_r['ring02_R']    
df_b['ring03_R']    = df_r['ring03_R']    
df_b['pinky00_R']   = df_r['pinky00_R']   
df_b['pinky01_R']   = df_r['pinky01_R']   
df_b['pinky02_R']   = df_r['pinky02_R']   
df_b['pinky03_R']   = df_r['pinky03_R']   

df_b['hand_L']      = df_r['hand_L']      
df_b['thumb01_L']   = df_r['thumb01_L']   
df_b['thumb02_L']   = df_r['thumb02_L']   
df_b['thumb03_L']   = df_r['thumb03_L']   
df_b['index00_L']   = df_r['index00_L']   
df_b['index01_L']   = df_r['index01_L']   
df_b['index02_L']   = df_r['index02_L']   
df_b['index03_L']   = df_r['index03_L']   
df_b['middle00_L']  = df_r['middle00_L']  
df_b['middle01_L']  = df_r['middle01_L']  
df_b['middle02_L']  = df_r['middle02_L']  
df_b['middle03_L']  = df_r['middle03_L']  
df_b['ring00_L']    = df_r['ring00_L']    
df_b['ring01_L']    = df_r['ring01_L']    
df_b['ring02_L']    = df_r['ring02_L']    
df_b['ring03_L']    = df_r['ring03_L']    
df_b['pinky00_L']   = df_r['pinky00_L']   
df_b['pinky01_L']   = df_r['pinky01_L']   
df_b['pinky02_L']   = df_r['pinky02_L']   
df_b['pinky03_L']   = df_r['pinky03_L']   

f_out = open('out_pose', 'w')
f_out.write(json.dumps(df_b))

コマンドラインから以下を実行します。

python pose_copy_hands.py a-pose.json shojo_classic01.json output.json

コマンドの意味は以下です。
python <実行スクリプト名> <ベースポーズファイル名> <手のポーズを取り込むポーズファイル名> <出力ポーズファイル名>

出力結果ファイル output.json を MB-Labの少女キャラクターに読み込むと以下のようになります。

a-poseにshojo_classic01の手のポーズが移植されました。
つまり体のポーズを仕上げたあと、手のポーズだけを目的のポーズに差し替えることができるのです。
スクリプトを改造すれば右手だけ、もしくは左手だけ、もしくは人差し指だけというように任意の部位を差し替えることができるので応用が利きます。

ついでに右手のポーズを左手に移植、またはその逆を行う例を紹介しましょう。
次のスクリプトをpose_copy_hand_one2other.pyとして保存してください。
スクリプトの意味を理解する必要はとりあえずはありません。
ただこのスクリプトもベタです。
諸兄姉は何を行っているのか推測できるでしょう。

import sys
import json

if __name__ == '__main__':
    args = sys.argv
    if 2 <= len(args):
        base_pose = args[1]
    else:
        print("no base pose!")
        exit()
    if 3 <= len(args):
        print(args[2])
        if ((args[2] != 'l2r') and (args[2] != 'r2l')):
            print("sub-command must be l2r or r2l") 
            exit()

    if 4 <= len(args):
        out_pose = args[3]
    else:
        out_pose = './output.json'

def x_axis_mirrord(a):
    b = a[:]
    b[2] *= -1.0
    b[3] *= -1.0
    return(b[:])

with open(base_pose) as f:
    print("Base pose",base_pose, "is loaded")
    df = json.load(f)

if (args[2] == 'l2r'):
    df['hand_R']     = x_axis_mirrord(df['hand_L'])
    df['thumb01_R']  = x_axis_mirrord(df['thumb01_L'])
    df['thumb02_R']  = x_axis_mirrord(df['thumb02_L'])
    df['thumb03_R']  = x_axis_mirrord(df['thumb03_L'])
    df['index00_R']  = x_axis_mirrord(df['index00_L'])
    df['index01_R']  = x_axis_mirrord(df['index01_L'])
    df['index02_R']  = x_axis_mirrord(df['index02_L'])
    df['index03_R']  = x_axis_mirrord(df['index03_L'])
    df['middle00_R'] = x_axis_mirrord(df['middle00_L'])
    df['middle01_R'] = x_axis_mirrord(df['middle01_L'])
    df['middle02_R'] = x_axis_mirrord(df['middle02_L'])
    df['middle03_R'] = x_axis_mirrord(df['middle03_L'])
    df['ring00_R']   = x_axis_mirrord(df['ring00_L'])
    df['ring01_R']   = x_axis_mirrord(df['ring01_L'])
    df['ring02_R']   = x_axis_mirrord(df['ring02_L'])
    df['ring03_R']   = x_axis_mirrord(df['ring03_L'])
    df['pinky00_R']  = x_axis_mirrord(df['pinky00_L'])
    df['pinky01_R']  = x_axis_mirrord(df['pinky01_L'])
    df['pinky02_R']  = x_axis_mirrord(df['pinky02_L'])
    df['pinky03_R']  = x_axis_mirrord(df['pinky03_L'])
else :
    df['hand_L']     = x_axis_mirrord(df['hand_R'])
    df['thumb01_L']  = x_axis_mirrord(df['thumb01_R'])
    df['thumb02_L']  = x_axis_mirrord(df['thumb02_R'])
    df['thumb03_L']  = x_axis_mirrord(df['thumb03_R'])
    df['index00_L']  = x_axis_mirrord(df['index00_R'])
    df['index01_L']  = x_axis_mirrord(df['index01_R'])
    df['index02_L']  = x_axis_mirrord(df['index02_R'])
    df['index03_L']  = x_axis_mirrord(df['index03_R'])
    df['middle00_L'] = x_axis_mirrord(df['middle00_R'])
    df['middle01_L'] = x_axis_mirrord(df['middle01_R'])
    df['middle02_L'] = x_axis_mirrord(df['middle02_R'])
    df['middle03_L'] = x_axis_mirrord(df['middle03_R'])
    df['ring00_L']   = x_axis_mirrord(df['ring00_R'])
    df['ring01_L']   = x_axis_mirrord(df['ring01_R'])
    df['ring02_L']   = x_axis_mirrord(df['ring02_R'])
    df['ring03_L']   = x_axis_mirrord(df['ring03_R'])
    df['pinky00_L']  = x_axis_mirrord(df['pinky00_R'])
    df['pinky01_L']  = x_axis_mirrord(df['pinky01_R'])
    df['pinky02_L']  = x_axis_mirrord(df['pinky02_R'])
    df['pinky03_L']  = x_axis_mirrord(df['pinky03_R'])

f_out = open(out_pose, 'w')
f_out.write(json.dumps(df))
print("Output file is",out_pose)

コマンドラインから以下を実行します。

python pose_copy_hand_one2other.py output.json l2r output2.json

これは上で生成したoutput.jsonを入力に左手のポーズを右手にコピーし、output2.jsonとしてポーズファイルを生成します。
MB-Labの少女キャラクターにoutput2.jsonを読み込んでみましょう。

手にご注目ください。
左手のポーズが右手に移植されていることが分かります。
同様に以下を実行してください。

python pose_copy_hand_one2other.py output.json r2l output3.json

これは上で生成したoutput.jsonを入力に右手のポーズを左手にコピーし、output3.jsonとしてポーズファイルを生成します。
output3.jsonを読み込んでみましょう。

期待通りの結果となっています。
いかがでしょうか?
まったくキャラクターのポーズ編集なしで、かなり思い通りのポーズをとらせることができることをご理解いただけましたでしょうか?
後は自分なりのポーズライブラリを蓄積してゆけばよいわけです。
無論Blenderでのポーズ編集ができるようになればもっと自由度が増すでしょう。
微調整を行うのはそれほど難しいことではないので、どんどんとチャレンジしてください。

今回の記事はMB-Labの説明ではないばかりか、Blenderの機能ですらありませんでした。
MB-Labのデーターファイルはどれも取り扱いやすいjson形式となっています。
だからスクリプトで変化させることができてしまうのです。

実際にデーターファイルを弄るためにはスクリプト言語の知識が必要だったりしますので、その実ポーズの編集を覚えるのとどちらが早いかは微妙なところもあります。
しかし、苦労したポーズは取っておいて、ライブラリ化すると良いと思います。

今回はこれで終わりです。
時間があれば[その9]を書きたいと思います。



黒灰色の魔女と時の魔女 第五章第三話(九)更新しています


黒灰色(こっかいしょく)の魔女と時の魔女』、『第五章第三話(九)君、山登れ』更新しています。
砂漠に子供二人、赤ん坊付きでおっぽり出されて、頼れるのは怪しげな砂漠の声だけというシチュエーション。
読んで下さいね。

絵はマリアの幼少期です。
流石にこれ以上は誰も死なないはず。
マリアって将来的には二児の母ですし。

で背景はWord Cloudです。
twitterとかで小説の宣伝画像を作りたいなと思うじゃないですか?
でも絵を作るってメンドクサイですよね?
そんな時にWord Cloudですよ。
私もtwitterを始めたばかりの時はWord Cloud一本で宣伝絵を作っていました。

Word Cloudとは切り出した単語や文章を、重要なものを大きく、そうでもないものを小さく表示して、画面全体を埋める表現手法です。
どのようなキーワードが流行しているかを見える化するツールなわけです。
我々小説家になろうに投稿するものは、小説のキーワードやインパクトのあるフレーズを表示させると良いんじゃないかと思うわけです。

作り方は色々あるのですけれど、お勧めはPython3でword_cloudを使う方法です。

Pythonはスクリプト言語です。
Python3は現状最新版のPythonです。
Python2もまだ現役ですが日本語の取り扱い等でPython3は進化しています。
WINDOWS10 PCへのインストールは「このサイト」を参照してください。
Python3のインストール

環境変数等も設定してDOS窓からPythonが実行できるようにしてください。
DOS窓から

python --version

と打つとマイクロソフトストアが立ち上がってトホホとなる場合は「ここ」を見ると幸せになれるかもしれません。
windowsでpython3を実行するとストアが開く

world_cloudはPython3のモジュールです。
前提となるモジュールがあるのでいくつかDOS窓でインストールを行います。
具体的には以下をDOS窓で実行します。

python get-pip.py 
python -m pip install --upgrade pip
python -m pip install matplotlib
python -m pip install numpy
python -m pip install pillow
python -m pip install wordcloud

pipというのはPythonのモジュールを取得するためのスクリプトです。
pipを使うことにより様々なモジュールをインストールすることができます。
matplotlibと numpy は数値演算系のモジュールで、Pythonプログラマは皆お世話になっているものです。
pillow はPythonの画像系のモジュールでお絵かきする人は知っておいた方が良いモジュールです。
Pythonインストール時、インストールディレクトリとその下のScriptsフォルダにパスを通しておいてください。
例えばC:\Python37にインストールしたのなら以下を環境変数PATHに追加します。

C:\Python37
C:\Python37\Scripts

Pythonのモジュールと言いましたが、word_cloudを使う上ではPythonは単なるプラットフォームで意識する必要はありません。
実際に使うのはword_cloud_cli.exeというコマンドです。
以下のコマンドが実行できるか確かめてください。

c:\work>wordcloud_cli --help
usage: wordcloud_cli [-h] [--text file] [--regexp regexp] [--stopwords file]
                     [--imagefile file] [--fontfile path] [--mask file]
                     [--colormask file] [--contour_width width]
                     [--contour_color color] [--relative_scaling rs]
                     [--margin width] [--width width] [--height height]
                     [--color color] [--background color] [--no_collocations]
                     [--version]

A simple command line interface for wordcloud module.

optional arguments:
  -h, --help            show this help message and exit
  --text file           specify file of words to build the word cloud
                        (default: stdin)
  --regexp regexp       override the regular expression defining what
                        constitutes a word
  --stopwords file      specify file of stopwords (containing one word per
                        line) to remove from the given text after parsing
  --imagefile file      file the completed PNG image should be written to
                        (default: stdout)
  --fontfile path       path to font file you wish to use (default:
                        DroidSansMono)
  --mask file           mask to use for the image form
  --colormask file      color mask to use for image coloring
  --contour_width width
                        if greater than 0, draw mask contour (default: 0)
  --contour_color color
                        use given color as mask contour color - accepts any
                        value from PIL.ImageColor.getcolor
  --relative_scaling rs
                        scaling of words by frequency (0 - 1)
  --margin width        spacing to leave around words
  --width width         define output image width
  --height height       define output image height
  --color color         use given color as coloring for the image - accepts
                        any value from PIL.ImageColor.getcolor
  --background color    use given color as background color for the image -
                        accepts any value from PIL.ImageColor.getcolor
  --no_collocations     do not add collocations (bigrams) to word cloud
                        (default: add unigrams and bigrams)
  --version             show program's version number and exit

c:\work>

作業はc:\workで行うこととします。
必要になるのは以下。
・wordテキストファイル。
表示するキーワードを格納するファイルです。
半角スペースもしくは改行で区切ります。
抜粋ですが以下のような感じです。

黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
黒灰色の魔女と時の魔女
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第五章:傍に居てよ
第三話:ずっときみを見守っていたんだ
第三話:ずっときみを見守っていたんだ
第三話:ずっときみを見守っていたんだ
第三話:ずっときみを見守っていたんだ
第三話:ずっときみを見守っていたんだ
第三話:ずっときみを見守っていたんだ
第三話:ずっときみを見守っていたんだ
(九)君、山登れ
(九)君、山登れ
(九)君、山登れ
(九)君、山登れ
(九)君、山登れ
(九)君、山登れ
(九)君、山登れ
マリア
マリア
マリア
マリア
マリア
マリア
マリア
マリア
マリア
マリア
リリィ
リリィ
リリィ
リリィ
リリィ
リリィ
ヨシュア
ヨシュア
ヨシュア
ヨシュア
ヨシュア
ヨシュア
ヨシュア
ヨシュア
ヨシュア
齧りながら
頷く
頷く
呟きながら
麓
緑
稜線
稜線
了解
立ったまま
立ち上がる
立ち上がる

このファイルをC:\work\input.txtとして保存します。
漢字コードはUTF-8を選択します。
数が多いキーワードは大きくなります。
なので数で調整してください。

後、漢字をサポートしているフォントファイルを指定します。
C:\Windows\Fonts\ にある適当なフォントを選択します。
気に入っているフォントがあればそれを指定しても構いません。
私は大好きな「装甲明朝」を使います。
DOS窓で以下のように実行してください。

wordcloud_cli --width 1920 --height 1080 --text input.txt --fontfile C:\Windows\Fonts\SoukouMincho.ttf --no_collocations --imagefile planetext.png

planetext.pngが生成されます。
以下のような感じになります。

マスク画像を指定して文字のある部分と無い部分を作ることもできます。
例えば以下のような画像ファイルを用意します。
image_mask.png

黒の部分に文字が入り、白の部分はマスクされます。
DOS窓で以下のように実行してください。

wordcloud_cli --width 1920 --height 1080 --text input.txt --fontfile C:\Windows\Fonts\SoukouMincho.ttf --no_collocations --mask image_mask.png --imagefile text_w_mask.png

text_w_mask.png が生成されます。

マスクされました。
フォントの色を指定することもできます。
例えば赤を指定したければ以下のようにします。

wordcloud_cli --width 1920 --height 1080 --text input.txt --fontfile C:\Windows\Fonts\SoukouMincho.ttf --no_collocations --mask image_mask.png --color red --imagefile text_w_mask_red.png

カラーマスク画像を使って色調を管理することもできます。
どんな画像でも良いのですがグラデーションやノイズ交じりのものが良いと思います。
例えば次のような画像を用意します。
cmask2.png

DOS窓で以下のように実行してください。

wordcloud_cli --width 1920 --height 1080 --text input.txt --fontfile C:\Windows\Fonts\SoukouMincho.ttf --no_collocations --mask image_mask.png --colormask cmask2.png --imagefile text_w_mask_cmask.png

以下のような画像が生成されます。

後は画像を合成すれば完成です。

いかがでしょうか?
twitter用の画像として手軽で良いと思いませんか?

絵で困ったときはword_cloudの存在を思い出してあげてくださいね。