
3step+αで作る光源ライト(vcrhatアバター, MA使用)
※コンテンツ部分はすべて無料で最後まで読めます。
はじめに
先日以下の製品をboothで出品しました。
今回はこのギミックの内部実装についての記事となります。
3stepで作る簡易版は約1500文字、+αを含めた全体像は約7500文字となります。(「1500文字+7500文字とか読む気しねえよ」という人は↑を購入いただくとこの記事の内容がすべて実現できます。(マ))
対象読者
・vrchatをプレイしていて、ある程度アバター改変を行う知識・環境がある
・ライトギミックの内部実装に興味がある
3stepで作る光源ライト
大言壮語なタイトルにしていますが機能の根幹をなすライト部分は本当に簡単に実装できます。
ここではアバターに光源ライトを組み込み、ライトオンオフのExメニューを設定して、Exメニューからライトをオンオフする。というところまでを以下の3stepで作ります。
ライトコンポーネントをつける
ライト位置調整
AvatarMenuCreator for MAでExメニュー設定
ライトギミックを実装したいアバターはunity上で開いておいてください。
それとModularAvatarとAvatarMenuCreator for MAを使うので導入は済ませておいてください。(step 0)

step 1 ライトコンポーネントをつける
ヒエラルキー上でアバタールートを右クリック→空のオブジェクトを作成を選択して空のオブジェクトを作ります。名前はLightにします。

コンポーネントを追加からLightを選択します。
パラメータがいろいろありますが今回はタイプはポイントで、範囲、色、強さはお好みで設定します。
例では範囲50、色は白、強さは3としています。(そこそこ強めの光源を想定)

また、ライトを追加するとシーン上に電球マークが表示されることも確認してください。表示されない場合は右上のギズモの表示をオンにしてください。

この時点でシーンをよく見ると、アバターが照らされていることが分かります。(強さの数値を大きくして、顔や服付近に持ってくると分かりやすい)
step 2 ライト位置調整
光源の中心となる位置を決めます。今回は右手の手のひらの上に光源を出すことを考えます。右手に追従してほしいのでコンポーネントを追加からMA Bone Proxyを追加します。

配置モードを一度「子として・ルートに配置」に変更に変更するとTransformに対象ボーンと同じ座標が代入されるので、そこから位置調整するのが良いと思います。「子として・ワールド位置と向きを維持」に変更してから位置を調整してください。

step 3 AvatarMenuCreator for MAでExメニュー設定
コンポーネントを追加からAvatar Toggle Menu Creatorを追加します。(AvatarMenuCreator for MAの使い方の項目にある「Tools」→「Modular Avatar」→「AvatarMenuCreater for Modular Avatar」から進めても問題ありません。)
オブジェクトを追加からLightオブジェクトを追加し、ON=表示にします。ついでにお好みでそれっぽい画像を用意してアイコンに設定します。

設定したらMA Menu installerを追加を押します。(既にMA Menu installerがついている場合は必要ないです。)
動作確認
以上で作業は終了です。
最終的にLightオブジェクトに
Transform(配置したい場所の座標が代入されている)
Light
MA Bone Proxy
Avatar Toggle Menu Creator
MA Menu installer
がついていればOKです。
プレイモードで確認してみましょう。
まずGestureManagerでExメニューを確認すると、メニューが追加されています。

そしてこのメニューをオンオフするとライトがオンオフします。


問題なさそうならアバターアップロードしてvrchat内で確認してみてください。
以上でライトの実装は完了となります。
お疲れさまでした。
これで暗いワールドやホラーワールドも怖くないですね!(※ワールドの光源設定が変更されていて、アバター組み込みのライトが無効化されている場合もあるため、どのワールドでも機能するというわけではありません。)
+α
はい。ここまでで「とりあえず暗いワールドを照らしたいんだけど」という需要に対して一応使えるものをサクッと作りました。ここからは+αです。
以下で販売しているギミックに実装されている機能をもう少し見ていきます。
機能
・ガラス球オンオフ
中心の確認用ガラス球モデルの表示をオンオフします。
ライトオンオフには影響しません。
・ライトオンオフ
ライトがオンオフできます。
・ローカル化
光源効果を自分だけに適用します。
・強度調整
無段階調整メニューにて設定可能(弱~強)
・色相調整
無段階調整メニューにて設定可能(白, 赤←色相変化→紫)
ここまでで「ライトオンオフ」は作成しましたが、他の機能も実装するとなるともう少し構造を考える必要があります。(※「ガラス球オンオフ」についてはこの記事では触れません(ガワの話なので))。
以下からこれらの機能がどう作られているか解説していきます。
prefab構造について
光源ライトギミックのprefabを見ると、以下の構造になっています。

