hibitの技術系メモ

数学とか3Dとか翻訳とか

アニメーションオーバーライドによって中腰になってしまったアバターを直す方法(Unity2017用)

 以前紹介していたアバターの中腰解除方法ですが、

deux-hibi.hatenablog.com

 なんと、VRChatに対応したUnityのバージョンが5.6.3から2017.4.15に上がったことにより、上記事の方法1が使えなくなってしまいました

 それに合わせて記事をリライトしようと思いましたが、タイミングがいいことにがとーしょこらさんがワンクリックで中腰を解除できるツール(VRCDeveloperTool)を公開してくれたので、その紹介を改めて行うような形で新記事としたいと思います。これを専門用語で他力本願と言います。

導入及び操作方法

 先程リンクを貼ったページからダウンロード。

f:id:hibit_at:20190107203050p:plain

 無料でもDLできますけど、当然お前らもブーストで投げ銭するよな?(私はしました)

f:id:hibit_at:20190107203409p:plain

 DLしたファイルをAssets欄にドラッグ&ドロップ。今からこの中腰になったAlcedoちゃんを救出します。

f:id:hibit_at:20190107203555p:plain

 ドロップした後は、Unityの上の方にあるメニューバーに「VRCDeveloperTool」という欄が出来ているはずなので、そこにある「HumanoidPose Resetter」をクリック。

f:id:hibit_at:20190107203742p:plain

 でてきたウィンドウにある「TargetObject」に、中腰を直したいアバターのオブジェクト(リグやメッシュではなく、親のオブジェクトです)をドラッグ&ドロップ。

f:id:hibit_at:20190107204022p:plain

「Reset Pose」を押すと、この通り。めでたしめでたし。

 …。

 ……。

 聴こえるぞ……ツールに頼らずに中腰を抹殺したいという怨嗟の叫びが……!

心を込めて中腰を抹殺する方法

 前記事の焼き直しになりますが、おさらい。

 Unityのアセット欄をたどって、

Assets > VRCSDK > Examples > Sample Assets > Animation

 の中にある「tpose-new」の横にある小さな再生ボタンを押します。

f:id:hibit_at:20180921214316p:plain

 そうしたらその横に「tpose-new」というアニメーションファイルが出てくると思うので、それを選択した状態でアニメーションウィンドウを押すと、   f:id:hibit_at:20180921214535p:plain

 このように、夥しい数のアニメーションコンポーネントが出てきます。これを全部コピーして、元々あった(つまり中腰の原因になっていた)アニメーションにペーストします。これで解決!

 ……と、前記事のコピペで終わるのもアレなので補足的なあれこれ。

Tポーズの動きを入れたら、アニメーション中も強制的にTポーズになったりしないの?

 なりません。VRCをプレイしている最中は、ボーンの動きはすべてトラッキングに準拠します。

全部のアニメーションにTポーズの動きを入れると煩雑なんだけど

 再生ボタンを押して発動するアニメーションは、Animatorの「Entry」から矢印が出ているオレンジ色のアニメーションになります。そこにTポーズの動きを入れていれば、再生中は(そして何か変なことをしなければ再生後も)Tポーズになります。

 更に、オーバーライド用のアニメーションに一切余計なプロパティを入れたくないということであれば、下の図ようにTポーズ用のアニメーションを用意して、Entryからそこに矢印を飛ばすようにしましょう。

f:id:hibit_at:20190107205556p:plain

 上の図でいうと「Wink」「Buku」がオーバーライドさせたいアニメーションになります。

再生中はTポーズにできても、再生を止めるとまた中腰になるんだけど

 Tポーズのアニメーションウィンドウで、

f:id:hibit_at:20190107205834p:plain

 この録画ボタンを2回押すと操作画面でもTポーズに戻ると思います。

 だが勇者よ油断するな、Unity2017を倒しても、Unityのアップデートが続く限り、第二第三の中腰がまたお前たちを襲うであろう……。

フェルマーの最終定理もどき

 先日、あるフォロワーさんがこのようなツイートをしていました。

f:id:hibit_at:20181225215109p:plain

(晒し上げる意図はないので、ID等は伏せています)

 nが自然数だったら有名なフェルマーの最終定理ですが、nが自然数じゃなかったら普通に成り立ちそうですね。という訳で私が考えた解答が以下の通り。

 本当の問題はこれからで、ドヤ顔であげたはいいものの、上の解答には数字の間違いがあります。よくやるんだこういうミス……。元ツイートのリプ欄には補足を入れていますが、\frac{7}{6}\piではなく\frac{7}{3}\piが正です。間違い正しついでに清書と解説を加えておきます。

清書

nが自然数であるとはどこにも書いていないので、n=\frac{1}{\log 2}\frac{7}{3}i\piとする。

(\log は自然対数)

この時、nは||n||\geq3を満たす。

ここで、(x,y,z)=(4,16,8)とすると、

4^{n}+16^{n}=4^{\frac{1}{\log 2}\frac{7}{3}i\pi}+16^{\frac{1}{\log 2}\frac{7}{3}i\pi}

=2^{2\frac{1}{\log 2}\frac{7}{3}i\pi}+2^{4\frac{1}{\log 2}\frac{7}{3}i\pi}

