ゲームエフェクトデザイナーのブログ (新)

レポート記事とか色々。C#とかも触ったり。

メインコンテンツ目次

●ニュース

Unreal Engine 4UE4)について書いた記事(主にVFX Artist向け)

エフェクトツールを使ってできること
エフェクトのワークフロー

テクスチャのインポートについて
テクスチャのプロパティについて
テクスチャのフォーマットについて

マテリアル作成の基本的な知識
最終マテリアル入力の各ポートについて
パーティクル向けのマテリアルの設定について

BISHAMONについて書いた記事

BISHAMONの最初のステップ
BISHAMON Personal v1.8 の新機能について
BISHAMONへのカメラのインポートについて

●Houdiniについて書いた記事

Houdiniの学習について
Billowy Smokeを使った煙のチュートリアル(前半)
Billowy Smokeを使った煙のチュートリアル(後半)

Mayaについて書いた記事

MELの最初のステップ
MELのウインドウ作成について
MELでシェーダー作成 1
MELでシェーダー作成 2
MELスクリプトのある場所を参照する
MELを配布する時のプロシージャについて
UVの正規化
頂点カラーを別のモデルに転送
テクスチャの色を頂点カラーに転送

Photoshopについて書いた記事

Photoshopのスクリプトを書いてみる

C#やプログラム全般について書いた記事

C#のはじめ方
C#で正規表現による置換を行う
C# DataGridViewの主なプロパティ

C#で作ったツール一覧

GitHubでのツールやソース公開について(CGアーティスト向け)
ライセンスについてのメモ

●その他の記事

数学が苦手な人向けのCG数学シリーズ

イチオシゲームエフェクトアレコレ

処理速度と処理量のお話 ms(ミリセカンド)について
ドローコールについて

おおまかな開発コストの計算方法
おおまかなゲームソフトの売り上げの計算方法

勉強会開催のすすめ
大阪・京都の貸し会議室メモ

続きを読む

UE4 SphereMaskで距離に応じて色を変える

UE4のマテリアルで距離に応じて色を変えたい場面があります。
例えばカメラに近付くと色が変わるとか透明になって消えるとか。

そんな時は「SphereMask」ノードを使うと便利です。

使い方としては例えばこのような感じ。

f:id:moko_03_25:20180516023158j:plain

するとカメラから半径200以内に入ると白くなります。
黒から白への遷移はHardnessで調整します。

f:id:moko_03_25:20180516023151g:plain

この時のRadiusとHardnessの関係をイメージにすると下図のような感じです。
HLSLのコードの中身までは見てないので違うかも知れません。。

f:id:moko_03_25:20180516025937j:plain

今回の例の場合だと、カメラからの距離(つまり半径)以内に対象が入ると 1 を出力し(白くなる)、外なら 0 を出力する(黒くなる)という感じです。
Hardnessは 0 から 1 に遷移する長さという感じで、1 にすると即値が変わりますが 0 にするとカメラの位置までかけて緩やかなグラデーションが付きます。

プロジェクトで運用する場合、Hardnessのパラメータを外部に出す際にはSoftnessにでも名前を変えて「1-x」ノードを挟んで0~1の入力を逆転させた方が直感的でユーザーフレンドリーになる気はします。

エフェクトでの使用例で言えば、パーティクルがカメラに近付いた際に突き刺さらないよう消えるようにしたりは定番と思いますが、World position OffsetとParticleSizeノードを併用してカメラに近付いたパーティクルのサイズを小さくしたりとかもできそうです。

この時、ピクセル単位ではなくパーティクル全体に影響するので良ければSphereMaskのAに入力するのはParticlePositionノードが良いかと思います。

UE4 PlotFunctionOnGraphで値をグラフで表示する

マテリアルを作成したり中身を解析したりしている時に、値の変動を脳内では処理できず紙に手描きでグラフを書くことがよくあるのですが、「値をグラフにするノードは無いものか」と思っていたところ hirapotさん(@hirappot)から「PlotFunctionOnGraph」というマテリアル関数を教えて頂きました!

hirapotさんありがとうございます!

ということで早速使ってみました。各Inputの説明は図に記述しています。
(Inputピンの「f(x)」にはUV座標のUを与えてやる必要があるっぽいです)

f:id:moko_03_25:20180516013935j:plain