Assetsのディレクトリ構成については販売ページにあるので合わせて確認ください(マ)。
Lightオブジェクトの配下にGlassSphere(ガラス球モデル)とPointLightオブジェクトがあります。正直構造はいろいろ模索中なのですが、重要なことはこの後作成するアニメーションファイルは、ヒエラルキー上の構造をもとに対象を探索するので途中で構造を変更すると面倒なことになります。なりました。
(余談:prefab直下のオブジェクトのTransformは原点にするのがマナーが良いらしい。Bone Proxyで動かすものも階層を深くして、prefab全体を動かさない方が良い?)
今回はLightオブジェクトにMA関連のコンポーネントを付与し、PointLightオブジェクトにはLightコンポーネントのみ付与します。
まず上画像のように空のオブジェクトとしてLightオブジェクトを作り、その配下にPointLightオブジェクトを作ります。3stepで作成したコンポーネントについて、
Transform→Lightオブジェクトの座標に採用、PointLightはすべて0
Light→PointLightオブジェクトに付与
MA Bone Proxy→Lightオブジェクトに付与
Avatar Toggle Menu Creator→削除
MA Menu installer→Lightオブジェクトに付与
と移動させます。コンポーネントのコピーや値のコピペを活用すると楽にできるかと思います。
それとAssetsの方で、これから作成するものを置いておくディレクトリをテキトーに作っておきます。こちらのパスは融通が効くので分かる場所ならどこでもいいです。以後、このディレクトリをワークディレクトリと呼びます。
Animator作成(ローカル化について)
ワークディレクトリで右クリック→作成→アニメーターコントローラーから空のAnimatorを作ります。名前はPointLightとします。(オブジェクト名と紛らわしいですがアイコンと拡張子で判別できます。)
アニメータータブのパラメータータブを選択し、画像のようにパラメータを作成します。

light_state: bool型、ライトオンオフを制御するための変数
light_color: float型、ライトの色を制御するための変数
light_intensity: float型、ライトの強さを制御するための変数
light_is_local: bool型、ローカル化の機能を制御するための変数
IsLocal: bool型、vrcsdk組み込みの変数、ローカル化に関係する
大文字小文字は区別されるので注意してください。(小文字のエルと大文字のアイにも注意)
次にレイヤータブに移り、ステートマシンのガワだけ作成します。(アニメーションファイルをまだ作っていないので各ステートに割り当てるべきアニメーションファイルが存在しないため。)
LightOnOffレイヤーとLightColorレイヤーを新規作成し、どちらも歯車ボタンからウェイトを1にしてください。


各ステートは画像の通り作りますが、アニメーションファイルはまだ作っていないので、今のところはMotionの欄はすべて空白で問題ありません。
トランザクション(矢印)についてはパラメーターを定義しているので作成できます。以下のように設定してください。番号は画像中の番号と対応します。
・トランザクション1~5共通
終了時間ありのチェックを外す
遷移間隔と遷移オフセットを0に
自身に遷移のチェックを外す

・トランザクション1
2本矢印が引かれている(or条件)
Conditionsについて
1本目の矢印:light_is_local が true かつ IsLocal が false
2本目の矢印:light_state が false
・トランザクション2
Conditionsについて:
light_state が true かつ light_is_local が false
・トランザクション3
Conditionsについて:
light_state が true かつ light_is_local が true かつ IsLocal が true
・トランザクション4
Conditionsについて:
light_state が true
・トランザクション5
Conditionsについて:
light_state が true かつ IsLocal が true
何をやっているのかという感じですが、動きを書き下すと、まずEntryから入ってきてデフォルトはLightOff(ライトオフ)です。
そこからオンオフを司る light_state が trueなら左下のLightOn(ライトオン)になります。
ローカル化の機能を実現するためにvrcsdk組み込みのIsLocalと自前のローカル化有効フラグlight_is_localで挙動を制御しています。特徴的なのはトランザクション1の条件の一つである「light_is_local が true かつ IsLocal が false」で、これを書き下すと「ライトのローカル化の設定が有効の場合、自分以外のプレイヤーはこの矢印の先(LightOff)に遷移する。」という挙動になり、結果としてローカル化の設定を有効にすると、ライトをオンにしても自分以外のプレイヤーはライトオフになります。
このあたりの挙動についてはIsLocalやAny Stateについて調べていただければと。複雑なので解説は丸投げします。
(余談:たぶんステートマシンはもっと簡潔に作ることができる)
Animation作成1(ライト強度)
では(めんどくさい)アニメーションファイルを作っていくのですが、その前にMA回りの設定をすると少し楽ができるのでやっておきます。
以下のようにLightオブジェクトに MA Merge Animator と (unity純正の)Animator と MA Parameters コンポーネントを追加します。