=e^{log 2\cdot2\frac{1}{\log 2}\frac{7}{3}i\pi}+e^{log 2\cdot4\frac{1}{\log 2}\frac{7}{3}i\pi}

 =e^{2\frac{7}{3}i\pi}+e^{4\frac{7}{3}i\pi}

 =e^{2\frac{1}{3}i\pi}+e^{4\frac{1}{3}i\pi}

 =e^{i\frac{2}{3}\pi}+e^{i\frac{4}{3}\pi}

 =(cos{\frac{2}{3}\pi}+i\cdot sin{\frac{2}{3}\pi})+(cos{\frac{4}{3}\pi}+i\cdot sin{\frac{4}{3}\pi})

 =(-\frac{1}{2}+\frac{\sqrt{3}}{2}i)+(-\frac{1}{2}-\frac{\sqrt{3}}{2}i)

 =-1

 =e^{i\frac{3}{3}\pi}

 =e^{3\frac{7}{3}i\pi}

=e^{log 2\cdot3\frac{1}{\log 2}\frac{7}{3}i\pi}

=2^{3\frac{1}{\log 2}\frac{7}{3}i\pi}

=8^{\frac{1}{\log 2}\frac{7}{3}i\pi}

=8^{n}

\therefore x^{n}+y^{n}=z^{n}を満たす自然数(x,y,z)は存在する。

証拠

 ホントかよ、と思う方へ。Wolframに実際に計算してもらいました。

f:id:hibit_at:20181225223425p:plain

f:id:hibit_at:20181225223501p:plain

f:id:hibit_at:20181225223537p:plain

解説

 上の解答を見ただけで納得できる人となんのこっちゃという人との両方がいると思うので、解説を加えます。上のトリック(?)は実数を虚数乗すると三角関数になるという仕組みを利用したものです。理由なんて聞かないで。今夜はずっと側にいて。もしくはマクローリン展開でぐぐって。式にすると以下になります。

e^{x+iy}=e^x(cos{y}+i\cdot sin{y})

 これを図示すると、下図のようなめかぶのバケモノみたいな曲面2種類(実部と虚部)、になりますが、x=0の断面でスパッと切るとおなじみの三角関数になります。

f:id:hibit_at:20181225223737p:plain

 しかも、この三角関数どのような実数をかけても振幅が同じであるという特性があります。振幅が変わらない代わりに周期が変わります。

 実数の虚数乗は実部と虚部とで単位円の座標になるので、単位円同士でa+b=cが成り立つような組み合わせを見つければ上記のフェルマーもどきを満たす等式は見つかるという訳です。そのようなものには、例えば\frac{2}{3}\pi,\frac{4}{3}\pi,\frac{3}{3}\pi(=\pi)があるので、それに対応した実数とnを用意すれば出来上がりです。

 ただ、\frac{1}{\log 2}\frac{1}{3}i\piだと||n||\geq3を満たさないので、三角関数の周期は2\piを足しても変わらない、という性質を利用して\frac{1}{\log 2}\frac{1}{3}i\pi+i2\pi=\frac{1}{\log 2}\frac{7}{3}i\piにしています。こうして見るとえらい強引だ……!

 ちなみに、上の計算に「オイラーの等式」として有名な下の式が出てきますが、

e^{i\pi}=-1

 要するに、\pi(=180°)回したら、単位円上の(-1,0)の位置になるよ、という幾何学的にはごく単純なことを述べているに過ぎないことがわかります。