するとこのような結果に!これぞ求めていたものです‥素敵!

f:id:moko_03_25:20180516013930g:plain

ちなみに中身を見てみたらこんな感じで把握するのが大変だったので‥

f:id:moko_03_25:20180516013927j:plain

とりあえず最小限の構成に整理してみました。
グラフのVと入力した値のUの距離(Distance)が 0(つまり一致する位置)に色が付くようになっているようです。

ただ注意がひとつあって、Inputでグラフの座標の範囲を指定しますが、その範囲をグラフ化したい値にも反映させないとグラフと値が一致しません。
そのため、グラフのVとTimeを足し合わせた結果を出力するようにしました。

f:id:moko_03_25:20180516013922j:plain

なので下図のように出力した値を使った値を入力する必要があって、ループした見た目の気持ち悪い構成になっていますが‥ひとまずこちらでうまく動作しました。
こういう時、マテリアル関数をふたつに分割すると良いのでしょうけれど、まいっかと。

ちなみに、試しにグラフ化するのに利用したのはLinearSine関数です。
このマテリアル関数は3つのOutputピンから三角波矩形波を出力します。

f:id:moko_03_25:20180516013919j:plain

1つめのOutputのLinearSineをグラフ化すると三角波になっているのが確認できます。

f:id:moko_03_25:20180516014032g:plain

ついでに2つめのOutputのRounded Linear Sineも試してみます。

f:id:moko_03_25:20180516014029j:plain

するとこんな感じ。
Debugノードで数値化はできますが、緩急はビジュアル化しないと分からないですよね。

f:id:moko_03_25:20180516014024g:plain

3つめのOutputのDirectionも試してみます。

f:id:moko_03_25:20180516014021j:plain

こちらは矩形波だということが確認できました。

f:id:moko_03_25:20180516014016g:plain

という訳で、グラフ化でした。お試しあれ!

何か間違っていたりもっと良い方法があったりしたら教えてください‥!
(customノードで直接描画するようにした方が綺麗なグラフにできますかね‥)

UE4 Dotproductでテクスチャのチャンネルを指定する

UE4のマテリアルで、テクスチャのRGBAのどのチャンネルを使うかをマテリアルインスタンスで指定したい場合があります。

そんな時、Static Component Mask Parameterを使った場合はこちらのように構成すると‥

f:id:moko_03_25:20180514010533j:plain

マテリアルインスタンスチェックボックスを変えることで自由に指定できます。

f:id:moko_03_25:20180514010538j:plain

しかしStatic Switch Parameterを使った場合と同様に、チェックボックスを変更すると別シェーダーとなり親マテリアルと同じデータサイズになってしまうという注意点があります。

この問題についてはEpic Games Japan篠山さんのスライドが詳しいです。

この問題を把握している上でStatic Component Mask Parameterを使用する分には良いと思いますが、代替えに良い方法があります。

それはDotproduct内積)ノードを使う方法です。

テクスチャとConstantノードをDotで掛け合わせるだけです。
この時、テクスチャとConstantノードはチャンネル(要素)の数を合わせておきます。

Dotでどのような計算が行われているかというと、テクスチャのRとConstant 4VectorのRを乗算、GとGを乗算、BとBを乗算、AとAを乗算、それらを全て足す‥という感じです。下図のConstantノードはR以外0が入っているのでR同士の乗算の結果だけが残るという訳です。

f:id:moko_03_25:20180514011443j:plain

そしてConstantノードをパラメータ化することで、マテリアルインスタンスで自由にチャンネルを指定することができます。内積がこんなところでも役に立つとは!

f:id:moko_03_25:20180514011836j:plain

こちらのテクニックはUE4標準のNormalFromHeightmap関数で使われています。

以上、知っておくと便利と思う小技でした!

C# 線グラデーション画像を作成するツール

ガンマの検証とか、単純にテクスチャとして使いたいといった理由で、1ピクセルごとに色の値が1ずつ増える「256 pixel 256 諧調」の完璧なリニアグラデーション画像を作成したいことってないですか? 私はあります。

PhotoshopSubstance DesignerやNukeなどでグラデーションを作成しても256pixelに256段階で推移しているのか確認すること自体が困難です。手作業で1ピクセルずつ塗っていく訳にもいきません。