まずMA Merge Animatorに先ほどガワを作成したPointLightアニメーターを設定します。設定値は画像の通りですが重要なのは付属アニメーターを削除
にチェックを入れることです。
次にAnimatorコンポーネントにもPointLightアニメーターを設定します。これはアニメーションファイルを円滑に作成するためだけに存在するので、アバタービルド時には消えてほしいものになります。そのための設定が先の付属アニメーターを削除なわけです。
最後にMA Parametersですが、追加時点ではここには何もないと思いますが、未登録パラメーターを展開するとPointLightアニメーターで定義した変数が出てきます。それらをすべて登録するのですが、登録後にそれぞれの変数を展開してパラメーター型はアニメーターで定義したものと同じものを設定してください。

ついでに自動リネームにチェックもつけておく
さて、これでアニメーションファイルを作る準備ができました。作っていきましょう。
アニメーションタブが開かれていない場合は上のツールバーからウィンドウ→アニメーション→アニメーションでタブを開いておきます。そしてLightオブジェクトを選択してからアニメーションタブのプルダウン→新しいクリップの作成を選択します。

初回は「新しいクリップを作成」のみのはずなのでそのまま気にせず進めてください。
作るアニメーションは以下の3つです。
ライトをオンにする(強度も加味する)アニメーション「LightOn」
ライトをオフにするアニメーション「LightOff」
ライトの色を変えるアニメーション「LightColor」
まずLightOnから作ります。新しいクリップを作成からワークディレクトリにLightOnアニメーションを作成します。その後、記録ボタンを押してライトのIs_ActiveとIntensityとRangeのプロパティを追加します。

プロパティを追加からでももちろんOK

フレーム0地点で、Is_Activeがtrue, Intensityが0.1, Rangeが30とします(ライト強度が弱い状態を表現)。
続いてフレーム10地点にキーを追加し、Is_Activeがtrue, Intensityが3, Rangeが50と設定します(ライト強度が強い状態を表現)。

後ほどlight_intensity変数を使って割合でこの範囲の値をとることになります。オン状態での強度の最低値と最大値を定めたと考えてください。
ライトオフの方は簡単で、すべてゼロにするだけです。(Is_Activeのみfalseにすれば事足りるが一応すべてゼロにしておく。)
新しいクリップを作成からワークディレクトリにLightOffアニメーションを作成。

こちらは特に変化しないのでフレーム0にのみキーがあれば十分です。
Animation作成2(色相変更)
さて、これで残るは "ライトの色を変えるアニメーション「LightColor」" だけです。強度と同じようにプロパティを見てみましょう。
新しいクリップを作成からワークディレクトリにLightColorアニメーションを作成。録画ボタンを押してからライトの色をいじってみます。このとき色の指定方式をHSVに設定して、H, S, V, Aすべて動かしてください。

すると以下のようにプロパティが追加されます。

色はColorのrgbとa(アルファブレンド)で表現されるようです。このうちaは1で固定で良いです。rgbを変化させれば色相が変わります。先程のHSVを動かしたときにSを100にするとカラーサークルの原色の色になります。

この状態でHを0~360にするとカラーサークル上で変化する色に対応することが分かります。しかしアニメーションプロパティはrgbなのでこのまま0~360に対応させることはできません。そこで総フレーム数を100と定めて、360と100の公約数だけキーを打ちます。今回は10段階のキーを作成します。このあたりの方法は以下サイトの「色変更のアニメーション」の手法を参考にしています。
ただし白を例外として入れる必要があるため、フレーム0は白、フレーム1は赤(H=0)~フレーム100は赤(H=360)とします。
記録ボタンを押し、フレーム数選択→キーを追加→色を操作してHSVを所定の値にする。を繰り返します。