冷静なつっこみ

 その後、あーあーあ~さんから冷静なつっこみが入る。

 ……。

 確かに、4^{3}+4^{3}>5^{3}であり、また 4^{4}+4^{4}<5^{4}なので、3 <n< 4のどこかで必ず4^{n}+4^{n}=5^{n}であるようなnは存在することになります。なお、これは容易に解けてn=\frac{log 2}{log 5-log 4} \fallingdotseq 3.11となります。

 ええーい、誰だ誰だ複素数なら成り立つ(ドヤ とか言ってたやつは。

 無駄に話を複雑にする男ってどこにでもいるよね~、という話でした。

f:id:hibit_at:20190104231916p:plain

Photoshop持ってなくてもpsdファイルがあるとテクスチャ改変する時に便利だという話

 今回はCGをやっている人からすると鼻で笑われるような話ですが、適当にぐぐった感触だと言及している記事がなかったので一応書いておきます。

アバターをテクスチャ改変したいとき

 アバターを改変するにあたって一番手頃な方法はテクスチャ改変(色変え)だと思います。だいたいの画像編集ソフトには色調補正(色相・輝度・彩度をいじる機能)がついているので、テクスチャ画像(pngファイル)のうち色を変えたい部分を範囲選択して色調補正する、というのがオーソドックスな方法かと思います。

 しかしこれには実は2つのデメリットがあります。

  • 範囲を選択するのがめんどくさい
  • ワークフローが直列かつ破壊的である

 レイヤー管理されたファイル(ほとんどの場合はPhotoshop用のデータであるpsdファイル)を使うことにより、これらのデメリットを解消することができます。でもワイPhotoshopなんてハイカラなモン持ってへんし……と思っているあなた、psdファイルはフリーソフトgimpでも開けるので大丈夫です。これから先は実際にgimpの操作画面を交えながら解説していきます。

範囲を選択しやすい

 これから先は、この間製作者であるみにさんの許可をいただけたので、実際の販売モデルである

miniscape.booth.pm

 みかちゃんのテクスチャで説明していこうと思います。みにさんありがとう! なななんとこのかわいいモデルが2,100円! 買うしかない! 時代の波に乗り遅れるな! マストバイ!

 で、これが実際のテクスチャ。psdファイルをgimpで開いています。

f:id:hibit_at:20181230021716p:plain

 右にあるレイヤーウィンドウで、このテクスチャ画像がいくつかのレイヤーに分かれていることがわかります。例えば、ハートの色をピンクから青に変えたい時は、

f:id:hibit_at:20181230022042p:plain

 ハートのレイヤーの色全体を変えれば、ハートの色だけが変わります。わざわざ範囲の選択や色域の選択で頑張る必要はなかった! というだけでなく、もう1つのメリットも紹介します。というか、こちらの方がより大事かなと。

直列かつ破壊的なワークフロー

 ある画像に対して

  1. 編集→その結果を反映
  2. 更にそれを編集→その結果を反映
  3. 更にそれを編集→その結果を反映

 という風に編集していくのは直列的なワークフローです。3番目の操作をした後で、2番目の操作だけを変えてみた結果を見たい、ということはアンドゥ等で遡らない限り不可能です。また、遡って2番目の操作を修正した後で3番目の操作を繰り返すのはひどく徒労感を伴います。

 そうでなくとも、色合いを変えた後で光沢もつけたいし、色合いもベースカラーと調整用の色を分けたいし……という状況が考えられますし、それぞれの効き具合も独立に確かめたいところです。

 また、pngで上書き保存してしまったら、もう元のファイルには二度と戻せません。そもそも緑色にしたいよね、となっても、もう青色になってしまったファイルしかないのです。元データや作業履歴を残すためには、別にファイルを用意してバージョン管理……とやる必要がありますが、まあスマートではないですよね。

f:id:hibit_at:20190103163757p:plain

 図で表すとこんな感じ。

並列かつ非破壊的なワークフロー

 レイヤーを使うと複数の操作を並列的に処理することができます。

f:id:hibit_at:20181230023257p:plain

 レイヤーウィンドウで右クリックして「新しいレイヤーグループ」を作成。

f:id:hibit_at:20181230023843p:plain

 でてきたグループ(例では「ハートG」と名付けています)にハートレイヤーを格納させた後、その中で「新しいレイヤーの追加」を行う。

f:id:hibit_at:20181230024112p:plain

 この時にレイヤーの描画モードを「標準」ではなく「乗算」にします。とりあえずは色を足すなら「乗算」、明るくするなら「加算」と覚えておいて、他のモードの細かい違いは慣れてきたら気にしていく感じでいいと思います。

f:id:hibit_at:20181230024519p:plain

 影や光を足していくとこんな感じ。それぞれの操作がレイヤーで分かれているのがわかるかと思います。

 図で表すとこんな感じ。

f:id:hibit_at:20190103163817p:plain

 各操作はレイヤーとして独立しているので、その調整にあたって順番を気にする必要はありません。また、元データはオリジナルレイヤーとして残されているので、いくら改変をしても元データに戻るのは容易です。例えるなら、電卓だと途中で1つでも打ち間違えたら終わりですけど、関数電卓だと途中の式を変えて計算結果を変えることができますよね。あんな感じです。余談になりますが私は以上のような理由により(破壊的編集プロセスの塊である)電卓が大嫌いです。

 テクスチャのごく簡単な改変でも、作業の途中で絶対にあ……これ戻りたいとか前やったあそこのパラメータだけ変えたいなとか思ったりすることはあります。元のデータには手を加えず、レイヤー管理ですべて済ませるという考え方を持つと、選択範囲を絞る労力も必要もないし、ムダなく作業ができますよという話でした。

漸化式は平面上の線形変換だということ、あるいは非線形を多次元で殴る話

 受験数学において三項間漸化式は頻出します。以下のようなやつ。

a_{n+2}=3a_{n+1}-2a_nの一般解を求めよ

 これを解くには、特性方程式を解いて式を比較して……というめんどくさい手続きをふまなければならないのですが、行列の対角化を使うことにより(計算量はともかく)手続き上はスムーズに解くことができます。

$$ \begin{bmatrix} a_{n+2} \\ a_{n+1}\\ \end{bmatrix}= \begin{bmatrix} 3 & -2 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} a_{n+1} \\ a_n\\ \end{bmatrix} $$

$$ \begin{bmatrix} a_{n+1} \\ a_n\\ \end{bmatrix}= \begin{bmatrix} 3 & -2 \\ 1 & 0 \\ \end{bmatrix}^{n-1} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

$$ \begin{bmatrix} a_{n+1} \\ a_n\\ \end{bmatrix}= \begin{bmatrix} 1 & 2 \\ 1 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 0 & 2 \\ \end{bmatrix}^{n-1} \begin{bmatrix} -1 & 2 \\ 1 & -1 \\ \end{bmatrix} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} 1 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 0 & 2 \\ \end{bmatrix}^{n-1} \begin{bmatrix} -1 & 2 \\ 1 & -1 \\ \end{bmatrix} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} 1 & 2^{n-1} \\ \end{bmatrix} \begin{bmatrix} -a_1+2a_2 \\ a_1-a_2 \\ \end{bmatrix} $$