ということでツールを作りました。

GitHubこちら。Zipファイルはこちら。ライセンスはMITです。

2018.5/13(ver.2)
 ボタンのサムネイルのグラデーションが間違っていたので修正

続きを読む

C# で作ったツール一覧

C#Windows Form Applicationで作ったツールが増えてきたので一覧にしておきます。

全てMITライセンスです。
ゲーム開発などお仕事でもご自由にお使いください。

GitHubはこちらです。

サブフォルダをリストアップするツール

サブフォルダの総サイズのリストアップ(ListBox編)
サブフォルダの総サイズのリストアップ(DataGridView編)

リスト管理できるテキストエディタ「List Fusen」

UE4のアセットの命名規則チェックツール

BMP画像に保存された色の値を調べるツール

線グラデーション画像を作成するツール

BMP画像に保存された色の値を調べる

ガンマの理解のためにも、実際に画像に保存される色の値を調べたい時があります。

先日「Photoshopでリニアな状態で作業する」という記事を書いた後に気になったので、こちらのサイトの解説を参考に、Photoshopで保存したBMPの中身をバイナリエディタStirling」で調べてみました。

それから、ウェブ上で2進法を10進法に変換してくれるサイトはこちら。

2進数、8進数、10進数、16進数相互変換ツール

中間グレーのBMPを用意


実際にPhotoshopで50%グレーの画像を作成し、作業用スペースをsRGBに設定した状態のものとLinearに設定した状態のものとをそれぞれBMPで保存。

f:id:moko_03_25:20180506011455j:plain

f:id:moko_03_25:20180501012329j:plain

バイナリエディタBMPの中身を確認する


「Stirling」で開いてみると、どちらのBMPも「7F」で埋め尽くされています。
この7Fが色の値ですが16進数なので10進数に変換します。

f:id:moko_03_25:20180506010650j:plain

先ほどのサイトで調べてみると「127」と分かりました。
ちゃんと中間グレーの値がそのまま保存されています。

f:id:moko_03_25:20180506011717j:plain

また、バイナリエディタで確認した2つの画像の中身はヘッダ情報も含め完全に一致しており、Photoshop(CS6)からBMP保存時にはカラープロファイル情報のチェックボックスがグレーアウトしますが、これで実際に保存されていないことが確認できたのではないかと思います。

※1:ググってみて出てきた記事によると、BMPには一応カラープロファイルを埋め込める仕様になっているそうですが対応しているアプリケーションはほとんどないとのこと

※2:PhotoshopからだとPSDは当然ですが、JPEGも保存時にカラープロファイルを埋め込めるようで、Photoshopで開くと保存前と同じカラー設定が適用されますが「Stirling」で調べるとsRGBで保存したファイルとリニアで保存したファイルの差異が激しかったのでそっ閉じしました

つまりPhotoshop上でどのカラースペースで作業しても、ディスプレイへの出力結果が変わるだけで、画像自体の色の値には影響が無いことが分かります。

自分は最近までこのあたりモヤモヤしていたのですがこれでスッキリしました。

Color Check Tool


ついでに、画像の色の値を調べるツールをC#で作ってみました。
制作時間はデバッグ含め2時間くらい。
放り込んだ画像サイズに合わせてレイアウトを崩さず丁度良いウィンドウサイズに広げるのに少し手間取りました。。ソリューション一式をGitHubにアップしています。

GitHubこちら。Zipファイルはこちら。ライセンスはMITです。

f:id:moko_03_25:20180506012212j:plain

大きな枠内に画像をドラッグ&ドロップして放り込んだ後、画像内をクリックすると画像ファイルに保存されている色の値をツール右側に表示します。
※追記:PictureBox内で補間の入る拡大縮小をしたりなど加工していなければ画像に保存された値と同じ値が取得できているは思うのですが‥このあたり何か判明したらまた追記したいと思います

ツール上での表示自体はsRGBになっているのではないかなと。。

そして中間グレーのBMPファイルを作業用スペースがsRGBの状態で保存したものとリニアのものと放り込んで色の値を見てみたところ、どちらも「127」であることが確認できました。

f:id:moko_03_25:20180506012553j:plain

ちなみに前の記事のスナップショット画像を放り込んで左のsRGBのファイルの色の値を出してみると、127 ではなく 125 と出ました。JPEGでもBMPでも同様でした。