H=(360/100)*[1~10段階]の色を記録・設定
このとき注意すべき点としてH以外のSVとAの値はどのキーでも常に100として設定してください(白以外)。
Animator設定(アニメーション割り当て)
アニメーションファイルは用意できましたか?Animatorタブに戻って各ステートにアニメーションファイルを割り当てます。
まずステートマシン上に追加した覚えのないステートは削除してください。(アニメーション新規作成時に自動的に作られる?)

全ステートに共通ですが、Write Defaultsのチェックは外してください。
LightOffステートのMotionに、ライトをオフにするアニメーション「LightOff」を割り当てます。

続いてLightOn_***ステート3つすべてのMotionに、ライトをオンにするアニメーション「LightOn」を割り当てます。その後Motion Timeのパラメータにチェックを入れ、light_intensityを指定します(3つとも)。

最後にLightColorレイヤーに移り、LightColorステートのMotionに、ライトの色を変えるアニメーション「LightColor」を割り当てます。その後Motion Timeのパラメータにチェックを入れ、light_colorを指定します。


以上でAnimatorとアニメーション関連の設定は完了です。お疲れさまでした。
Exメニュー作成
アニメーション関連が終われば後はほぼウィニングランです。頑張っていきましょう。
久しぶりにAssetsに戻って、ワークディレクトリで右クリック→作成→VRChat→Avatars→Expressions Menuを選択して、二つ、空のメニューを作ります。名前はLightMenuとLightSubMenuとします。
(余談:Exメニュー作成方法について
「あれ?ExメニューはMAでヒエラルキー上でつくれるよね?」と思った方。正解です。
ただ今回はMAでなくvrcsdk純正のメニューを作ります。製品としてまとめる際にメニューファイルで管理した方が取り回しが良いので。)
まずLightMenuですが、一つだけ項目を追加し、タイプをサブメニューとしてLightSubMenuを指定します。名前、アイコンをそれっぽくお好みで設定します。

次にLightSubMenuですが、こちらはそれぞれの機能に対応する項目を4つ追加します。
ライトオンオフ, Toggleタイプ, light_state
ローカル化, Toggleタイプ, light_is_local
明るさ調整, RadialPuppetタイプ, Rotationにlight_intensity
色相調整, RadialPuppetタイプ, Rotationにlight_color




それぞれ名前とアイコンはそれっぽいものでOKです。注意点としては変数名のガイドはないため大文字小文字を間違えないことと、RadialPuppetの場合はRotationの方に変数名を入力することです。何やらパラメータがないと警告が出ていますが、パラメータは実行時にMA Parametersで定義されるため、ビルド前はこの警告が出てても大丈夫です。Animatorやらなんやらで散々準備してきた布石はここから回収されます。
以上の設定ができたら、ヒエラルキー上のLightオブジェクトにMA Menu Installerをつけます。
プレハブ開発者向け設定を展開し、インストールされるメニューにLightMenuを設定します。

以上で作業は終了です。お疲れさまでした!
動作確認
プレイモードで確認してみましょう。
まずGestureManagerでExメニューを確認すると、メニューが追加されています。

シーンを見ると電球マークがないためデフォルトではライトはオフです。

Exメニューの「ライトオンオフ」を押すと、電球マークが表示されます=ライトオン。

ライトオン状態でExメニューの「明るさ調整」を変化させると、ライトの強度が変化します。

Exメニューの「色相調整」を変化させるとライトの色が変わります。(電球マークの色で表される。)

すべてが想定通り動けば動作確認は完了です。
アバターアップロードしてvrchat内で確認してみてください。(ローカル化の確認は自分だけではできないので、フレンドと会ったときに試してみてください。)
お疲れさまでした。以上で光源ライトギミックの実装の解説は終了となります。
おわりに
ここまで読んでくださりありがとうございました。
今回はboothでの初出品に伴って、ギミックの実装内容について解説しました。こういう知見は広めると商品価値が下がるように思えますが、界隈が発展すれば巡り巡って全体の利益になると思っています。
それでもモチベーションにつながるのでリンクから光源ライトギミックの購入もよろしくお願いいたします。ここまで読んだ人は自分で実装できますので、自信を持って自作に取り組むのもまた良しです。皆さんも改変、しよう!ということで。
今回の知見が誰かの役に立てば幸いです。
(有料部分にはコンテンツはありません。この記事を気に入っていただけたなら、ご支援いただければ幸いです。)
終
2024/09/26
written by shift
ここから先は
¥ 100
この記事が気に入ったらチップで応援してみませんか?