$$ a_n=-a_1+2a_2+2^{n-1}(a_1-a_2) $$

 めでたしめでたし。テクニックだけを知りたいのならば、ここから先は読む必要はありません。

行列の意味するところ

$$ A=\begin{bmatrix} 3 & -2 \\ 1 & 0 \\ \end{bmatrix} $$

 この行列が意味するところを考えていきます。2*2の行列は平面上における座標変換、それも線形変換を示しています。 つまり、上の行列はxy平面において(x,y)=(a_{n+1},a_n)という点がどこからどこへ移動するかを示しているということになります。変換の様子を図示したものが下の図になります*1

f:id:hibit_at:20190103170347p:plain

 Aを作用させ続けると、(1,0)がどのような動きをするかを図示したものが下になります。

f:id:hibit_at:20190103165856p:plain

 また、固有値を持つ線形変換は対角化によって直交基底の成分を抽出することができます。直交基底というとものものしいですが、要は「横方向にn倍、縦方向にm倍しているだけ」という状態です。見方を変えると、真の姿はそのようなシンプルな変換であるにも関わらず、何かの事情で、歪んだレンズを介してしか格子座標の世界に姿を現せないかわいそうな行列がAであるともいえます(向こうからしたら我々の世界こそA^{-1}に歪んだ世界でしょうが)。その証拠に歪んだ座標に合わせた初期値を与えてやると以下の通り

$$ \begin{bmatrix} 3 & -2 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} 1 \\ 1 \\ \end{bmatrix}= \begin{bmatrix} 1 \\ 1 \\ \end{bmatrix}=1* \begin{bmatrix} 1 \\ 1 \\ \end{bmatrix} $$


a_1=1,a_2=1の時、a_n=1,1,1,1,…

$$ \begin{bmatrix} 3 & -2 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} 2 \\ 1 \\ \end{bmatrix}= \begin{bmatrix} 4 \\ 2 \\ \end{bmatrix}=2* \begin{bmatrix} 2 \\ 1 \\ \end{bmatrix} $$


a_1=1,a_2=2の時、a_n=1,2,4,8,…

 1倍、2倍されています。なんという素直な変換! お気づきの方も多いと思いますが、「n倍、m倍」は行列の固有値、「歪んだ座標に合わせた初期値」は行列の固有ベクトルに相当します。

固有値が重複する場合

 漸化式の話に戻ると、特性方程式が重解を持つ場合があります。以下のようなやつ。

a_{n+2}=4a_{n+1}-4a_nの一般解を求めよ

 オーソドックスな手法だと、変数の数に対して方程式が足りなくなるため、2^{n}で割るなどの小細工が必要になりますが、行列を用いた手法ならばそのようなものは必要ありません。

$$ \begin{bmatrix} a_{n+2} \\ a_{n+1}\\ \end{bmatrix}= \begin{bmatrix} 4 & -4 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} a_{n+1} \\ a_n\\ \end{bmatrix} $$

$$ \begin{bmatrix} a_{n+1} \\ a_n\\ \end{bmatrix}= \begin{bmatrix} 4 & -4 \\ 1 & 0 \\ \end{bmatrix}^{n-1} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

$$ \begin{bmatrix} a_{n+1} \\ a_n\\ \end{bmatrix}= \begin{bmatrix} 2 & 1 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} 2 & 1 \\ 0 & 2 \\ \end{bmatrix}^{n-1} \begin{bmatrix} 0 & 1 \\ 1 & -2 \\ \end{bmatrix} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

 多少ジョルってますが(註:完全な対角化が不可能であり、ジョルダン標準形を持つこと)計算は依然としてシンプルです。

$$ a_n= \begin{bmatrix} 1 & 0 \\ \end{bmatrix} \begin{bmatrix} 2 & 1 \\ 0 & 2 \\ \end{bmatrix}^{n-1} \begin{bmatrix} 0 & 1 \\ 1 & -2 \\ \end{bmatrix} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} 1 & 0 \\ \end{bmatrix} \begin{bmatrix} 2^{n-1} & (n-1)2^{n-2} \\ 0 & 2^{n-1} \\ \end{bmatrix} \begin{bmatrix} 0 & 1 \\ 1 & -2 \\ \end{bmatrix} \begin{bmatrix} a_2 \\ a_1\\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} 2^{n-1} & (n-1)2^{n-2} \\ \end{bmatrix} \begin{bmatrix} a_1 \\ a_2-2a_1 \\ \end{bmatrix} $$

$$ a_n=2^{n-1}a_1+(n-1)2^{n-2}(a_2-2a_1) $$

次元を上げて行列で殴る…定数項編

 でもこの手法で扱えるのって線形変換だけじゃないの? と思った方へ。ご安心ください、以下のような非線形な式も次元を増やすことによって線形行列で殴ることができます。

a_{n+1}=2a_n+1の一般解を求めよ

 行列形及び回答は以下の通り。

$$ \begin{bmatrix} a_{n+1} \\ 1\\ \end{bmatrix}= \begin{bmatrix} 2 & 1 \\ 0 & 1 \\ \end{bmatrix} \begin{bmatrix} a_n \\ 1\\ \end{bmatrix} $$