Photoshopの画面のスクリーンショットを取ってPhotoshopで貼り付けて保存すると色の値が少し下がる?(真っ白の場合は 255 → 254 になりました)

f:id:moko_03_25:20180506012546j:plain

以前からガンマについて検証する際に画像をスクリーンショットで保存したりブラウザで表示することに正確性があるのか色々と不安がありましたが、ガンマ2.2かリニアかが比較できれば良いと思うので気にするほどではないですかね。。

パーセンテージと割合と単位

前回の記事に引き続いて「割合」についてさらに書いておきたいと思います。

前回は「割り算が苦手」という話をしましたが、数学を苦手に感じる大きな要素の1つが割り算ではないかなと思っていて、学習に際しては割り算への苦手意識を減らすことが重要だと考えています。

そして「割合」もまた、割り算に大きく関係します。

割合とは?


とても分かりやすい表の入った算数プリントが「ちびむすドリル【小学生】」というサイトで無料配布されていましたので、引用させて頂きたいと思います。

f:id:moko_03_25:20180423015113j:plain

日常生活では100%のように百分率を使うことが多いですが、数学やシェーダーの計算で百分率を使う場面はほとんど無いように思います。その代わりに「 1 を100%の値とした割合」をよく使う印象です。

「1 なら 100%」「0.5 なら 50%」「0 なら 0%」といった感じです。

PhotoshopのRカラー(8bit)の値は「0~255」なのはアーティストには馴染み深いですが、シェーダー等での色の計算は黒~白の範囲を「0~1」で表したりします。

UV座標も基本となる範囲は「0~1」で表しますし、「0~1」で表すことで「0.5なら半分の値」だし「2なら2倍の値」という風に、人間から見ても直感的でとても分かりやすく頭の中で計算もしやすくなりますね。

何かの割合を求める


例えば 5 リットルのペットボトルに 3 リットルの水が入っていれば「全部で 5 ある内の 3 」つまり「{\frac{3}{5}}」なので、「 3 ÷ 5 = 0.6 」になり、ペットボトルに対して水の割合が 0.6 ‥百分率で言えば 60% であることが分かります。

何かに割合を掛ける


割合は、何かの値に対して掛けると「その値に対しての割合の値」が出ます。

何かを半分(50%)にしたかったら 0.5 を掛けますよね。
30に対して 0.5 を掛けると 15 が出ますが、これは30の半分は15であるということです。

割合そのもの」は具体的な値(cmとかkgとか分のような)ではなく「何かに掛ける」ことでようやく「」になります。

割合が 0.3 だったとして、この 0.3 は長さなのか重さなのか面積なのか分かりません。
ですが「60分」に対して掛ければ「18分」が出ます。

60 * 0.3 = 18(60分の30%は18分)


これは後に解説予定の「三角関数」で「cosやsinに斜辺の値を掛けると実際の長さが出る」ことを理解するために必要な考え方になるかと思います。

1を単位とする


「1」は特別な数字だと思います。

割合での「1」は「100%」を表しますし、「1円」や「1時間」や「1cm」 や「1Kg」のような単位では「基準となる値」を表します。

これは結構大事なことだと思っていて「単位に定数を掛けたものが実際の値」という認識が必要な場面があると思うのです。
つまり単位が1cmなら「 1cm * 7 は 7cm」ということです。

例えば x,y 座標が ( 5, 3 ) だった場合は「xy座標の単位となる x=1,y=1 に対して 5 と 3 を掛けたものが現在の座標」と言い表すことができますよね。

「まだるっこしい考え方だなあ」と思うかも知れませんが、こちらも後に解説予定の「行列」が出てきた時に、必要になってくる考え方だと思います。

単位である 1 の値を出して計算を楽にする(正規化)


拡張された「帰一法」 | TETRA'S MATH

こちらの記事の例題が分かりやすいので引用させていただきます。

7cmで35gの棒は、15cmで何gになりますか


この場合まず「 1cm は何g か?」が分かれば計算が楽になるので、35g を 7 で割ります。
すると「 35 ÷ 7 = 5 」で「1cm は 5g」と1cm単位でのグラム数が出ます。
そしたら「1cm分のグラム数(5g) * 15cm = 75g」と計算しやすくなって答えが出ます。

