Author: chokopan

RadeonRaysを使ってみた

どうも,チョコです.

最近レイトレーシングをちょっとやってるんですけど,流石に自分でメモリ構造体を作るのが不効率すぎて辛い.昨日Siggraph Asia行った時に見たRenderMan22が速すぎて衝撃を受けました.

そこで,AMDが開発したRadeonRays(以下RR)というオープンソースなライブラリを見つけました.しかもopencl1.2なのでいろんな環境で動きますね.

(ここでレイトレプロのみなさんへの忠告です.この記事を書いた僕はくそレイトレ―シング初心者です.画像を見て吐き気がしたら見るのをやめましょう.)

さて,RRのサンプルを動かしてみよう.ここではVisualStudioを使ってCornellBoxサンプルをコンパイルして見ましょう.

DmqIdRdUwAA2Wmt.jpg large

おう.すごい.

しかし,これだとレイトレっぽくないので,とりあえず反射を入れましょう.

反射とは要するに,レイをdとしたら,表面の法線nに対して

d’=d2(dn)n

を計算すればいいですね.また,この時,最終の色は元の色と乗算します.

DmqWF7MV4AEb7vS.jpg large

レイトレっぽくなりましたね.

次に,反射をDiffuseにしましょう.ここではLambertを使います.Lambertは簡単にいうと,入射角と法線の内積で明るさが決まりますね.まずは単純に,表面から半球の法線をランダムに決めて内積を取って乗算します.ただし,ここでは光源を円に変え,円に当たらなかったレイは黒にします.

cwe

ノイズ高いですね(適当).

Diffuseの次は当然Specularですね.ここではBeckmannを使います.説明が面倒なのでググって.ただし,普通にランダムに取ると収束まで結構時間がかかりますので,ここではImportance Samplingを行います.

BeckmannのImportance Samplingはここを見てください.

LambertのImportance Samplingはここを見てください.

Specularだけだとこうなります(Beckmann coefficient = 0.2).

s

ピカピカですね.

DiffuseとSpecularの組み合わせはShlick’s Fresnelを使います.とりあえず単純に,このFresnelの値を確率のカットオフとして,ランダム値がこの値より小さかったらSpecular反射を解散して,そうでなかったらDiffuseということにします.こういうことです.

すると結果はこうなります(Specular = 0.4).

wv

ノイズ高いですね(これしかコメント言えん).

箱は見飽きたので,サルを入れてみましょう.サルは金属にしましょう.

Screenshot (381)

ふむ....

サルは可愛くないので,シャロちゃんを入れましょう().CornellBoxも消して,Skyboxを入れましょう.

レイが表面にぶつからなかった時,方向を使ってSkyboxから色をこのように取ります.ただし,レイがまだ反射していないものなら黒にします.

するとこのようになります(適当).

Screenshot (385)

かわいい...


まだまだダメですが満足したのでやめます.最後にコメントです.

RRのGeneratePerspectiveRaysは視野を気にしないので,表示の縦横比を帰ると変になります.そのため,GLMの行列を使って書き換えます.

Importance Samplingが入っているLambertとBeckmannのコードです.ただし,乱数生成器はXorshiftを使います.

では.

Blenderで脚を作ります

どうも。チョコです。

気づいたら12月になって、Advent Calenderに調子乗って2日投稿にしたのに何も書くネタが思い付かなくて焦っている(1日現在)。

これだと総代表様から怒られが発生するので、僕が一番素早く記事にできるものは何だろうと自分に問い詰めた結果、”Blenderでの KCSちゃん 幼女 名取 脚 の作り方”にたどり着きました。ちゃんと真面目で健全な内容なのでご安心ください。それでも総代表様から怒られが発生しうるが。

(Advent Calender2日目にこのようなしょうもない記事を出して誠に申し訳ございません。)

(私はプロモデラーではないので、これが脚のモデルのやり方だ!というのはあまり大きな声で言えないが、まあ参考までに。)

(タイトルを「Blenderでの脚の作り方」にしたかったんですけど、ちょっと調子に乗ってそうなので変えました。)


さて、脚はモデルの半分なので、綺麗に作るに越したことはありません。SDキャラだったら脚はcylinder作って若干下の部分を縮めば出来上がりですが、愛着が湧かないのでここではフルサイズキャラについて語ります。