$$ \begin{bmatrix} a_n \\ 1\\ \end{bmatrix}= \begin{bmatrix} 2 & 1 \\ 0 & 1 \\ \end{bmatrix}^{n-1} \begin{bmatrix} a_1 \\ 1\\ \end{bmatrix} $$

$$ \begin{bmatrix} a_n \\ 1\\ \end{bmatrix}= \begin{bmatrix} -1 & 1 \\ 1 & 0 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 0 & 2 \\ \end{bmatrix}^{n-1} \begin{bmatrix} 0 & 1 \\ 1 & 1 \\ \end{bmatrix} \begin{bmatrix} a_1 \\ 1\\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} -1 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 \\ 0 & 2 \\ \end{bmatrix}^{n-1} \begin{bmatrix} 0 & 1 \\ 1 & 1 \\ \end{bmatrix} \begin{bmatrix} a_1 \\ 1\\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} -1 & 2^{n-1} \\ \end{bmatrix} \begin{bmatrix} 1 \\ a_1+1 \\ \end{bmatrix} $$

$$ a_n=-1+2^{n-1}(a_1+1) $$

 なおこの変形は、幾何学的に見ればアフィン変換です。

 ただこの手法、見かけはシンプルですけど計算量は多いです。対角化さえすればあとは単純ですが、そもそも対角化をするのが結構めんどうくさい。これだったらオーソドックスな特性方程式で解いた方が早いです。オシャレではあるけど実用性はないやつ。

次元を上げて行列で殴る…階差数列編

 次元を上げれば非線形な漸化式も行列計算で解決できる! 今度はさらに発展させてみましょう。

a_{n+1}=a_n+nの一般解を求めよ

 いわゆる階差数列というやつ。

 これも漸化式を分解することによって以下のように整理できます。

$$ a_{n+1}=a_n+b_n $$

$$ b_{n+1}=b_n+1 $$

$$ \begin{bmatrix} a_{n+1} \\ b_{n+1} \\ 1 \\ \end{bmatrix}= \begin{bmatrix} 1 & 1 & 0\\ 0 & 1 & 1\\ 0 & 0 & 1\\ \end{bmatrix} \begin{bmatrix} a_n \\ b_n \\ 1 \\ \end{bmatrix} $$

$$ \begin{bmatrix} a_n \\ b_n \\ 1 \\ \end{bmatrix}= \begin{bmatrix} 1 & 1 & 0\\ 0 & 1 & 1\\ 0 & 0 & 1\\ \end{bmatrix}^{n-1} \begin{bmatrix} a_1 \\ 1 \\ 1 \\ \end{bmatrix} $$

※a_2=a_1+1よりb_1=1

$$ \begin{bmatrix} a_n \\ b_n \\ 1 \\ \end{bmatrix}= \begin{bmatrix} 1 & n-1 & \frac{(n-1)(n-2)}{2}\\ 0 & 1 & n-1\\ 0 & 0 & 1\\ \end{bmatrix} \begin{bmatrix} a_1 \\ 1 \\ 1 \\ \end{bmatrix} $$

$$ a_n= \begin{bmatrix} 1 & n-1 & \frac{(n-1)(n-2)}{2}\\ \end{bmatrix} \begin{bmatrix} a_1 \\ 1 \\ 1 \\ \end{bmatrix} $$

$$ a_n=a_1+(n-1)+\frac{(n-1)(n-2)}{2} $$

$$ a_n=a_1+\frac{n(n-1)}{2} $$

 このあたりになると、1次元直線における操作を3次元空間に写して計算していることになり、(この例では必要ないですが、大体の場合においては)逆行列の計算とかがエグいことになります。基本的に3次元以上の行列計算は人間のやることではないと考えています。GPUとかにやらせましょう。

補足1

 タイトルに「平面上」とありますが、正確には「\mathbb{R}^nユークリッド空間上」です。タイトルのわかりやすさを優先しました。

補足2

$$ a_{n+1}=a_n+b_n $$

$$ b_{n+1}=b_n+1 $$

 を変形すると以下のような三項間漸化式(+定数項)になります。

$$ a_{n+2} = a_{n+1}+b_{n+1} $$

$$ a_{n+2} = a_{n+1}+b_n+1 $$

$$ a_{n+2} = a_{n+1}+(a_{n+1}-a_n)+1 $$

$$ a_{n+2} = 2a_{n+1}-a_n+1 $$

 つまりこの2つの漸化式は、初期値の反映のされ方(つまり「歪み」)による見え方が違うだけで、本質的には同一のものであるといえます。実際に、得られるジョルダン標準形も同じです。

$$ \begin{bmatrix} 2 & -1 & 1\\ 1 & 0 & 0\\ 0 & 0 & 1\\ \end{bmatrix}= \begin{bmatrix} 1 & 1 & 0\\ 1 & 0 & 0\\ 0 & 0 & 1\\ \end{bmatrix} \begin{bmatrix} 1 & 1 & 0\\ 0 & 1 & 1\\ 0 & 0 & 1\\ \end{bmatrix} \begin{bmatrix} 0 & 1 & 0\\ 1 & -1 & 0\\ 0 & 0 & 1\\ \end{bmatrix} $$

 例えば、 a_{n+1}=a_n+nという条件を満たす初期値ベクトルは、前者では(a_1,1,1)、後者では(a_1+1,a_1,1)という形になります。