こういった計算方法を「帰一法」というそうです(覚えなくて良いです)。

CGでは計算しやすくするためなんかに値を 0~1 に収めることを「正規化(Normalize)」と言いますが、MayaのUVエディタでUVを 0~1 の範囲にすっぽり収まるようスケーリングする際に、メニューから「正規化」を実行しますよね。

この正規化は帰一法と同じ考え方のようです。

他にも、シェーダーの計算でベクトルを正規化することがありますし、この数学シリーズでもベクトルと内積の解説の際に正規化が登場する予定です。

また、カラーとガンマの計算をする際には、RGB値を 0~255 の 8bit の単位ではなく 0~1 の正規化した単位に置き換えてから計算する必要があります。

例えば、RGBの値がPhotoshopで「37」の場合‥
0 から数えているので +1 して {\frac{38}{256}} の状態ですよね。
すると割合は「0.1484375」で、正規化‥つまり「1が100%」の場合は割合である「0.1484375」がそのまま実際の値になります。

こちらを2.2乗したり0.4545乗したりしてガンマが絡む計算をすれば良い訳ですね。

という訳で「割合」とか「単位」とかの話でした。

Photoshopでリニアな状態で作業する

「リニアワークフロー」とか「PBR」といったことが当たり前になってからも、Photoshopでは画像をリニアな状態で作業できないと思っていました。

正確に言えば32bitモードにすれば可能とは知っていましたが、8bitモードでカラースペースをリニアにできるとは知りませんでした。

そんなとき、作業用スペースをリニア(Gamma 1.0)にする方法を千葉章人(@chiba_akihito)さんから教えていただいたので記事にしておきたいと思います。
千葉さんありがとうございます‥!

ちなみに管理人のPhotoshopはCS6なのでその点はご注意を。。

まず、デフォルトのカラースペースである「sRGB IEC61966-2.1」の状態で、8bitモード と 32bitモード の中間グレーを見比べるとこのような感じ。
(中間グレーは真っ白キャンバスに黒50%で塗り潰したもの)

右側の 32bitモード だとリニアになっています。

f:id:moko_03_25:20180501012329j:plain

そして本題の作業用スペースをリニアにする方法を。

まずはメニューの「編集>カラー設定」を開きます。

f:id:moko_03_25:20180501012326j:plain

カラー設定ダイアログの「作業用スペース>RGB」内で「カスタム RGB」を選択します。

f:id:moko_03_25:20180501012323j:plain

「カスタム RGB」ダイアログで「ガンマ」を 1 に設定します。
OKした後に、カラー設定を保存しておくと良いかも知れません。

f:id:moko_03_25:20180501012321j:plain

すでに開いているファイルなど別のカラー設定のファイルに対して今設定したガンマ 1 のカスタム RGBを適用したい場合は、「編集>プロファイルの指定」でカスタム RGBを指定します。

するとこのようにリニアな状態になりました。

f:id:moko_03_25:20180501012317j:plain

今まで検索しても見つからず、過去にGammaに詳しい方に聞いても回答を得られなかったりしたのでてっきりできないものと思っていました。。

お試しあれ!
 

UE4のマテリアル関数「CustomRotator」の中身について

UE4のマテリアルでUV座標を回転させたい時に中心位置を自由に指定したい場合は「CustomRotator」というマテリアル関数が便利ですが、数学の回転行列を理解すると中身が理解できたのでメモっておきたいと思います。

という訳で、CustomRotatorの構成のスクショにそのまま説明を入れました。

f:id:moko_03_25:20180501001659j:plain

「-sinとsin逆じゃない?」と思うかも知れませんが、数学で出てくるxy座標のグラフと違ってUV座標は原点が左上なので、y軸のプラスマイナス方向が逆転しているためだからかなと。

工程①と③の「UV座標をズラして元に戻す」というのは、つまるところ下図のようなことかと思います。

f:id:moko_03_25:20180501004824j:plain

ちなみにCustomRotatorを使ってUVのタイリング数を変えても真ん中で回転するようにしたい場合、下図のように組むと良いかと思います(Divideで2で割るのではなくMultiplyで0.5を掛けているのは計算を軽くするため)。

f:id:moko_03_25:20180501005111j:plain