フィジカルレンダラーのとき動作が変わるXPresso

前のエントリの「全自動ヨッパライ歩行XPresso」をやっていたとき気がついたのですが、XPressoには「レンダラーがフィジカルのときだけ動作が変わってしまう」ものがあります。どうやら「値を記憶ノード」のようにXPresso内で時間の経過がカウントされる場合に起こるようです。単純なサンプルを使って発生条件や対処法などを検証したので、メモとしてここに書いておきます。なお、この件が単にバグだった場合はそのうち修正されることもあるかもしれませんので(報告はしておきます)、この記事を執筆時期よりずっと後に読んでおられる方はご注意ください。

フィジカルレンダラーで動作が変わるXPresso

こちらがサンプルファイルです。以下の解説で使っている3つのc4dファイルが入っています。

サンプルファイル:20181229_XP_phy_sample.zip

フィジカルで動作が変わる例

サンプルファイル:XP_phy_1.c4d

はじめに、フィジカルレンダラーのとき動作が変わるXPressoの実例を紹介します。このアニメーションはキーフレームなし、XPressoのみで動いています。

エディタビューでの再生や標準レンダラーでのレンダリングでは想定通りに動き、レンダリング結果は以下のようになります。まずピンクの「一部が欠けたチューブ」が回転し始め、12フレーム遅れてグリーンの「細くスライスされた円柱」が回転し始めます。グリーンの「円柱」はピンクの「チューブ」にぴったりくっついていて、後ろから押されて動いているように見えます。

XPressoで想定通りに動いているレンダリング結果

 

ところが同じファイルをフィジカルレンダラーでレンダリングすると、レンダリング結果は変わってしまいます。グリーンの「円柱」は想定より速く動き始め、ピンクの「チューブ」にはくっつかずに隙間の中間で動きます。

フィジカルレンダラーでは想定と違うレンダリング結果になる

 

XPressoの中身はこうなっています。

XPressoの中身

まず「時間ノード」から「現在のフレーム」を取得し、それに「数式ノード」で「5」を乗算します。これを「チューブ」の「角度B」に入力すると、「チューブ」は「1フレームにつき5°」ずつ回転します。なお途中に「角度の変換ノード」をはさんでいますが、これは「数式ノード」から出力される角度の値が「ラジアン」となるためです(数式ノードのオプションの「角度の単位」は「sin」などの関数が認識する値にのみ影響し、出力は常に実数になります)。

数式ノード

「円柱」のほうは「チューブより12フレーム遅れて動く」設定になっています。「チューブ」を回転させている値を「値を記憶ノード」に入力し、「古さ」が「12」の値を「円柱」の「角度B」に入力すると、12フレーム遅れて動くことになります。「値を記憶ノード」では「値を記憶する回数」を「13」とします(古さは0から始まる序数なので、回数としては13回になります)。

値を記憶ノード

「円柱」は1フレームで5°動き、「チューブ」はそれに12フレーム遅れて動くので、両者の差は「60°」になります。「チューブ」の隙間は「90°」で「円柱」のスライス角度は「30°」なので、アニメーションではちょうど端がぴったりくっついて動くことになります。これが本来想定していたXPressoの動作です。

12フレーム遅れで動き出し、角度の差は「60°」

いっぽう、フィジカルレンダラーでレンダリングしたほうでは、「円柱」は6フレーム遅れの7フレームめでもう動き出してしまい、両者の角度の差は「30°」になっています。このため、両者は離れたままで動き続けます。

6フレーム遅れで動き出し、角度の差は「30°」

フィジカルでの動作を補正した例

サンプルファイル:XP_phy_2.c4d

上記の差異を見ると、フィジカルレンダラーでは「値を記憶ノード」の「古さ」が1フレームにつき1ではなく2ずつカウントダウンされているようです。そこで、「古さ」を本来の「12」の2倍の「24」に設定してみます(値を記憶する回数のほうも「25」に増やします)。

「値を記憶ノード」の「古さ」を2倍の「24」に

この設定でフィジカルレンダラーでレンダリングすると、レンダリング結果は本来の想定通りになります。

フィジカルレンダラーで想定通りのレンダリング結果に

 

ただし、この方法には問題があります。当然ながら、エディタビューでのアニメーション再生や標準レンダラーのレンダリング結果のほうは、本来の想定とは違った結果になってしまいます。

標準レンダラーでは想定しない結果になる

フィジカルレンダラー対応の補正にオンオフスイッチをつけた例

そこで、先程XPressoに追加したフィジカルレンダラー対応の補正を必要に応じてオンオフできるスイッチをつけます。

サンプルファイル:XP_phy_3.c4d

まず適当なヌルオブジェクトなどに「ブール値」のユーザデータを作成し、名前を「フィジカルレンダラー」としておきます。

「ブール値」のユーザデータ

切り替えスイッチには「条件分岐ノード」を使用します。「条件分岐ノード」は複数の入力(デフォルトでは2つですが任意に増やせます)を「スイッチ」に入力された値で切り替えるノードで、スイッチが受け付ける値は「0」から始まる整数で、順に「0,1,2,3…」となります。

作っておいた「ブール値」のユーザデータ「フィジカルレンダラー」を、「条件分岐ノード」の「スイッチ」に接続します。「ブール値」の「フィジカルレンダラー」からは、オフのときは「0」、オンのときは「1」が出力されるので、「条件分岐ノード」の入力の数が2つならスイッチとして使用できます。

そして「1つめの入力」には通常時の「古さ」の値を、「2つめの入力」にはフィジカルレンダラーのときの「古さ」の値を入力して、ノードの出力を「値を記憶ノード」の「古さ」に接続します。これで「値を記憶」の「古さ」にはスイッチの「オフ=通常時」と「オン=フィジカルレンダラー使用時」のそれぞれの値が送られることになります。

「条件分岐ノード」による切り替えスイッチ

切り替えスイッチとなるユーザデータの「フィジカルレンダラー」はHUDとしてビューに配置しました。フィジカルレンダラーでレンダリングするときだけこのスイッチをオンにすれば、いずれの場合でも想定通りの結果が得られることになります。以下のレンダリング結果でも、標準レンダラーとフィジカルレンダラー、いずれも想定通りの動作になっています。

標準レンダラーでスイッチオフのレンダリング結果

 

フィジカルレンダラーでスイッチオンのレンダリング結果

 

まとめ

この例のように「値を記憶ノード」を使った場合のほか、「1フレーム毎に値が加算されていく」というような場合にもフィジカルレンダラーでは結果が変わるようです。また、値の補正が「古さ」を単純に2倍して一致する場合と、0から始まる序数として考えて「9の2倍は19」のようにすると一致する場合とがあるようです。

いずれも見たところフィジカルレンダラーではXPressoが1フレームにつき2回更新されているような挙動なので、そこを相殺するようなルーチンを加えれば補正できるのではないかと思われます。お役に立てば幸いです。