*1:この図示は、私が自作したシェーダ「EigenShader」によるものです。GitHubリポジトリここ

アバターを高速移動させたい時に便利な、コライダーボードを用いた移動方法

!注意事項!

 以下の事項に十分に注意した上でご使用ください。

  • ワールド製作者の意図しない動き(ギミックの崩壊 等)をもたらす恐れがあります。
  • ワールドの舞台裏(通常ユーザーが入れない領域)を見られることが不本意な製作者もいるかも知れません。
  • 演算負荷が高いので、他のユーザーのFPSを低下させる恐れがあります。

 Publicや不特定多数が集まる場、とくにギミックがあるワールドでの濫用は避けましょう。

ここから本文

 人はいつの時代も逃れたがる。仕事から、家庭から、社会から、重力から、物理法則から……。

 という訳で、バーチャル世界の中だけでも物理法則を無視して高速移動したい人向けにコライダーボード現象*1を用いたコライダーダッシュ/ジャンプのやり方を紹介します。

 以上のような形でワールドを縦横無尽に動き回ることができます。ついでにアニメーションオーバーライドの基本的な解説もしていきます。

オブジェクトの実装

f:id:hibit_at:20181220014123p:plain

 まず高速移動させたいアバターを選択して、

f:id:hibit_at:20181220014224p:plain

「Create Empty」で空のGame Objectを作成します。

f:id:hibit_at:20181220014442p:plain

 さきほど作ったGame ObjectのComponentに「Box Collider」を追加。

f:id:hibit_at:20181220020908p:plain

 Game Objectに以下のような設定を加えます。

  • TransformのPosition…行きたい方向。
  • Box ColliderのCenter…上で入力した座標と逆の座標を入力。
  • Box ColliderのSize…yのサイズだけ0。

 コライダーボードは、Game Objectのコライダーとアバターのコライダーが干渉した場合、Game Objectに引き寄せられるという現象です。

f:id:hibit_at:20181220015653p:plain

 オブジェクトのコライダーがアバターの足元にある場合、オブジェクトが存在し続ける限り「干渉→テレポート」という無限ループが繰り返されるため、結果として高速移動ができます。オブジェクトのPositionが移動方向になります。コライダーの中心は、アバターの足元に持っていくためにPositionの座標をマイナスする必要があります。

 Positionの設定としては、

 あたりがオススメです。ダッシュにも上方向の移動の成分を入れていますが、これについては後述します。あと、コライダーボードにはオブジェクトのRotationも反映されるため、高速回転、高速きりもみ等も再現できますが、まあ興味ある人はどうぞレベルですね。

f:id:hibit_at:20181220020030p:plain

 設定が終わったらGame Objectの脇のチェックを外して非表示にしておきましょう。これを忘れると一生高速移動し続けるアバターになり、VRChat上での操作もままならなくなります。表示/非表示で移動モードとそうでない時を切り替えられる状態にすることが必要です。次節でその手順を解説していきます。

アニメーションオーバーライドの設定

f:id:hibit_at:20181220021619p:plain

 Animationウィンドウをクリック。

f:id:hibit_at:20181220021845p:plain

「Create」ボタンをクリック。

f:id:hibit_at:20181220021921p:plain

 適当な名前で保存。画像では「dash」としていますが、別に何でもいいです。

f:id:hibit_at:20181220022042p:plain

「Add Property」でさきほど作ったオブジェクトの「Is Active」を追加。

f:id:hibit_at:20181220022840p:plain

 初期状態だと1秒(=60フレーム=1:00)後に設定されているキーフレームを1フレーム(0:01の位置)後まで移動した後、両フレームの「Is Active」のチェックボックスをチェックに。

 以上でアニメーションの設定は終わりですが、今度はそれをアニメータに入れていきます。

f:id:hibit_at:20181220023541p:plain

「Assets > VRCSDK > Examples > Sample Assets > Animation」の中にある「Custom Override Empty」をCtrl + ドラッグで作業フォルダにコピー。コピーした後は名前をわかりやすいものに変えておいた方が良いかもです(検索で紛らわしいので)。今回の例では「Collider Board」にしています。

f:id:hibit_at:20181220224503p:plain

 アニメータファイルを選択すると、インスペクタ欄にずらっと色々でてきますが、その中の「HANDOPEN」に先程つくったアニメーションファイル(例では「dash」)をドラッグ。なぜHANDOPENなのかは後述します。他の動作を割り当てたい場合、下の図に従って対応したアニメーションファイルを設定していきましょう。

f:id:hibit_at:20181220024849p:plain (正確な作者は存じ上げませんが、とてもわかりやすい図。ありがたく転載させていただきます)

 今度は、アバターにアニメータファイルを設定して終わりです。

f:id:hibit_at:20181220224654p:plain

 アバターのインスペクタにある「Custom Standing Anims」にさきほど作ったアニメータファイルをドラッグ。これで、

  • コントローラを操作する。
  • 操作に対応したアニメーションが発動する。
  • アニメーションにより、非表示だったGame Objectが表示になる。
  • コライダーボード現象が起こりアバターが高速移動する。

 という機能を持つアバターが出来上がりました。