Screenshot (461)
図1:SDのKCSちゃん

*愛着が湧かないというのは脚へのことであって、別にKCSちゃんへ愛着が湧かないなわけではありません。KCSちゃんには常に日頃愛着が湧いています。

ただし、綺麗な脚を作ろうと思うと、ボーンを物凄く入れて筋肉表現を表すことももちろんできますが、やりません。変態(褒め言葉)じゃないので。あくまでゲームで使うモデルで最小限のボーン数で再現できる範囲で作ります。そのほうが参考になるかと。多分。

Siri

脚が始まるところです。アニメーションをつけるキャラクタには、動かすことを意識して作らなければなりません。特に、脚が曲がったときにSiriの部分に体積が足りないとこうなります。

Screenshot (465) Screenshot (466)

図3:Siriが消える

したがって、この状態でも大丈夫よう、Siriの下部分に頂点が近づけますね。これが横から見ると特徴的な形状になりますね。ウェイトをつけるときは上のほうの頂点に影響少なめにすると、いい感じに曲がります。

Screenshot (462) Screenshot (463) Screenshot (464)

図3:頂点を足した

ただし、脚は裏には曲がりませんので、頂点が変になっても気にする必要がありません。脚が後ろに曲げたいときは腰のボーンを曲げましょう。

太もも

一番大事なところですね(個人的な意見)。太ももを前から見たときに、内側は3次曲線で外側は2次曲線、という認識を持っていますね。形状をもっと強調したいときは内側の下部分にU型のトポロジーを入れます。

a

図4:太もも

また、気づくかもしれませんが、内側の膨らみは筋肉なので、内側の方が食い込みます。つまり、ニーハイやベルトを装着するとこうなります。

asdfffdsa

図5:ニーハイの履き方

(ニーハイに食い込みは作らないですって?物理法則違反です。作りましょう。)

膝もまた変形するところですね。察すると思いますが、内側より外側の方に頂点を多く入れますね。膝の形も強調したいので、前から見るとU形になっている感じで作ります。そうすると小牛も自然に後ろに生えます。

膝の裏は、曲がるときに食い込みが発生する問題を解決するために、曲がるところに変形する頂点を置きません。また、靱帯は上から下に生えて逆Vを作っていますので、ボーンのウェイト平衡点を上部分にずらします。すると比較的に綺麗な曲がり方ができますね。あと、足も同じく前に曲がることはないので、膝のウェイトは太ももボーンが支配的ですね。

Screenshot (467) Screenshot (468) wfer

図6:膝

(うん?何か飛ばした?幻覚です。)

足は下から見ると特徴的な形状を持ちますね。正直いうと大体靴か靴下を履かせていますので生足経験が少ない(パワーワード)が、基本的にはこの不均一感を出すのは大事ですね。特に、内側が上に上がる部分はちゃんとあげましょう。

また、足首から足指にかけては、”へ”の形がしていて、決して平らや球状ではありません。足小指に行くと位置は後ろにずれますので、上から見ると斜めの配置になっていますね。

そして、足の裏は一本の太い靱帯と両側の凸の間は若干食い込みます。これを意識して作ると特に制服の靴を履くと若干隙間ができていいです()。

egrs
図7:足

(こうして記事にまとめると,足へのこだわりが足りないことに気づきますね.足だけに.反省.)

結論

以上のポイントを全部合わせると、綺麗な脚を作ることができるんでしょうね。まあ、場合によって強調する量を調整したり、違ったトポロジーで作ったりしますので、決して鉄則ではありませんね。3Dモデリングですから。

このしょうもない記事をここまで読んでいただいてありがとうございます。最後に、参考までに僕が2年前に作ったえりりを見てください。脚にはそれなりに力を入れました。

*これはAdventCalender 2日目の記事です*

←1日目 3日目→

矢上祭とSwitch

チョコです.

矢上祭,お疲れさまでした.

今年もぴょんぴょん(+)人気だったな,,,,思った以上に「面白い」,「ハマる」って感想いただけてすごくうれしかったです.

 

さて,ぴょんぴょんですが,去年のゲームジャムで3日で作ったにして結構人気があったシューティングゲーム.今年用に二人プレイできるようにしたのと,かわいいかわいいKCSちゃんモードを入れました.

