[VRChat] コントローラーの握り具合に応じて表情を変える

VRChatではコントローラーの握り具合に応じてアバターのアニメーションを変化させることができます。
本記事では一例として、コントローラーの握り具合で表情を変化させる方法を説明します。
なお、本記事ではOculus Quest2を使用することを前提にしています。ですが、他のコントローラーを使用する場合でも参考になる内容かと思います。

目次

この記事の概要

本記事では、コントローラーの握り具合に応じて表情を変化させる方法に絞って説明します。
アニメーションに必要なAnimation ClipやAnimation Controllerの基礎的な説明はしませんので、こちらの概念がわからない場合は他の記事をご参照ください。また、VRCSDKの設定方法等も説明していませんので、わからない場合はそちらも別途お調べください。

表情を変化させるとは

具体例

以下の動画では真顔から笑顔へ顔を変化させています。コントローラーの握り具合により笑顔になるまでの速度を早めたり遅くしたりできます、変化の途中で表情を止めることもできます。

握り具合とは

握り具合というのは、以下の画像内で説明されている"Axis1D.PrimaryHandTrigge"という名前のトリガーの押し込み具合のことです。

f:id:yakumo890:20211119235618p:plain
Quest2のコントローラーの名称

(出典: https://developer.oculus.com/documentation/unity/unity-ovrinput/)

Quest2のコントローラーの場合はFistのハンドジェスチャーの握り方をしている場合のみ値を変化させられるようです(この情報は筆者がデバッガを使って確認しただけであり、公式情報ではありません) 。
Fistというのはグー(✊)の手のことで、コントローラーを以下のように握る事により表現できます。

f:id:yakumo890:20211119235621p:plain
Fistの握り方

この状態で、トリガーの押し込みを緩めたり強めたりすれば表情も変化させられます。

実現方法

仕組みの説明

はじめに仕組みから説明します。やり方だけ知りたい方は読み飛ばしても良いです。

このギミックの実現方法は、GestureRightWeight/GestureLeftWeightMotion Timeに設定するというものです。
これらの用語について説明します。

GestureRightWeight/GestureLeftWeightとは

GestureRightWeightとGestureLeftWeightは、VRChatがユーザー向けに用意しているAnimation Parameterの一つです。
これらの値は、ユーザーがコントローラーを握っている強さに応じて0から1までのいずれか実数値になります。GestureRightWeightは右手のコントローラーに対応し、GestureLeftWeightは左手のコントローラーに対応します。これらのパラメーターは左右以外に違いはないので、以下の説明ではこれらをまとめてGestureWeightと呼ぶことにします。
この値の変化はどのようにコントローラーを握っているかに依存するようで、前述の通りQuest2のコントローラーではFistの握り方をしているときのみトリガーの押し込み具合で変化させることができます。全く押し込まなければ0、最大まで押し込んでいれば1です。

Motion Timeとは

UnityのAnimation Controllerには、アニメーションの特定の割合だけ進んだ部分のみ再生するMotion Timeという仕組みがあります。
たとえば以下のような、キューブが60フレームでx軸方向に10動くアニメーションがあったとします。

このアニメーションに変更を加えていきます。
まずは、Animation Parameterを追加します。追加するパラメーターのタイプをFloatにし、名前を"Motion"にします。
つぎに、ステートの「Motion Time」の横にあるParameterにチェックをつけます。そうすると、プルダウンメニューが追加されますので、先程追加したMotionというパラメーターを設定します。

f:id:yakumo890:20211120003257p:plain
Motion Timeの設定

Motionを0.5に設定してアニメーションを再生します。そうすると、キューブがx軸方向に5だけ移動した位置で静止します。

f:id:yakumo890:20211120004039p:plain
キューブがX=5の位置に移動

この状態でMotionの値を変えると、それに応じてキューブが移動します。

これはMotionというパラメーターで指定した割合(0.5だったら50%)だけアニメーションが進んだ部分のみ再生しているからです。
この仕組は、ゲーム中に変化するパラメーターに応じてアニメーションの再生を変えたり、アニメーションの進行速度を別の要因と同期させたりするのに使えます。

そして、このMotion TimeによりGestureWeightの値とアニメーションを同期させることにより、コントローラーの握り具合に応じてアニメーションを変更させることができるようになります。

詳細な設定手順

表情を変化させるとはの表情変化を例に説明していきます。

1. 筆者の作業環境

  • OS: Windows 10 21H1
  • Unity: 2019.4.31f1

VRCSDKは3です。2でも実現することができるようですが本記事では説明しません。

2. 表情のアニメーションを作成する

表情のアニメーションには、2つのキーフレームを追加する必要があります。
1つ目のキーフレームはコントローラーを全く握っていないときの表情で、2つ目のキーフレームはコントローラーを最大まで握っているときの表情です。 この2つのキーフレームに以下の表情を割り当てます。

f:id:yakumo890:20211120223034p:plainf:id:yakumo890:20211120223037p:plain
右が1つ目のキーフレーム、左が2つ目のキーフレーム

これらのキーフレームの間隔ですが、1フレーム以上空いていれば構いません。今回の例では1フレーム空けています。

3. FXレイヤーで使用するAnimation Controllerを設定する

表情のアニメーションはFXレイヤーに入れなければなりません。なので、今回作成するアニメーションはFXレイヤー用のAnimation Controllerに入れます。

まず初めに、Animation Controllerに表情用のレイヤーがない場合は新規に作成してください。このレイヤーのステートマシーンの構造は今回の話とは無関係なので、好きなように構築して構いません。
ただし、Fistの表情用のステートを必ず作ってください。
Animation ParameterのGestureRight/GestureLeftはFistを1で表すので、これらの値が1になったときに遷移するようにすればFistのアニメーションが作れます(GestureRight/GestureLeftがAnimation Controllerにない場合は新規に作成してください。値はIntです)。
以下の画像では右手のFistのステートの作り方を説明しています。

f:id:yakumo890:20211120223943p:plain
Fistに遷移する設定

続いて、Animation ControllerのAnimation Parameterに値を追加します。
追加する値はFloatにしてください。名前は必ずGestureRightWeightGestureLeftWeightにしてください。
これらの違いは、右手のコントローラーか左手のコントローラーかです。右手のコントローラーの握り具合に応じて表情を変える場合はGestureRightWeightという名前に、左手のコントローラーの握り具合に応じて表情を変える場合はGestureLeftWeightという名前にしてください。どちらの手にもアニメーションを付けたい場合はこの両方を追加してください。
これらのパラメーターの値は0のままで構いません。

このFistのステートを設定していきます。 まずは、Motionに上記で作ったアニメーションを設定してください。 次に、Motion Timeの横にあるチェックボックスにチェックをつけます。チェックをつけるとプルダウンメニューが表示されるので、そこにGestureRightWeightかGestureLeftWeightを設定します。繰り返しますが、右手用の表情ならGestureRightWeightで、左手用の表情ならGestureLeftWeightを設定します。
以下の画像ではGestureRightWeightをセットしています。

f:id:yakumo890:20211120224745p:plain
Fistのステートの設定

これで設定は完了です。

4. 確かめる

アバターをアップロードすればVRChatで確かめられますが、Unity上でもある程度の確認はできます。
Hierarchyでアバターを選び、InspectorからAniamtorというコンポーネントのControllerに上記のFXレイヤー用のAnimation Controllerを設定してください。

f:id:yakumo890:20211120225519p:plain
テストのためのAnimatorの設定
この状態でPlayすると、アバターにFX用のAnimation Controllerが適用された状態でSceneが再生されます。
再生した状態でGestureRightもしくはGestureLeftの値を1にし、アバターの表情をFistの表情に変化させます。
この状態で、GestureRightWeightもしくはGestureLeftWeightの値を0から1までの好きな数字に変えます。これにより、アバターの表情が変化したら設定が正常に完了していることになります。
ただし、Animation Parameterの名前が正しくない(スペルが間違っていたりする)場合は、Unity上では動いてもVRChat上では正常に動かなくなるのでスペルが正しいか必ず確認してください。

おわりに

本記事では、コントローラーの握り具合で表情を変化させる方法を説明しました。
筆者が持っているHMDがOculus Quest2ということもあり、Quest2のコントローラーを前提にした説明をしましたが、GestureRightWeightとGestureLeftWeightは他のHMDのコントローラーでも変化させられると考えています。
他のコントローラーでこれらの値を取得する方法(握り方)を知っている方、教えていただけるとありがたいです。

ティグリなすちゃんをAvatar3.0に移行して髪型を変えられるようにした

※この記事はUnity及びBlenderの素人が調べながら作業したときの記録です。ベストプラクティスではありませんのでご注意ください。

目次

はじめに

VRChat想定アバター、ティグリなすちゃん(以下、なすちゃん)をAvatar3.0にアップデートしました。
また、なすちゃんはポニーテールバージョンとピッグテールバージョンの2種類あります。
この2種類は別々のアバターのため、独自のExpressionを実装して1つのアバターで両方の髪型を変更にできるにしました。
そのときの作業の記録です。

この記事の内容

この記事で説明していること

  • なすちゃんをAvatar2.0からAvatar3.0にアップデートする
  • なすちゃんの髪型をExpressionsで変えられるようにする

この記事で説明していないこと

説明具合

読者はBlenderをあまり操作した経験がないことを想定しますので、Blenderでの操作については詳しく記載します。 Unityでの作業はある程度経験があることを想定します。Unityでの操作説明は多少端折ります。
(これは筆者の作業当初の状態です)

作業環境

使用したアセット

本記事では必要

必要ではない

工程

1. なすちゃんを購入

兎にも角にも、なすちゃんを購入しダウンロードします。これが無いと始まりません。 3000円と比較的安価で何よりも可愛いので皆さん購入しましょう。

2. なすちゃんの髪のパーツを分割する

以下の工程では、このページをもとにBlender内のウィンドウを呼称します。 blender-cg.net また、UIは日本語とし、ショートカットはデフォルトのままとして説明します。

2.1. Blenderで3Dモデルを開く

まずはBlenderで3Dモデルを開きます。
Tigri_Nasu.zip(なすちゃんのアーカイブファイル)を解凍して得られるフォルダ内にある「nasu_Pigtails_PC.fbx」及び「nasu_Ponytail_PC.fbx」の両方をインポートします。「nasu_Pigtails_PC.fbx」はピッグテールで「nasu_Ponytail_PC.fbx」はポニーテールのなすちゃんです。
fbxファイルのインポートは、ファイル > インポート > FBX(.fbx)で行います。
モデルを開くとアウトライナーは以下のようになります。Armature、Armature.001の左横の三角マーク(▶)を押せば階層が表示されます。

f:id:yakumo890:20211001171324p:plain
nasu_Pigtails_PC.fbxとnasu_Ponytail_PC.fbxをインポートしたときのアウトライナー
このArmatureはそれぞれのモデルファイルオブジェクトを表すものですが、このままの名前ではわかりにくいので以下のように名前を変更します。名前の変更は、オブジェクトにフォーカスを当てた状態でFn2キーを押下することでできます。
f:id:yakumo890:20210917120031p:plain
オブジェクトの名前の変更
Pigtailと名のついているものはnasu_Pigtails_PC.fbxをインポートしたもの、Ponytailと名の付いてるものはnasu_Ponytail_PC.fbxをインポートしたものです。
以降、変更した名前で説明していきます。

3Dビューに2つのモデルが表示されている状態は邪魔なので、Pigtailを非表示にします。
非表示は、アウトライナーから非表示にしたいオブジェクトの横にある目のマークをクリックして目をつむった状態のマークにすることでできます。

f:id:yakumo890:20210917120206p:plain
オブジェクトの非表示

2.2. ポニーテールのメッシュを分離する

次に、ポニーテールのメッシュを分離します。
メッシュを分離するためには編集モードに移行する必要があります。
編集モードに移行するには、アウトライナーでメッシュ(Ponytail_mesh)を選択し、3Dビューの上にマウスカーソルを乗せてからTabキーを押下します。モデル上に線が網目状に表示されていれば編集モードに移行できています。

f:id:yakumo890:20210917120809p:plain
編集モードに移行した状態
ところで、編集モードに移行する前の状態は、デフォルトではオブジェクトモードと呼びます。モードによってできる操作が異なるため、操作がうまく行かない場合はモードを確認してください。
f:id:yakumo890:20211001172738p:plain
現在のモードを確認する
次に、ポニーテールの部分だけ分離するために、ポニーテールのメッシュのみを選択します。
3Dビュー上でAlt+A*1を押下してメッシュの選択を解除します。その後、ポニーテールの上にマウスカーソルを乗せた状態でLキー*2を押下します。 これにより、ポニーテール全体が選択された状態になります。
ちなみに、3Dビュー上でモデルを拡大/縮小表示させるにはマウスホイールを回します。モデルを回転させるには、3Dビュー上の適当な場所でマウスホイールをドラッグします。
f:id:yakumo890:20210917121811p:plain
ポニーテール全体が選択されている状態
選択した後、3Dビューにマウスカーソルを乗せた状態でPキー*3を押し、表示された選択肢の「選択」をクリックすると、ポニーテール部分のメッシュを分離することができます。
f:id:yakumo890:20210917122056p:plainf:id:yakumo890:20210917122227p:plain
ポニーテール部分のメッシュが分離された状態(左)、ポニーテール部分のメッシュ(Ponytail_mesh.001)が追加された(右)
分離が完了したら、Tabキーを押して編集モードを終了します。
新たにできたメッシュの「Ponytail_mesh.001」は、「Ponytail_tail_mesh」と名前を変更します。

2.3. ポニーテールのボーンを分離する

続いて、ポニーテールのボーンを分離します。
アウトライナーでボーン(Ponytail_bone)を選択して、編集モードに移行します。ボーンの編集モードへの移行もTabキーでできます。
選択のやり方ですが、ボーンをクリックするとそのボーンを選択することができ、左クリックドラッグで範囲選択が可能です。あるボーンを選択したまま別のボーンも選択したい場合はShiftキーを押しながらクリックすることで選択できます。
ここでは、ポニーテールに関わるすべてのボーンを選択します。ここでの選択すべきボーンは文字では説明しづらいので、画像を参考にしてください。なお画像はなすちゃんを横から見た状態であり、メッシュは非表示にしています。

f:id:yakumo890:20211001174023p:plain
ポニーテールのボーンをすべて選択した状態
選択できたら、Pキーを押して「ボーンを別アーマチュアに分離」をクリックしてください。「Ponytail.001」というオブジェクトができたらOKです。
f:id:yakumo890:20210917124539p:plainf:id:yakumo890:20210917124549p:plain
ポニーテールのボーンが分離された状態(左)と、ボーンのオブジェクト(Ponytail.001)が追加された状態
Ponytail.001という名前はわかりにくいので、「Ponytail_tail」と名前を変更し、階層の下にある「Ponytail_bone.001」は「Ponytail_tail_bone」と名前を変更しておきます。

2.4. ポニーテールのメッシュとボーンを紐付ける

ポニーテールのメッシュとボーンはばらばらの状態になってしまったので、再度紐付けます。

編集モードになっている場合は、Tabキーを押下してオブジェクトモードに移行しておいてください。
最初に不要なオブジェクトを削除します。
Ponytailはポニーテールの部分以外は不要なので、ポニーテール以外のメッシュ及びボーンを削除します。
アウトライナーで「Ponytail_mesh」、「Ponytail_bone」を選択します。Xキーを押下することにより、選択したオブジェクトを削除できます。

f:id:yakumo890:20211001175142p:plainf:id:yakumo890:20210917130408p:plain
不要なオブジェクトを選択(左)、オブジェクトを削除した状態(右)

次に、メッシュとボーンを紐付けていきます。
アウトライナーPonytail_tail_mesh→Ponytail_tailの順に選択します。
選択した後、3Dビューにカーソルを乗せてからCtrl-P*4を押下し、選択肢の中から「自動のウェイトで」をクリックします*5。 そうすると、メッシュとボーンが同じオブジェクトの中に入ります。

f:id:yakumo890:20210917130804p:plain
ポニーテールのメッシュとボーンを紐付けた
ここで、Ponytail_tail_boneの階層にある「Hair_B」というボーンの名前を「Pony_B」にしておきます。このボーンは後に使うためわかりやすい名前をつけておきます。
f:id:yakumo890:20210917162241p:plain
Hair_BをPony_Bに変更

2.5. ピッグテールのメッシュを分離する

次に、nasu_Pigtail_PCの方のピッグテールも分離します。
テールが2つあるので、片方のメッシュを選択した後にもう片方のメッシュも選択するようにします。そうすれば両方のテールが選択された状態になります。

f:id:yakumo890:20210917155444p:plain
ピッグテールを選択した状態
選択したメッシュ分離します。分離したメッシュには「Pigtail_tail_mesh」と名付けます。
メッシュはボーンに紐付いたままなので、これ以上は操作しなくて大丈夫です。

2.6. ポニーテールを結合する

次に、Pigtailにポニーテールを結合させます。

作業前にオブジェクトモードに移行しておいてください。
アウトライナーで、Ponytail_tail→Pigtailの順に選択し、3Dビューにマウスカーソルを乗せてCtrl-J*6を押下します。
Pigtailの階層にPonytail_tail_meshが移動し、Pigtail_boneの階層にPony_Bが移動しているはずです。

f:id:yakumo890:20210917163840p:plain
Pigtailの階層にすべてのオブジェクトが結合された

次に、ポニーテールのボーンを本体に接続します。 現在のポニーテールのボーンは本体とは離れていて、ポニーテールの部分が宙ぶらりんになっている状態です。そのため、本体とポニーテールを接続する作業が必要になります。

アウトライナーでPigtail_boneを選択して、編集モードに移行します。
ここで選択するべきボーンは近い位置にある(というより重なっている)ため、誤操作を避けるためにアウトライナーからボーンを選択するようにします。
選択するべきボーンは2つで、「Pony_B」と「Head」です。Headの場所は「Hips > Spine > Chest > Neck > Head」と階層をたどった場所にあります。
「Pony_B → Head」の順番で選択してください。

f:id:yakumo890:20210917164449p:plainf:id:yakumo890:20210917164500p:plain
Pony_BとHeadを選択(左)、選択されたときの3Dビューの状態(右)

2つのボーンが選択できたら、3Dビューにカーソルを乗せてCtrl-Pを押下し、「オフセットを保持」をクリックします。Headの階層にPony_Bが移動していたらOKです。

f:id:yakumo890:20210917164910p:plain
Headの階層にPony_Bが移動している

最後に、ポニーテールのメッシュとボーンを紐付けます。
オブジェクトモードに移行してください。アウトライナーPonytail_tail_mesh→Pigtail_boneの順に選択します。その後、3Dビューにカーソルを乗せてCtrl-Pを押下し、「空のグループで」をクリックします。
これにより紐付けが完了しました。

2.7. メッシュとボーンが紐付いていることを確認する

メッシュとボーンが意図したとおりに紐付いているか確認します。
メッシュとボーンが紐付いてる状態とは、ボーンを動かすと連動してメッシュも動く状態です。

まずは、ポーズモードに移行します。ポーズモードとは、ボーンを動かすことができるモードです。
アウトライナーでPigtail_boneを選択し、Ctrl-Tabを押下してください。そうすることでポーズモードになります。
ボーンを選択すると、そのボーンが水色になります。

f:id:yakumo890:20211001180739p:plain
ポーズモードでボーンを選択した状態
ボーンを選択したらRキー*7を押下します。そうすれば、マウスでボーンを回転できるようになります。
ポニーテールやピッグテールの根本のボーン(Hips > Spine > Chest > Neck > Head > Hair_BやPonyB)を選択して適当に動かしてみてください。髪の毛のメッシュも一緒に動けばメッシュとボーンが連動している状態です。
f:id:yakumo890:20210917170100p:plain
ポニーテールのボーン(Pony_B)を選択して動かした
左クリックでその位置にボーンを固定できます。また、クリックせずにEscキーを押下すればボーンを動かせる前の状態に戻ります。
今回は初期状態のままにしておくので、クリックはせずにEscキーを押してください。クリックしてしまった場合はCtrl-Zを押して戻してください。

2.8. モデルをエクスポートする

作成したモデルをFBX形式でエクスポートします。

Unityでの整合性を合わせるために、エクスポートする前にオブジェクトの名前を変更します。
「Pigtail」を「Armature」、「Pigtail_mesh」を「Body」に変更してください。

f:id:yakumo890:20210919201151p:plain
オブジェクトの名前を変更した

エクスポートは「ファイル > エクスポート > FBX(.fbx)」で行えます。適当な名前でFBXファイルを保存してください。本記事ではnew_nasu.fbxとします。

3. Avatar3.0に移行する

作業前にVRCSDK3.0-AVATARとユニティちゃんトゥーンシェーダー2.0、VRCAvatar3Toolsをダウンロードしておいてください。また、必要があればDynamic Boneを購入しておいてください。

3.1. Assetをインポートする

VRCSDK3.0-AVATAR、ユニティちゃんトゥーンシェーダー2.0、VRCAvatar3Tools、Dynamic Bone(必要であれば)、Tigri_Nasu、改変したなすちゃんのfbx(new_nasu.fbx)をインポートします。

それぞれ、Unitypackageファイルをダブルクリックすれば、現在開いているUnityプロジェクトにインポートできます。
メニューの Assets > Import Package > CustomPackage… からでもインポート可能です。
ここで、面倒を避けるためにTigri_nasuは他のUnitypackageを一通りインポートした後にインポートしてください。

Dynamic BoneはUnity Asset Storeで購入していれば、Package MangerからImportできます。

f:id:yakumo890:20211001185655p:plain
Package ManagerからDynamic Boneをインポートする

Tigri_Nasuをインポートした後、改変したfbxファイルをUnityプロジェクトにインポートします。
プロジェクトへのインポートは、エクスプローラーからファイルをプロジェクトにドラッグ&ドロップ(D&D)することでできます。

3.2. 改変したなすちゃんのモデルを設定する

改変したなすちゃんのモデルの設定を行います。

new_nasu.fbxを選択してInspectorでモデルの設定を行います。設定項目は「Model」、「Rig」、「Animation」、「Materials」の4つがありますが、それぞれ以下の画像のように設定してください。

f:id:yakumo890:20210919191900p:plainf:id:yakumo890:20210919191929p:plainf:id:yakumo890:20210919191936p:plainf:id:yakumo890:20210919191948p:plain
new_nasu.fbxの設定

上記の設定の後、「Rig」タブを開いて「Configure…」からボーンの設定を行います。
「Mapping」タグから、「Body」、「Head」、「Left Hand」、「Right Hand」の4項目を設定できます。今回の場合は「Head」以外は特に設定をしなくて良いです。「Head」は以下の画像のように設定してください。

f:id:yakumo890:20210919193301p:plain
RigにおけるHeadの設定

3.3. なすちゃんをAvatar3.0対応アバターにする

new_nasu.fbxのモデルをVRChat対応アバターにします。

まずは、Avatar3.0対応素体を生成します。
メニューからVRCAvatar3Tools > VRCAvatarConverterTo3を選択し、コンバーターを開いてください。
次に、「2.0 Avatar Prefab」の箇所で「nasu_Bou_PC」を選び、「Convert Avatar 3.0」をクリックします。

f:id:yakumo890:20211001190654p:plain
nasu_Bou_PCをAvatar3.0にコンバート
Hierarchyにnasu_Bou_PC_3.0が生成されたと思います。
コンバートした後は、nasu_Bou_PC_3.0に付いている「Missing」となっているコンポーネントを削除してください。

次に、new_nasuをHierarchyにD&Dし、Prefabをアンパックします。アンパックは、右クリックでコンテキストメニューを開き「Unpack Prefab Completely」をクリックで可能です。
nasu_Boud_PC_3.0の下にあるオブジェクトをすべて削除し、new_nasu配下にあるオブジェクトをすべて、nasu_Bou_PC_3.0の下に移動してください。

f:id:yakumo890:20210920163112p:plain
nasu_Bou_PC_3.0のオブジェクトを削除して、new_nasuのオブジェクトを移動する
移動した後はnew_nasuは削除して構いません。
説明を簡単にするために「nasu_Bou_PC_3.0」は「nasu」と名前を変えておきます。

次に、LipSyncの設定を行います。
現状では、「VRC Avatar Descriptor (Script)」コンポーネントの「LikpSync」の項目が不正になっているので、これを変更します。
「Face Mesh」にnasuの下にあるBodyをD&Dしてください。

f:id:yakumo890:20210920164328p:plain
FaceMeshにBodyを設定

これで、VRChat用アバターとしての最低限の設定は完了しました。

3.4. 髪型を変更するExpressionsを作成する

Expressionsで髪型を変更できるようにします。

まずは、Assetsの適当な場所(Tigri_Nasuの下にフォルダを作ると良いでしょう)で、「Expressions Menu」、「Expressions Parameters」を新規に作成します。これらは、コンテキストメニューのCreate > VRChat > Avatarsから作成できます。それぞれ、「NasuMenu」、「NasuParams」と名前をつけておきます。
これらをnasuに紐付けます。nasuの「VRC Avatar Descriptor (Script)」の「Expressions」に、「Menu」と「Parameters」を設定する項目がありますので、それぞれに「NasuMenu」、「NasuParams」を設定してください。

f:id:yakumo890:20210920173749p:plain
VRC Avatar DescriptorのExpressionsにMenuとParametersを設定

続いて、NasuParamsのパラメータを1つ増やします。
Inspectorの「Add」をクリックし、新しく生成された行を以下の画像のように設定します。

f:id:yakumo890:20210920195820p:plain
NasuParamsにパラメータを追加

パラメータを増やしたら、NasuMenuに髪型を変えるメニューを追加します。Inspectorの「Add Control」をクリックすることで、メニューが追加できます。以下の画像のように設定してください。

f:id:yakumo890:20210920195848p:plain
NasuMenuにメニューを追加

次に、アニメーションを作成します。
「Pigtail」というアニメーションを作成し、NasuにD&Dします。Animationウィンドウから、以下の画像のように設定します。

f:id:yakumo890:20210920181317p:plain
Pigtailアニメーションの設定
設定し終わったら、Pigtailアニメーションをコピーして、「Ponytail」という名前に変更します。
Ponytailのアニメーションは、Pigtailとは逆に、PonytailのIsActiveのみチェックを付けます。
f:id:yakumo890:20211001191320p:plain
Ponytailアニメーションの設定

続いて、Animation Controllerの設定を行います。
AssetsのTigri_Nasu > Animationの下に「vrc_AvatarV3HandsLayer_nasu_Bou_PC 1」というAnimation Controllerができていると思います。これを編集していきます。
見つからない場合は、nasuのVRC Avatar Descriptorコンポーネントの「Playable Layers」にある「FX」に設定されているオブジェクトをクリックしてください。

f:id:yakumo890:20210920192729p:plain
編集するべきAnimation Controller
Animatorウィンドウの、Layersタブでレイヤーを追加します。追加したレイヤーはTailと名付けます。
f:id:yakumo890:20210920194751p:plain
Animationレイヤー追加
追加したレイヤーの歯車マークを押して、Weightを1に設定します。
f:id:yakumo890:20210920194829p:plain
AnimationレイヤーのWeightを1にする
次に、Parametersタブでパラメータを追加します。追加するパラメータはIntで、名前をTailにします。
f:id:yakumo890:20210920194945p:plain
Animationパラメータの追加
Animatorウィンドウに先ほど作成したPigtailアニメーションとPonytailアニメーションをD&Dします。今回は、Ponytailアニメーションを先にD&Dしています。
f:id:yakumo890:20210920200757p:plain
AnimatorレイヤーにアニメーションをD&D
「Any State」を右クリックしてコンテキストメニューから「Make Transition」をクリックし、出てきた矢印をPonytailとPigtailに接続してください。
f:id:yakumo890:20210920201327p:plain
Any StateとPigtail、PonytailをMake Transisionで接続
生成したTransition(矢印)をクリックし、Inspectorから以下の画像のように設定してください。
f:id:yakumo890:20210920201930p:plainf:id:yakumo890:20210920201922p:plain
PonytailのTransitionの設定(右)とPigtailのTransitionの設定(左)

以上でExpressionsの作成は終了です。

Avatar3.0 Emulatorというツールを使うと、ExpressionsをUnity上で試すことができます。ここでの使用方法の説明は省略しますが、いちいちVRChatにアップロードせずともExpressionsが確認できるため便利なので利用してみてください。

3.5. マテリアルの変更

現状だとnasuのシェーダーはUnityの標準のシェーダーになっており、本来の見た目になっていない(はず)です。そのためマテリアルを変えてあげます。
BodyとPigtail_tail_meshには「nasu_Pigtails_PC」を、Ponytail_tail_meshには「nasu_Ponytail_PC」をそれぞれD&Dで適用してください。これらのマテリアルは、Assets > Tigri_Nasu > Materialsにあります。

3.6. DynamicBoneの設定

※DynamicBoneを利用しない場合は、この項目は飛ばして良いです。

ピッグテールとポニーテールにDynamicBoneを設定します。
はじめに、nasu_Pigtail_PC(Prefab Asset)とnasu_Ponytail_PC(Prefab Asset)をHierarchyにD&Dします。
D&Dしたnasu_Pigtails_PC及びnasu_Ponytails_PCにはDynamic Boneのコンポーネントが付いていますので、それらをnasuにコピーしていきます。
コンポーネントのコピーは、コンポーネントのタイトルを右クリック(もしくは、右端にある「…」を縦にしたようなマークをクリック)して、コンテキストメニューを開き「Copy Component」をクリックすることによってできます。

f:id:yakumo890:20211001192126p:plain
コンポーネントのコピー
一方、コンポーネントのペーストは、ペースとしたいオブジェクトが持つコンポーネントの1つ(どれでも良い)のコンテキストメニューから、「Paste Component As New」をクリックすることによってできます。
f:id:yakumo890:20211001192155p:plain
コンポーネントのペースト
ここでコピーするDynamic Boneのコンポーネント4つです。
3つはnasu_Pigtails_PCが持つすべてのDynamic Boneコンポーネントで、最後の1つは、nasu_Ponytail_PCが持つ、「Root」に「Hair_B」が設定されているDynamic Boneコンポーネントです(以下の画像を参照)。
f:id:yakumo890:20210921235946p:plain
nasu_Ponytail_PCからコピーするべきDynamic Boneコンポーネント

コピーしてきたこれらのDynamic Boneコンポーネントは、コピー元のボーンを参照しているため、ボーンの参照先を変える必要があります。Dynamic Boneが参照しているボーンはコンポーネント内の「Root」に設定されているボーンです。
まずは、「hair.F」、「hair.F.002」を参照しているDynamic Boneは、nasuが持つ同名のボーンオブジェクトを参照させるようにします。
次に、nasu_Pigtails_PCからコピーしてきた「Hair_B」を参照しているDynamic Boneは、nasuの「Hair_B」を参照させるようにします。
最後に、nasu_Ponytails_PCからコピーしてきた「Hair_B」を参照しているDynamic Boneは、nasuの「Pony_B」を参照させるようにします。

f:id:yakumo890:20210922001425p:plainf:id:yakumo890:20210922001437p:plainf:id:yakumo890:20210922001506p:plainf:id:yakumo890:20210922001522p:plain
nasuのDynamic Boneコンポーネント

シーンをプレイし、nasuを適当に左右に動かしてみてください。テールが揺れればDynamic Boneの設定は終了です。

3.7. VRChatにアップロードする

以上でアバターの基本的な設定は完了したので、アップロードしてください。
ここではアップロードについての説明は省略します。

Quest対応について

ここまでの説明はPC用アバターでの説明になります。
Quest用アバターで行いたい場合は、同様の手順をQuest用のなすちゃんに適用してください(QuestではDynamic Boneやユニティちゃんシェーダーが利用できないので、その手順は飛ばしてください)。

おわりに

なすちゃん改変の方法を備忘録的に記述しました。
見様見真似でやったのでもっと良い方法があると思っています(特にBlenderの分離と結合)。もし、もっと良い方法を知ってるという方はぜひ教えて下さい。

今回は単に髪型を切り替えるようにしただけですが、VRCのアバターは他にもたくさんのことができます。
VRCのアバター改変は楽しいので皆さんも色々改変してみましょう。

参照したページ

*1:選択の全解除という操作

*2:リンク選択という操作

*3:分離という操作

*4:アレントを作成という操作

*5:本当はウェイトをちゃんと設定すべきなのかもしれませんが、筆者が試したところ自動ウェイトでも特に問題はありませんでした

*6:結合という操作

*7:回転

シン・エヴァンゲリオン感想

※ 本記事はシン・エヴァンゲリオン劇場版のネタバレを多分に含みます。

本記事では「旧作」を「新世紀エヴァンゲリオン劇場版 Air/まごころを、君に」と定義する。
また、本記事は自己理解に依る記述があることをご了承願いたい。

総評

僕はシン・エヴァンゲリオンを高く評価している。それは以下の2つの理由による

各人の幸せがおおよそ可視化されたこと、について

旧作でのシンジは補完計画の中心として、他人への恐怖を覚えぬ世界(補完計画の完成)か、いままでと同じく他人への恐怖を抱く世界(補完計画の否定)かのどちらかを選ぶことになる。他者を恐れる彼が己と向き合った末に、「他者とはわかりあえるかもしれない」と補完計画を否定しその先へと足を踏み入れた。そしてその先にあったのは他者からの(への)拒絶である。彼は幸せへの道筋を見たかも知れないが幸せを掴んだわけではなかった。ゲンドウはシンジと同じように他人を恐れていてシンジとわかりあえずユイとの再開を果たせぬまま殺された。アスカは結局誰かの承認を得ることなく、エヴァシリーズに惨敗したのだからたまったものではないだろう。
さて、今作でのシンジは他者の幸せを自身の幸せと確信し、補完計画の中心として他のエヴァパイロットの幸せを望み、エヴァが必要のない人が人らしく生きられる世界を望んだ。その結果としてアスカは拠り所を見つけ、カヲルも自身の幸せはシンジの幸せと理解した(レイについては正直良くわからなかった。シンジがエヴァに乗らなくて良いようになったから良いのかな…)。 また、シンジは同じように他者を拒絶してユイに依存していたゲンドウと対話することで、彼の幸せを引き出した。そしてゲンドウは最後にユイの開放を成し遂げたのだ。
こうしてそれぞれの幸せが可視化されていたことに僕は満足を覚えた。
その一方で、ミサトは惜しかった。彼女はシンジに重責を負わせたことを悔やみ続けており、その経験もあってか息子から遠ざかる道を選んだ。最終的にシンジが立ち直り自ら贖罪のためエヴァに乗る決意をしたこと、そして自身の願いを彼に押し付けるのではなく託すことができたことで彼女はその重荷を下ろすことができた。しかし、最終的に自ら一方的に縁を切った息子への後悔は拭えずに終わってしまったのだから。
ここまでぐだぐだ書いてて気づいたが、結局の所、僕はシンジが幸せを掴むことができたことが嬉しかっただけなんだろうな。

エヴァンゲリオンと決別したこと、について

副題にもある通り、本作はエヴァンゲリオンの決別を描く作品であった。それは劇内の「兵器」としてのエヴァンゲリオンだけでなく、「作品」としてのエヴァンゲリオンも含意する。 本作で語られているのは、旧作の世界も本作の世界も、とあるゴールに向かう輪廻の一部であるということである。これの意味するところは、シン・エヴァンゲリオンは旧作の完結も描いたということだ。もちろん、旧作が終わっていなかったという話ではなくて、あれはあれで一つの終局の形である。しかし、監督としても後ろ向きな終局だけでない終局がほしかったのだろう。 序から始まる新劇場版はTVシリーズと旧作の流れを無視して完全に新規に作ることもできたろう。しかし、そうではなく新規に作り直すどころか旧作を一部として取り込んでいる(プロジェクトが立ち上がった段階でどのくらい意図されていたかは不明だが、結果としてそうなったのだ)。監督が旧作を踏まえたこと(旧作への未練すら感じることができたこと)やもう一度終局へと導いてくれたことに、旧作を何回と見直した僕は深い感銘を受けたのだ。
(ここで旧作の終局を否定的に書いているようであるが、僕はあれも好きである。心の壁がある限り他者への恐怖が潰えることはないが、シンジはやや前を向いたのだから)

映画の最後にスクリーンの右下に表示された「終劇」の文字は、僕に晴れやかな気持ちをもたらしてくれたのだ。ああ、すべてが終わったのだと。

エヴァンゲリオンを初めてみたのは中学生の時だった。TVシリーズを何週か見たがあまり良くわからなく、登場人物は嫌いな奴らばかりだった。旧作も10回以上は見たと思うが、あの終局に納得いっているのか自分でもよくわからなかった。結局、エヴァンゲリオンという作品が好きか嫌いかわからずにいた。
でも、シン・エヴァンゲリオンを見てはっきりした。エヴァンゲリオンという作品を知れて良かった、と。

ありがとうエヴァンゲリオン

雑感

  • トウジとケンスケが生きてるの嬉しくなっちゃったし、トウジが医者やってるのも委員長と結婚してるのも良すぎる
  • ケンスケがうつ状態シンジに対してあまり干渉することなく、何もせず何も言わずにいる状態も「今はそれでいい」と認めてくれるの優しいし、トウジは初号機のせいで妹怪我させられてて更に親をも失っているのにも関わらずシンジの生還を心から喜ぶのも器がでかくて泣いちゃう
  • シンジの自己評価の低さと他人の優しさとのギャップでめちゃくちゃ苦しむの、正直気持ちがわかってしまうので見てて辛かった
  • 最初の戦闘シーンから一変して、旧に文化レベルが下がった村での無知で無垢な綾波(のそっくりさん)が農業をするシーン、カントリーな音楽と相まって見ててめちゃめちゃ気持ちよかったな、エヴァンゲリオンでこんな爽やかなシーンが見れるとは
  • 綾波(そっくりさん)が村での生活の中で色んな人たちと触れ合って人間らしくなっていくの良すぎるし、見てて正直めちゃめちゃかわいかったな。エヴァのキャラをかわいいって思ったこと全然なかったんだけど、綾波かわいかった
  • シンジに対して泣きつくサクラに、アスカが女房かよって突っ込むの普通に笑っちゃった
  • 命の恩人であり親の仇でもあるシンジのことを憎んでるんだけど完全に敵視してるわけでもなくて、シンジが苦しい思いもするのも嫌なんだけど、エヴァに乗るとシンジも自分らもろくなことにならなそうだからエヴァだけはどうしても乗ってほしくなくて、っていう複雑な思いを処理できず混乱してるサクラが本当にいたたまれなかった…
    • なんかサクラは言動が理解できなくてやべー女扱いされてめちゃくちゃ人気が出てるらしくて笑ってしまった。わかる…
  • シンジがエヴァに乗るって言ってるのに「碇さんはエヴァには乗りません」って断言するサクラにめっちゃ違和感あって、見終わったあとに気づいたんだけど、(いまから怪我させてエヴァを操縦できないようにするから)碇さんはエヴァには乗らんのです、ってことか。やべぇ…
  • 最終的にサクラがどうなったか教えてほしい
  • ヤマト作戦が始まったあとの、砲撃とか言って戦艦撃ち出すのとかエヴァなんとかシリーズとか言って無限にエヴァが出てくるのとかいきなり槍作り出すのとかシンクロ率が無限大になるとか、そういうスケールのデカさで解決する感じにガイナックスの息を感じてしまう。シン・グレンラガン
  • マイナス宇宙で量子テレポート繰り返すゲンドウ、字面と絵面がシュール過ぎて笑うだろあんなの。やりたい放題にも程がある
  • アスカのコピーを作ったの、使徒化したアスカを補完計画に利用するとかの色々な目的があるんだろうけど、「惣流・アスカ・ラングレー」から「式波・アスカ・ラングレー」への名前を変更したことへのメタファーと言うか手向けと言うか、とにかくそういうのを感じてしまう
  • ゲンドウがリツコに撃たれるのめっちゃ良い。旧作でリツコがゲンドウに撃たれて死んだのと対比になってる
    • 他にもそういう旧作のオマージュみたいなのたくさんあって見てて気持ちよかった
  • シンジとゲンドウがエヴァに乗って色んな場所でチャンバラし始めたときは、これこれこれこれこれこれなんだよな~、これが見たかったんだよな~、ってめっちゃ興奮してしまった。
  • 初号機が自分と十三号機を貫いたあとに、色んなエヴァが串刺しにされていくシーン、やりたいことはわかるんだけどダサくて笑った
  • リリスの顔面の綾波が普通に気持ち悪くて嫌だった。旧作はでかい以外普通の綾波だったじゃん、あれみたいな感じじゃダメなの
  • 真希波・マリ・イラストリアス、結局どういう存在なのか全然わからんかった、なんで日本に不法侵入したかわからんし、NERVでエヴァパイロットやってた理由もWILLEについた理由もわからなすぎる、あの女なんなんだ~
    • そもそも年齢はいくつなんだ。エヴァパイロットだとするとシンジと同年齢になると思うんだけど、ゲンドウの回想に出てきてんだよな。そうなるとシンジよりだいぶ年上になる気がする。ゲンドウと一緒に居たのがマリの母親だったとか考えた場合、冬月を「先生」呼ばわりしてるのが納得いかないし…
  • イスカリオテのマリアって名前めちゃくちゃしびれてしまった。救世主を産みし者と救世主を裏切りし者の名前の融合
    • 補完計画の中心を救世主と考えた場合、もともと補完の中心としてエゴを達成しようとしたゲンドウを裏切り(裏切りって言い方はちょっと違うかもしれんが)、新たな補完計画の中心であるシンジを導いたマリを表してるなって思った
  • マリがシンジを迎えに行くシーンの絵コンテのやつとか、エンディングの実写のシーンとか、旧作のセルフパロディと言うか自虐みたいに見えてしまうのは穿った見方だろうか
  • 最後の見せ場で帽子を脱ぎサングラスを外し髪を解いたミサト、かっこよすぎんだよ。ミサトめちゃくちゃいい女だ
    • BGMが完全にAerosmithのI Don't Want to Miss a Thingだったな
  • この結末を導くにあたっていくつか強引なところもあったとは思う。シンジはカヲルとの死別と自身の過失から立ち直る必要があったが、その立ち直りがあまりにも急すぎた(きっかけが綾波コピーの言葉しかないように見え、きっかけとしては弱いように見える)し、WILLEや第三村の人たちも崩壊した世界を受け入れて前進しようとしていた(絶望のコンティニュー)のにもかかわらず、シンジは槍の力で世界を書き換えてしまった。よって(当然ではあるが)すべての人が望んだ世界にはなっていないだろう。
    • 目の前で綾波を失っても凹まず最終的にヴンダーに乗るとか言いだすシンジ、急に強くなりすぎだろ。何があったんだよ

C97で新刊出します(サンプルあり)

やくもです。

サークル「山梨のけんざかい」としてC97にサークル参加します。

今回は、弊サークルで作成している「森久保が学ぶ確率論」シリーズの新刊を出します。

「森久保が学ぶ確率論」とは

このシリーズは、「アイドルマスターシンデレラガールズ」に登場する「立てば芍薬座れば牡丹歩く姿は菊の花」を体現したようなアイドルの「森久保乃々」に数学を教えてあげるなら、という妄想を読み物にしたものです。
内容は、確率論について対話形式で解説していくといったものです。
森久保乃々は14歳であるため、内容はそこまで高度にしていない(つもりです)ので、確率論・統計学に造詣が深い方には物足りない内容かなとは思います。

新刊について

シリーズ新刊は、「森久保が学ぶ確率論 ~ランダムウォーク~」というタイトルになります。 表紙はこんな感じです。

本文の内容はこちら。

タイトルの通り、基礎的な確率過程であるランダムウォークについて書いています。
サンプルのPDF(Dropboxリンク)を本記事の最後に添付します。どうぞご覧ください。
値段は600円(予定)です。
興味を持っていただけたら、ぜひ「山梨のけんざかい」まで遊びに来て下さい!

頒布情報

サークル名: 山梨のけんざかい
日時: 12月30日 月曜日(3日目)
場所: 南地区 ヘ-38b

頒布物:

  • 森久保が学ぶ確率論 ~ランダムウォーク~(新刊)
  • 森久保が学ぶ確率論 ~分布と密度~(既刊)

※既刊は余りのみを持っていくので、数量は新刊より少ないです。

サンプル

リンク先から新刊、既刊のサンプルPDFを閲覧できます。
本PDFの内容、テキスト、画像等の無断転載・無断使用はご遠慮ください。

新刊

drive.google.com

既刊

drive.google.com

C96で新刊出します(サンプルあり)

やくもです。

サークル「山梨のけんざかい」としてC96にサークル参加します!

今回は、弊サークルで作成している「森久保が学ぶ確率論」シリーズの新刊を出します。

「森久保が学ぶ確率論」とは

このシリーズは、「アイドルマスターシンデレラガールズ」に登場するめっちゃかわいいアイドルの「森久保乃々」に数学を教えてあげるなら、という妄想を読み物にしたものです。
内容は、確率論について対話形式で解説していくといったものです。
森久保乃々は14歳であるため、内容はそこまで高度にしていない(つもりです)ので、確率論・統計学に造詣が深い方には物足りない内容かなとは思います。

このシリーズは、過去にC94にて以下の2冊頒布しています。

  • 森久保が学ぶ確率論 ~確率論の基礎~
  • 森久保が学ぶ確率論 ~共分散の基礎~

ちなみにC92で、このシリーズの原点となる本を頒布していますが、それをリメイクしたものが上記の「~確率論の基礎~」です。

新刊について

シリーズ新刊は、「森久保が学ぶ確率論 ~分布と密度~」というタイトルになります。 表紙はこんな感じです。

本文の内容はこちら。

  1. 確率分布とは
  2. 二項分布
  3. 確率分布の性質
  4. 標準偏差と偏差値
  5. 正規分布
  6. 極限
  7. 確率密度関数
  8. 大数の弱法則

だいぶ仰々しい内容だと思いますが、そこまで深く掘り下げていなく表面をなぞる感じで書いています。
本作は「~確率論の基礎~」の内容を踏まえています。しかし、こちらの内容を読んでいなくても、場合に数による確率の計算、期待値、分散の基礎知識があれば読めると思います。
サンプルのPDF(Dropboxリンク)を本記事の最後に添付します。どうぞご覧ください。
値段は600円(予定)です。
興味を持っていただけたら、ぜひ「山梨のけんざかい」まで遊びに来て下さい!

頒布情報

サークル名: 山梨のけんざかい
日時: 8月11日 日曜日(3日目)
場所: 西地区 お-27b

頒布物:

  • 森久保が学ぶ確率論 ~分布と密度~(新刊)
  • 森久保が学ぶ確率論 ~確率論の基礎~(既刊)
  • 森久保が学ぶ確率論 ~共分散の基礎~(既刊)

※既刊は余りのみを持っていくので、数量は多くないです。

サンプル

リンク先からPDFを閲覧できます。
本PDFの内容、テキスト、画像等の無断転載・無断使用はご遠慮ください。

drive.google.com

エラー処理のエラー処理

ちょっとした小話。

RtlNtStatusToDosError

RtlNtStatusToDosErrorという関数がある。NTSTATUSをWin32のエラーに変換する関数だ。
こいつをエクスポートしているのはntdll.dll、つまり明示的リンクからのアドレス取得という処理が必要になる。

using _RtlNtStatusToDosError = ULONG(*)(const NTSTATUS Status);
auto hNtdll = GetModuleHandle(L"ntdll.dll");
auto RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(hNtdll, "RtlNtStatusToDosError");
auto err = RtlNtStatusToDosError(STATUS_UNSUCCESSFUL/*=0xC0000001*/);

ところで、RltNtStatusToDosErrorのラッパー関数を作ったとしよう。

ULONG NtStatusToDosError(NTSTATUS Status)
{
	using _RtlNtStatusToDosError = ULONG(*)(NTSTATUS Status);
	auto hNtdll = GetModuleHandle(L"ntdll.dll");
	auto RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(hNtdll, "RtlNtStatusToDosError");
	return RtlNtStatusToDosError(Status);
}
エラー処理のためのエラー処理

上記コードは一見良さそうだが、よくよく考えるとGetModuleHnadleだってGetProcAddressだって失敗することがある。
つまり、この関数自体が失敗したことを想定することもできる。
じゃあ、この関数を改変して、返り値を関数が成功したかどうかにし、GetLastErrorでエラーを取得できるように変更しよう。

BOOL NtStatusToDosError(NTSTATUS Status, ULONG* DosStatus)
{
	using _RtlNtStatusToDosError = ULONG(*)(NTSTATUS Status);
	auto hNtdll = GetModuleHandle(L"ntdll.dll");
	if (hNtdll == NULL)
	{
		SetLastError(GetLastError()); //わざわざこんなことをする必要はないがわかりやすさのため
		return FALSE;
	}

	auto RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(hNtdll, "RtlNtStatusToDosError");
	if (RtlNtStatusToDosError == NULL)
	{
		SetLastError(GetLastError());
		return FALSE;
	}

	*DosStatus = RtlNtStatusToDosError(Status);
	return TRUE;
}

これで、失敗したときの備えも出来た。

でも、RtlNtStatusToDosErrorの用途の殆どはエラー処理である。
上記のコードを書いた場合、エラー処理中に別のエラー処理をする必要があることになる。
下手すれば永遠にエラー処理することになるんじゃないか。

余計な心配はしなくていい

とてもとても元も子もないことを言うが、今回のコードに関しては余計なエラー処理はいらないはず。

まず、GetModuleHandle(L"ntdll.dll")についてだが、ntdll.dllはWindowsのプロセスなら必ずロードされる。
そのため、ハンドルが取れないなんてことはないはずだ。
万が一こいつが失敗した場合、LoadLibraryを使ってntdll.dllをロードすればいい。流石にWindowsでntdll.dllが環境に存在しないなんてことはないはずだ。
少なくともXPの時代からあるDLLであるし、Windows10にもある。kernelbase.dllやadvapi32.dllのようにwindowsのバージョンアップに伴い増えたシステムのDLLはあれど、
システムのDLLが減るということはありえないんじゃないか。ましてや、ntdll.dllはシステムコールを含んでる。こんなDLLをWindowsのバージョンアップで消し飛ばすわけがない。

次に、GetProcAddressだが、エクスポート関数を増やすことはあっても消すことはないだろう。
だから、エクスポート関数のアドレスが取れないことはないんじゃないか。

ただ不安があるとすれば、ntdll.dllのエクスポート関数は基本的に非公開関数だということ。
非公開関数は公開関数とは違い、使用するユーザに全責任がかかる。仮に、関数のインターフェースをMicrosoftが勝手に変更してプログラムがクラッシュしてもMicrosoftに非はなくユーザは泣き寝入りすることになる。
(まあ、そのためのInsider previewなのだろう)
RltNtStatusToDosErrorはまだ明確にドキュメント化されている(RtlNtStatusToDosError function (Windows))し、インターフェースもシンプルだから
NtCreateProcessやNtCreateFileなんかよりはインターフェースの変更の可能性が限りなく低い。
GetProcAddressが失敗する心配はないだろう。

結局こんな感じでいい。

ULONG NtStatusToDosError(NTSTATUS Status)
{
	using _RtlNtStatusToDosError = ULONG(*)(NTSTATUS Status);
	auto hNtdll = GetModuleHandle(L"ntdll.dll");
	if (hNtdll == NULL)
	{
		hNtdll = LoadLibrary(L"ntdll.dll");
	}

	auto RtlNtStatusToDosError = (_RtlNtStatusToDosError)GetProcAddress(hNtdll, "RtlNtStatusToDosError");

	return RtlNtStatusToDosError(Status);
}

なによりも普通にコーディングしてて、Rtl~を呼び出すことなんてない。

最後に

勝手に問題を提起して勝手に解決し、挙句の果てに不必要な議論だったことにしてしまった、変な記事になった。
今回やりたかったのは、エラー処理のためにエラー処理が必要になる場面に遭遇した時どうするんだっていう、まあ一種の思考実験なわけだ。
…実際にそんなシチュエーションあるかわからんけど。

こうしてまたこの世から、

この広告は、90日以上更新していないブログに表示しています。

を1つ消し飛ばした。90日間限定だけど。

シンデレラ5thツアーについて

やくもです。
8/13をもって、「THE IDOLM@STER CINDERELLA GIRLS 5thLIVE TOUR Serendipity Parade!!!」全公演が終了しました。今回はその感想を簡単に話したいと思います。

さて、5thツアーのテーマは「奇跡の大行進」でした。
今回のツアーでは、開演時に旗を持ったアイドルたちが曲に合わせてパレードを行うという演出が一貫して行われました。これが「大行進」の由来であります。
では、今回のツアーにおいて「奇跡」とは何だったのでしょうか。
自分は次の2つだと思っています。

  1. 新しいアイドルの参加
  2. オリジナルのいない楽曲の披露

それぞれについて自分の考えを述べたいと思います。

新しいアイドルの参加

今回のツアーでは、千秋楽であるSSA公演Day2以外には周年ライブ初参加のアイドルがいらっしゃいました。

公演 初参加アイドル
宮城 早坂美玲、難波笑美及川雫
石川 森久保乃々、佐藤心
大阪 椎名法子道明寺歌鈴
静岡 脇山珠美
幕張 三船美優、水本ゆかり
福岡 依田芳乃、上田鈴帆
SSA Day1 浜口あやめ十時愛梨

公演を重ねるごとにどんどんアイドルが増えていくこの様子が、奇跡の一つだと思っています。
少し、4thライブSSA公演1日目「brand new castle」の話をします。この公演ではサブタイトルの通り比較的新参のアイドルたちが舞台を披露していました。周年ライブに初期から参加されていたアイドルや、アニメで活躍されていたアイドルがほとんどいないこの公演は、"誰もがシンデレラ"であるシンデレラガールズのすそ野の広さを表すものでした。
5thツアーでたくさんの初参加アイドルが登場したことは、brand new castleが示唆したメッセージを実地に表すものだったのではないでしょうか。

第6回総選挙で5人のアイドルが新たに声がつくことが決まっていますし、CINDERELLA MASTERもこれからまだまだ制作されて新たなアイドルに声が付くと思います。美玲のようにサプライズボイスが付く可能性もあります。これからもどんどんライブに出ることができるアイドルが増えていくでしょう。
まだまだアイドルが増えていくことがシンデレラガールズの趨勢であり、増えていけることが奇跡なんだと思います。

これからもプロデューサーとしてファンとしてアイドルが増えていく様子を見届けていきたいものです。

オリジナルのいない楽曲の披露

公演中に何度も、オリジナルのアイドルを抜きにした楽曲の披露が行われていました。以下にいくつか例を載せます。

楽曲 披露したアイドル オリジナル
私色ギフト 宮本フレデリカ、森久保乃々、佐藤心龍崎薫 城ヶ崎美嘉城ヶ崎莉嘉諸星きらり赤城みりあ
Wonder goes on!! 松永涼椎名法子塩見周子片桐早苗 前川みく多田李衣菜安部菜々木村夏樹
心もよう 脇山珠美大和亜季、乙倉悠貴 島村卯月渋谷凛本田未央
この空の下 双葉杏、橘ありす、塩見周子 アナスタシア、新田美波神崎蘭子

自分は、このオリジナルがいない楽曲こそが今回のツアーで重要な要素の一つであり、奇跡の一つだと思っています。

この公演を通して、シンデレラガールズの楽曲は誰にでも歌えるということを示したのではないでしょうか。
ツアーの中でのおそらく一番の目玉であった、DJぴにゃによるメドレーは特にそのことを表していたと思います。森久保乃々の「あんずのうた」、神谷奈緒の「Never say never」、上条春菜の「おねだりShall we~?」、向井拓海の「Can't stop!!」、new generationsの「Trancing Pulse」...、と様々なリミックスが披露されました。
アニメ円盤の特典に、CINDERELLA PROJECTのソロ曲を他のメンバーがソロリミックスをするというCDがついていました。それは序の口で、新たなソロリミックスが今回のメドレーで聞くことができました。さらに、new generationsのTrancing Pulseのような、オリジナルメンバー以外は歌わないと思われていたような楽曲も容赦なく他のメンバーによって披露されました。これはまさしく奇跡と言えるでしょう。
シンデレラガールズは、これからもどんどん楽曲が増えていきますが、こういった"多様性"が見られるのもシンデレラガールズの大きな魅力であると思います。これからも様々な楽曲が聴けることを楽しみにしましょう。

おわりに

奇跡の大行進は、埼玉に旗を着地させることによって完遂されました。自分は7公演(厳密には石川2日目以外)を現地及びLVで参加しましたので、宮城から次々に旗が渡されていく様子と、最後に着地する様子をこの目で見ることができました。各地で公演をするために頑張ってきたアイドルたちの思いが詰まった大行進を最後まで見届けることができて本当に感無量でした。

また、自分はこの4ヶ月間、ほぼほぼライブとコミケのために生きてきたので、このライブが終わったあとは虚無感に包まれて、なにもできなくなるのではないかと思っていました。しかしライブを終えて感じたのは、奇跡の大行進の終わりがシンデレラガールズの終わりではないということ。シンデレラガールズモバマスデレステを中心としてコンテンツが展開していきますし、今年の10月にはシンデレラ劇場のアニメも始まります。6周年記念イベントもあれば、単独ドームライブの開催も決定されました。
シンデレラガールズはこれからもどんどん展開し、アイドルたちはどんどん前へと進んでいきます。「昨日の目的地、明日には通過点」という歌詞の通りです。自分一人が足を止めている場合ではありません。自分も今までと同じように自分の人生を歩んで、またアイドルたちに会いに行くだけです。

最後に、今回の公演で奇跡を見せて下さったアイドルの皆様、スタッフの皆様、シンデレラガールズを盛り上げてくださったプロデューサー・ファンの皆様、一緒にライブを見に行った友人の皆様にはこの場で感謝の気持ちを述べたいと思います。

本当にありがとうございました。




エスセレンディピティ