実際に動かしてみる

 アバターをVRCに上げたら、今度は実際に動かしてみましょう。あと、大事な部分を言い忘れていましたが、コライダーボード現象は床の上にいる状態だと発動しません。ジャンプするなり段差を移動するなりでなにがしか落下している状態を作り出す必要があります。

 例でHANDOPENに設定したのはこのためで、「右親指でジャンプ→他の指でグリップボタンを押す」という操作がやりやすいからです。あと、HANDOPENはグリップボタンを離すだけでアニメーションが解除されるので制御が楽というのもあります。また、ダッシュの動作に上方向の動きを入れた方がいいのもこのためで、ダッシュで高低差を稼ぐことでHANDOPEN以外の操作に割り当てたアニメーションも発動させやすくなります。

 皆様も用法用量を守ってよき高速移動ライフを(慣れない内はわりと酔います)。

*1:コライダーテレポートと呼ぶこともあります。私の場合はうれいしさん、あーあーあ~さん→SHIARUさん→私、という形で教えていただきましたが、他にも色々な方が編み出していたようです

TOEIC900点とれませんでした

 どうも、タイトルの通りです。去る11月18日にTOEIC(L&R)を受けてきました。諸般の事情があってハイスコアが必要な状況で、900点を目標、800点を最低ラインとしていたのですが、先日公開された結果はL430+R415で845点でした。

f:id:hibit_at:20181214020539p:plain

 普段Twitterアメリカ英語とイギリス英語の違いが~」とか呟いたり、VRChat内で「まあ外国人が来たら俺が対応するから」的な空気出したりしているくせにこのザマだよ!

 実はTOEICを受けるのはこれが2回目で、1回目に受けた時は学生の時で760点(うろ覚え)でした。その時に比べれば、個人海外旅行も何回か経験したし、英語圏の友人も増えたから、その気になって1か月ぐらい本気で対策すれば900も夢ではないかも……!? という甘い考えでいましたが、余裕で甘かったですね。

試験当日の様子

 当日はリスニングが全然聴き取れなくて(結果的にはある程度は聴き取れていたみたいです)50問目ぐらいで泣きそうになっていました。試験が終わった後もしばらく放心状態で、家に帰ってからも「この一か月の努力はなんだったんだ……」とふて寝してました。

↑ふて寝の様子

 リーディングは結構できた感触だったので(結果的にはそんなことはなかった。我ながら点数予想がザル過ぎでは?)、「L320+R480で800点取れれば御の字かな」という予想でした。いやまあでも本当に、700点台にならなくてよかった。

良かった点…リーディング全般

 やったことがある人ならわかると思いますけど、TOEICのリーディングは時間との勝負です。とにかく大量の長文を読まされます。最初に受けた時は長文の物量に圧倒されてしまい、後半は完全に塗り絵状態でした(初心者あるあるらしい)。そのことだけは覚えていたので、とりあえず75分で長文を走りきる! ということだけは意識して訓練してきました。本番も良いペースで解き切ることができたので、そこは素直に自分の成長を認めたいです。

悪かった点…リスニング(Part2)

 Part2は短い質問に答えるやつです。長時間の会話は2,3語聞き逃してもなんとなくストーリーがわかりますが、短い質問は1語聞き逃すと終わりです。試験当日は結構終わっていました。反省。

TOEICの住人、物分りよすぎ説

 ところで、TOEICに出てくる登場人物ってえらく物分りがいいですよね。飛行機が遅れるけどクーポンで我慢してとか、渋滞にハマったからスケジュールを変更してくれとか。「飛行機が遅れるのに、200ドルのクーポンなんかで納得できるか! 訴えるぞ!」とか「渋滞にハマったとか寝言いってんじゃねえ! 這ってでもこい!」みたいな展開があっても面白いと思うのですが。そこまでTOEICに詳しくないので、実はあったらごめんなさい。

セル結合の記事についての釈明

 先日、セル結合について以下のような記事を投稿したところ、予想外の反響をいただくことになりました。

deux-hibi.hatenablog.com

 その中には同意の声も批判の声もあって、まあそれはそうだなという感じなのですが、こちらの伝え方が明らかにまずかった部分もあって、そこは非を認めて補足・訂正させていただくべきかなと思い、記事を書くことにしました。

タイトルが不適切

 第一に、セル結合を全否定するようなタイトルは明らかに余計でした。炎上目的と言われても仕方ないです。ある程度ぶっちゃけると、まさかここまでバズるとは思わずに適当にタイトルつけてしまったのですが、これはさすがに私が悪かったです。申し訳ありませんでした。全面的に非を認め、元の記事にも釈明コメントをつけさせていただきます。

お前は一切セル結合してないのか

 何を隠そう、かくいう私も労の場では当たり前のように結合しています。私にも生活があるのでな。場合によってはセル結合も必要になる、というのは十分理解しています。ただ、そこも含めて詳しく説明するべきだったな、というのがあるので、次節以降述べていきます。

セル結合が悪かは用途による

 エクセルは編集用と提出用とで使い方が異なり、編集用データでセル結合するな、それはさすがに百害あって一利なしだよ、というのが一番言いたかったことです。