3

図1:ぴょんぴょん+の宣伝図(宣伝してない)

このゲームを毎年プロジェクターを使って大画面でやるのが恒例なのですが,KCSは Oculusを買う金はあるのに 同じコントローラーを二つも持っていません.ではここで,「試しにNintendo SwitchさまのJoyconを使ってはどう」という発想に至ったわけです.

さっそくSwitchを借りて,やってみよう!と思ったわけですが,ここでとても重要な2ポイントがあります.

1.PCにはBluetoothで通信できる

2.UnityはJoyconをコントローラーとして認識できる

まさに神.2秒で移植できるじゃん.(1日かかりました)

(1ですが,Joyconの上にある小さいボタンを長押ししながらpairingをしないと認識できません.)

とりあえず,ボタンを軸登録することですね.なお,キーボードででも同じ操作ができるように,以下のような入力ラッパーを書きました.

public static bool jbt(int i, int j) {
    return Input.GetKey("joystick " + i.ToString() + " button " + j.ToString());
}
public static bool jump(int i) {
    return Input.GetKey("space") || jbt(i, 4);
}

リスト1:InputManager.csの一部

ボタンのIDはこんな感じですね.

httrhgtrh

図2:JoyconのボタンID

Bluetoothの登録順でjoystick 1, joystick 2, …で決まりますね.つまり,複数台Switch持ってれば(ry

 

最後に,Input.GetButtonDown(“Jump”)を全部InputManager.jumpに変えるだけですね.

 

あ,そう.あとは一人プレイ用に書いたガバスクリプトを二人プレイにしたときに発生したバグの塊を解消する作業ですね...

 

来年も出したいな,,,(卒業しなくていいの?)

完.

UnityでのDeferred Celシェーディング

どうも,チョコです.院試おつ↓かれ↑ーい.

いつものUnityでのCelシェーディングをやっていました.しかし,シェーダを全部Cel式に変えるのはめんどい.そしてunlit shaderで照明を扱うのはどうも釈然としない.そこで,Deferredでなんとかならない?と思ったわけです.

UnityではDeferredの内部シェーダを変えられるようになっています.このように.

(Edit->Project Settings->Graphics)

Screenshot (13)

ここに自分のシェーダを突っ込めば,カメラの出力を制御できるというわけですね.

さて,これをやるにはまずbuiltin_shadersアセットをダウンロードしないといけない(ダウンロードページにあります).そして,Internal-DeferredShading.shaderを見つけます.

シェーダを中を見ると,おっと,この部分は画面に色を吐いているなと,読めばわかると思います.

half4 CalculateLight (unity_v2f_deferred i)
{
    ...
    half4 res = UNITY_BRDF_PBS (data.diffuseColor, data.specularColor, oneMinusReflectivity, data.smoothness, data.normalWorld, -eyeVec, light, ind);
    return res;
}

なるほど.つまり,ここの戻り値を変えればいいと.さて,Celシェーディングでやりたいことを確認しましょう.

deftoon

図の通り,まずは白の材質に対しての照明を得て(1),そしてCel風のカーブにし(2),最後にDiffuseを適用(3)すればいいです.上のコードを書き換えましょう.

uniform float _deferred_cutoff;
uniform float _deferred_shade;
uniform float _deferred_saturate;
half4 CalculateLight (unity_v2f_deferred i)
{
    ...
    half4 inten = UNITY_BRDF_PBS (half3(1,1,1), half3(0, 0, 0), 1, 0.5, data.normalWorld, -eyeVec, light, ind);
    float brg = clamp(ceil(inten.r - _deferred_cutoff), 0, 1);
    float shd = 1-((1-_deferred_shade) * (1-data.smoothness));
    return half4(saturate(data.diffuseColor * (brg * (1-shd) + shd), 1 + _deferred_saturate - (_deferred_saturate) * brg), 1);
}

(デフォルトシェーダの仕組みはどこにも書いていないので,関数の意味などはCGIncludesの中身を自分で読まないといけませんね)

はい.ここで,UNITY_BRDF_PBS は(1)なので,それを(2)にしたのがbrgとなって,最後にdata.diffuseColorを適用しました(3).

最後に,Inspectorでデフォルトのシェーダを変えよう.そしたら(エラーがなければ)オブジェクトのマテリアルを一切触っていないのにカメラの出力が変わります.

Screenshot (12)

これで1つのシェーダでアニメ風にできますね.スタイル変換捗りー.

(実はこの方法は,照明ごとに行われるので,光が重なるととても明るくなります.解決したらパーツ2の記事にします)

では.

StackTraceを実装する話

* この記事では、MSVCのinlineアセンブリ構文を使う。
** C++はあまり詳しくないのと、深夜テンションで思いついた実装なので、もっと速い・簡単なやり方があればぜひ教えてほしい。

Unity3Dをやっている人は分かるが、簡単に実例を説明しよう。例えば、描画関数の中でしか使えない関数がある。

void OnDraw () {
    Game::DrawCube(...);
}

ここでGame::DrawCubeはOnDrawおよびOnDrawで呼ばれた関数からの実行出なければいけない。では、エラーチェックとしてOnDrawから呼ばれたかを確認したい。

じゃあ、これをどう実装すればいいのかという話。もちろんStackUnwindとかのライブラリ使ってもいいけど、そもそもデバッグではなくて実際のリリースでも使いたいのと、関数の名前より関数のIDを見るのと、個人的に人の実装を使いたくない癖(ここ重要)がある。

  • StackFrameについて

さて、C++(別にC++じゃなくても)のDisassemblyに着目する。関数が呼ばれたときにstackをみると

address   value
------------------------
EBP-4     return address
EBP       old EBP
EBP+4     funcvar1
EBP+8     funcvar2
...

になっている。これを関数のStackFrameと言う。

では、EBPはこの関数のヘッドを指しているが、その値がなんと呼ばれた関数のヘッドのアドレスが入っている。つまり、

mov EBP [EBP]

をやれば、StackTraceをすることができる(EBPは破壊されるのでこのまま使わないが)。

  • アドレスに着目

関数というのは、あくまで下のようにStackにある変数を操ったりする命令の集合である。例えば、以下ではDrawCubeを呼ぶOnDraw関数の例である。

        OnDraw:
0x123     instruction 1
0x125     instruction 2
...
0x200     call Game::DrawCube (0x502)
0x204     ret

(0x502はGame::DrawCubeのラベルが存在する位置である。例えばOnDrawだと0x123となる)

ここで、Game::DrawCubeが呼ばれた時のStackFrameを見ると、return addressが0x204となる。つまり、この関数が終わったらEIP(instruction pointer)がどこを指せばいいかを教えている。

では、この情報をどう使えばいいかとなるが、まず「呼ばれた関数」の定義を改める。「この関数はあの関数であるか」というのは、厳密に言うと「この関数のreturn addressは一緒なのか」となる。なぜかというと関数の名前より、システムが描画したいときにしか呼ばない「一ヵ所」からの実行だからである。

  • 実装

まず、OnDraw関数を呼ぶところは一定なので、下のようにあらかじめ登録することができる。なお、ラベルはアプリで共通されるため、__COUNTER__などでユニークなラベルにする必要がある。

int funcLoc;
__asm{
    uniquelabel1:
    mov EAX, offset uniquelabel1
    mov funcLoc, EAX
}

なお、このコードは関数を呼んだ直後に入れる。

次に、DrawCubeの中で、親(の親の親の…)のreturn addressがfuncLocであるかを確認すればいい。

偽コード
for EBP=*EBP
while *(EBP+4) != funcLoc ;

実際のコード

__asm{
    mov EBX, EBP
  loop:
    mov EBX [EBX]
    mov EAX, [EBX-4]
    cmp EAX, funcLoc
    jne loop
}
  • Access Violation防止

上のループは、funcLocが見つからないと永遠にループしてAccessViolationエラーが起こる。これを防止するにはどこかで止める必要がある。まず、mainスレッドからの関数と考えれば、
1. assert (std::this_thread::get_id() == mainThreadId);
2. asmのなかに

cmp EAX, mainThreadFuncLoc
je end

ただし、mainThreadFuncLocはmain()を呼んだ__CRT_Startupなんちゃらの場所である。

  • まとめ

アセンブリをいじることで、関数の親をトレースすることができた。この方法を使って、この関数を呼んだ親を区別することも可能となる。なお、デバッガでRTCが入ると、関数が実行された後にEBPの確認instructionが入るので、アドレス登録が動かなくなる場合がある。解決方法考え中(とりあえずオフにした)。もちろんリリースでは影響されない。

Winapiでプロセス間のリアルタイム映像転送

どうも、チョコです。久しぶりの進捗がありました。

今回は、OpenGLの2つのアプリ間で通信をしないといけないことになりました。ただし、リアルタイムの生画像転送なので、100mbpsくらいの速度が最低ないと困る。

ポートとかパイプあけて通信すればよいではという考えもあったが、アプリAがアプリBの好きなデータを取れるようにしたい(そういうプロジェクトだから)。なので、いちいちデータの名前送ってデータをもらうとすごく面倒だし、なにより遅い。

そこで、WinAPIのReadProcessMemoryです。要は、アプリAがアプリBに親権限を持っていれば、なんでもしていいよとのこと。よさ。
WriteProcessMemory(HANDLE processHandle, void* source, void* destination, ulong numbytes, ulong* numbytesread)

*sourceはアプリBでのポインタ値で、destinationはそのポインタの指しているデータをアプリAにコピーする場所。destinationを先に初期化しないといけない(それはそう/1時間消耗した。)。
ん、読みたいところのポインタがないとできないね(それはそう)。ので、まずはポインタ集というStructを作ります。
struct PointerList {
uint hasDataLoc, pixelsLoc, pixelCountLoc, displayWLoc, displayHLoc, okLoc;
} pointers;

*win32なので、ポインタは32ビットunsigned intに変換できます。
なので、最初にこのStructを読み取れば、すべてのポインタがわかるね。わーい。

実際にやったものを見せよう。

わーい。(ただこれを見せたかった)

では。

Assemblyコードの最小化(?)

どうも、チョコです。Assemblyちょっとやってたら調子に乗って記事書きました。誤りがあったら訂正お願いします。

この間、BootLoaderを書いていたが、ファイルサイズが1Sectorの512バイト(-署名2バイト)に入らなければいけなかったため、最適化を行った。(もちろん、ほかのSectorを呼び出して実行はできるが、それでは面白くないから。)

BootLoader#とは?

パソコンが起動したとき、BIOSが初めて実行する512バイトのプログラムをMBRと呼び、このコードがWindowsなどのOSの起動(Boot)をすればBootLoaderと呼ばれる。

最小化#とは?

ここでは、RAMとかStackの最適化とかせずに、実際にコードが保存されているバイト数の節約をする。512バイトしか使ってはいけないので、油断するとすぐ使えないプログラムになってしまう。なんでC++で書かないかのも、このためである。(gcc使えないからとかは黙っておこう)

(ただし、MBRはRealModeで実行するので、Registerは最大32ビットである。)

512バイトで何ができる?

例えば、テトリスのゲームを作ろう。こんな感じの。(最適化の話なので、実際のプログラムはどうでもいいかと)

DA0a29XVoAAfyv6

(作り方を詳しく聞きたい人は、これが完成したら記事を書くので、お楽しみに。)

ここで、移動の処理だけのコードを書くと、なんと100バイトくらい使った。ブロックを積み重ねる判定付けたら180バイト使った。残りのバイトでクレアとか回転とかを実装できそうにないなぁと。

では、プログラムのバイト数を削ってみよう(実際の処理内容は変わらない)。

1.一回しか使わない関数はinlineで書く。逆に、2回以上使う長い処理は関数にまとめる(こっちは常識だな)。call[address] … retは6バイト消化してしまうため、重複処理が6バイト以上であるときだけ関数を使うべき。またRegisterはGlobal変数なので、関数内で宣言もできる。

2.xorを使う(Assemblyでは常識かな)。Registerを0にしたいときにmov EAX,0を書くと4バイト使ってしまうが、xor EAX,EAXを書けば2バイトになる。

3.sub-registerを用いる。EAXの後半がAXで、AXがAHとALの合成など、必要な所を読み、変更できる。例えば、AXは最初が0であれば、mov AX,1とmov AL,1は両方1になるが、AXの場合は2バイトなので結局mov AX,0x0001となり、1バイト無駄になる。

いまは大体こんな感じ。使っている定数に対するregisterのバイト数を気にすると結構バイト数減らせた。以上のことをやるとなんと20バイト以上減らせた。わーい。

(まだ現在進行形ですが、)ソース

では。

BlenderでXray目の再現

どうも、チョコです。多く知られているMultipassのやり方を(今更)理解したので共有したいと思います。

BlenderではMultipassのことをRenderLayerといい、Compositorで組み合わせができる。

ラムのモデルでデモしよう。

Screenshot (1226)

 

髪の毛の前に目を出したいので、まず目と髪の毛を別のオブジェクトにして、髪の毛をレイヤ2にする。

RenderLayerを2個作り、それぞれのマスクを設定する(Hairはレイヤ2しかレンダしない)。

Screenshot (1221)

これをレンダすると、髪の毛が消えた。さて、Compositorで合成しよう。InputNodeを2個使えば両方のRenderLayer画像が入手できる。

 

レイヤ1から目の部分を切り取りたいので、ObjectIDマスクで分離する(目のObjectID1にした)。

Screenshot (1224)

最後に、二つのレイヤをCombineZで合成し、さらに上から切り取った目をAlphaOverする。

Screenshot (1225)

完成。では。

 

OpenGlでスポットライトを実装

チョコです。

エンジン作ってますが照明システムが必要となりました。そこでスポットライトが一番簡単なのでまずそれを実装しました。

Screenshot (1141)

プロセスを説明します。

Deferredなので、まずオブジェクトのパスを出します。zバッファーを使います。

Screenshot (792)
そして、光パスで画面スペース→世界スペースに変換し、光からの距離、角度を出します。割と簡単な数学演算なので省略。
そこで、影がないとおかしいので、影も実装しました。
光パスの前に、光を視点としたMVP行列をかけ、画面をもう一度レンダ―し、マップに保存します。
Screenshot (1142)

光の行列をシェーダーに渡し、世界スペース→陰スペースを算出します。そこのz値を出します。

Screenshot (1143)

陰スペースの自分のz位置と比べて、影かどうかを判断します。完成。biasなど全然かけてないのに割といい結果を出せました。

シェーダーコードも載せときます(フラグメントだけ)

 

これからはポイントライトやら一方向ライトやらの陰も実装しますが、意外と面倒なのでゆっくりやります。では。

ホラーゲーム作ります:テクスチャ・演出・D言語くん

バイオ7出ました。素晴らしくて泣いた。決して怖くて泣いたのではありません。

せっかくなので試しにホラーゲーム作ってみたい。ホラーゲームも一人称ゲームも作ったことないし。

早速モデル作りました。こんな感じです(Blender内です)
asdfasdf

これどっかで見たような。。って思ったあなた、友達になってください。
(がっこうぐらしですねはい)

でもこれテクスチャがないとあまり怖くないですね。SubstancePainterに移りましょう。(ここから宣伝)

まず古い校舎感を出すために、「Coarse cement」のレイヤーに「Fine cement」をかけて、マスクで削る壁を演出した。さらにその上にほこりを載せる。

Screenshot (683)

おお、いい感じ。(これにはあらかじめ分割したモデルをベースにノーマルなどをベークした(例の椅子のヤツです))

では、ちょっと血を入れます。物理エンジン(?!)が使えるので、HeavyLeakingやBurn効果(Diffuse色やSpecular, Glossinessをいじったもの)を使ってみよう。

血はDiffuse #770000 Specular #ff6666 Glossiness 0.3かな(だいたい)。旧い血痕はSpecular低めで。

particles

グロ。でも好き。

さて、これをUnityにエクスポートしよう。Export Textures押すとUnityのStandard Materialがすぐ使えるDiffuse, Specular, Normal, Height, Occlusionマップが生成される。これを適用してみよう。

普通の照明じゃ面白くないので、カメラについているSpotlightで照らそう。

Screenshot (727)

怖い怖いちょっと待ていい雰囲気じゃねぇか。ほんとのホラーゲームっぽいぞ。(ホラーゲームです)

 

他のアセット:

1.KCSxUnity本

Screenshot (693)

2.D言語くん Screenshot (719)

↑Sketchfabはいいぞ。

この感じでアセットを作ると超便利で速い!

 

(ネタばれしたら実際のプレイも怖くなくなるので、他のシーンのものは見せられません。お楽しみに。)

では。