f:id:hibit_at:20181213040201p:plain

 けして、一切のセル結合を認めないという意図ではなかったです。が、十分そう読めてしまう内容だったので、それは私が悪かったです。

f:id:hibit_at:20181213040229p:plain

 あと、エクセルをデータベース用途でのみ使えという風に取れる書き方もしてしまったので、それもそうではなかった、ということも合わせてお伝えしたいです。

f:id:hibit_at:20181213043109p:plain

 また、編集用と提出用とで明確に分離できていないワークフローも問題だよね、ということも言いたかったことです。

f:id:hibit_at:20181213040256p:plain

 ただ、これは組織全体としてのITリテラシーやワークフローの問題であり、簡単に変えられるものではなく、個人がどうエクセルを操作するかの範疇を超えています。なので、これから先は議論してもしょうがない領域かなと思います。というか、この部分については問題提起とか啓蒙とかというより、こういう凝り固まった社会ってままならないよね、という嘆きのポエムのつもりでした。簡単に変えられないからこそ、同じような論争が何十年も続いているのだろうなぁ……。

技術系を標榜するなら解決策を示せないの

 上にも述べたとおり、組織のワークフローの問題であり、局所的解決法があればみんなハッピーという問題ではないと思いますが、一応私の場合の局所的解決法も示しておきます。

 前記事のAやBをCにする方法ですが、VBAで表の範囲をRangeで選択した後に、Unmergeした後、if cells(i,j) = "" then ; cells(i,j)=(i-1,j) ; end ifというイテレーションを繰り返して整然データを作ったりしますね。ソースコードを貼ろうと思いましたが、VBEを開いてコードをコピペするスキルがある方はそもそもここら辺の問題で悩まないと思うので省略します。

 あと、前記事のCをBっぽく見せる方法については、詳しくない方向けに少し丁寧に解説します。

f:id:hibit_at:20181213043457p:plain

 表を選択して「条件つき書式」「新しいルール」

f:id:hibit_at:20181213043601p:plain

「数式を使用して~」で=左上のセル=その1つ上のセルという数式を打ち込みます。

f:id:hibit_at:20181213043712p:plain

 数式欄の右下にある「書式(F)」を押して、文字色を白色に。

f:id:hibit_at:20181213043817p:plain

 すると見かけ上はBっぽくなります。空白に見える部分も文字はちゃんと入力されているので、集計はできます。(12/16追記)ブコメで「真っ白よりはうすいグレーとかの方がよいのでは」という指摘を頂きました。データがあるのを明示したい場合は確かにそうですね。指摘ありがとうございます。

 あと、コメントでいただいたSUBTOTAL関数(AGGREGATE関数の方がより高機能ですが)は結局「ピンポイントで範囲を指定する」労力がかかるので、私は選ばないですね。小計を入れたければ別シートにするしかないかなと思います。

曖昧な仕様を許しているMicrosoftに文句を言うべきでは?

 それもそうですね。おい、Microsoft! そういうところやぞ! コラ! わかっとんのかワレ!

怒りすぎ、口調がキモい

 これは純粋に驚きだったのですが(我ながらサイコパスみたいな発言だ)、私は別にそこまでマジギレしていた訳ではないのですよ。「セル結合に両親でも殺されたのか」というコメントをいただきましたが、幸い両親は健在です。もちろん、セル結合のここはダメだなあという積年の思いはありまして、それを淡々と書き記したつもりなのですが、上のような反応をいただいた訳です。

 それで、改めて自分の文を見てみたら「言われてみれば確かに怒ってそう」とか「言われてみれば確かにキモいわ」とかいうことに気付いて、自分の認知が歪んでいたなと思いました。と言うのも、単語のチョイスや言い回しが芝居がかって大袈裟ですよね。大悪とか、弾劾とか、0.5秒とか。ただこれって、怒りのあまりそうなったというよりは、文章の流れ上、そういう戯画的な表現になったという方が実情に近いです。とはいえ結果的にできた文章がアレだったので、そこは配慮をすべきだったなと反省しています。今回の件である程度懲りたので、以後気を付けることにします。

 なんというか、自分には「おちょくり癖」「不謹慎癖」みたいなものがあって、言葉遊びでふざけられるポイントを見つけたら徹底的にふざけてしまう悪癖があります。今この文をご覧になっている皆様も、随所から隠しきれない「ふざけオーラ」のようなものを嗅ぎとっているものと思われます。行を削除する例で「町田市」を出したのもその手の遊びで、「ここで敢えて町田市を出したら帰属問題でややこしくなって更に面白いな」という考えのもと、意識して悪ノリしました。

 もちろん、無用な暴言は生産的な結果を生まないことは人並みに認識しており、むしろ実生活とくに対人では絶対にそういうことを言わないように心掛けているのですが(説得力ゼロ)、今回の記事ではチラ裏気分で悪ノリが暴走してしまったみたいです。一方で「文が面白かった」と言ってくださる方もいて、それは純粋にありがたいなという思いです。自分の文章の「癖」がどういう人達の口に合う/合わないのかがわかったので、これからも皆様を(行きすぎない範囲で)アジテートしていけたらと思います。

f:id:hibit_at:20181213042656p:plain

(こういうふざけた画像を作る性格だから怒られるんだろうなあ)

(でもやめられない)

(これはもう本能のようなもの、逃れられぬ宿痾……)