Author: chokopan

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はいいぞ。

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

 

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

では。

Unityを拡張しよう!#2: 表面分割アルゴリズムの実装(Part 1)

どうも、チョコです。あけましておめでとうございます。

さて、今年初の記事です。わーい。
(もともと去年に完成させたいものですが、バグが出てきてそのまま年越えましたorz)

さて、今回は”Catmull-Clark 表面分割をUnityで使いたい!”と思ったので作ってみました。はいストップ。Catmull-Clarkは何ぞや。説明します。
Catmull-Clark Subdivision Surfaceとは、とあるメッシュを分割し、比較的に滑らかな四角ポリゴンからできたメッシュにするアルゴリズムです。

ニホンゴデハナシテ。

見ていただいた方が早いので、↓の通りピラミッド、キューブとn角はてなメッシュを表面分割させました。

screenshot-426

あらきれい。滑らかになってますね。
ちなみにBlenderではこのようにModifierを追加することで表面分割させられます。

screenshot-428

Catmull-Clark出てきましたね。

では、これをUnityに入れたいと思います。ちょっとまて。なんで入れるのかな。Blenderではもうこの機能ついてるのに??

答え:>>>アニメーションのためです!ボーンを付けてアニメーションさせたところ、Modifierは全部消されてしまいますボーンModifierの前に適用されます。じゃあそもそもボーンの後に表面分割する必要ある?って思ったあなたへ、下の図をご覧ください。

screenshot-434

足ですね。曲がるところに頂点がないことを確認してください。
でもちょっと頂点数少ないので、表面分割しましょう。

screenshot-422

円滑になりました。でも左の方はなんか不自然ですね。これは分割してからボーンを付けたせいですね。曲がるところに頂点が入ってしまいますので、これを2本のボーンだけでは数学的には右のような形にはできません。説明略。
右のほうを見ると頂点は全く同じで、ただボーンと分割の順番を逆にしただけできれいになります!!

疲れた。まだ本文に入っていない。まだちょっとありますので我慢してください。

では、このアルゴリズムをUnityに入れ(たいと思い)ます。Catmull-ClarkのWikipediaページをご覧いただくと、頂点の関係式は中学レベル以下ですね。記事書く必要ある??って思うかもしれません。こんなの3秒で書いてやる!とか、思いましたか?私か思いました。orz

さて問題:よく読むと、このアルゴリズムはN角形に対応しています。そこでUnityは、なんと、三角形(時には四角形)しかできないのです!!!

それだけではありません。メッシュを分割させるために、ボーンに変形された頂点位置が欲しいが、これも、なんと、シェーダー側でしか手に入れられないのです!!!(実はBakeMesh()関数もありますが、indexなどがめちゃくちゃかつ遅いのでやめました。)

ち。面倒なことになってきましたね。そもそも面のデータが取れないのに、どうやって実装するんだ。

あれあれ、この前も記事書きましたよ?この記事#2ですから、#1はどういう内容かな。
それはなんと、Unityにimportされないデータを読み取れるエディタースクリプトでした!!!!!パチパチパチ。
リンク張っておきます。

(ここからが実装の本文になりますが、正直いちいち説明するのがめんどいので手順だけ紹介します。詳しく知りたい人はGithubページへ)

まず、1で作ったスクリプトをEditorで呼ぶことにしました。.netでBlenderのexeを見つけて、それにアセットを入れて、同じフォルダーにデータを出力させました。こんな感じです。(.blend)の隣のn++ファイルが出力ファイル。

screenshot-429

これで面のデータが取れますので、これを表面分割アルゴリズムに突っ込みます。中学レベルの数学なので省略。
*ここでは、頂点を生成するアルゴリズムを実行しました。この関数はStart時点に一回だけ実行したいので、頂点関係をあらかじめバッファーに入れました。データ構造以下のようです。

screenshot-430

次に、変形された頂点の位置を読み込み、関係式に突っ込みたい。あれ、データが入手できない。ち。

シェーダーを使うしかないですね。では、どうやってシェーダーから頂点データを出力すればいいんだ?

やり方は2通りあります。テクスチャに書き込むか、ComputeBufferを使います。

テクスチャ使ったら、まあそれは簡単になりますし、一般のパソコンでも動くでしょうけど、分割したいメッシュ1体につき、カメラが一個増えます!!
仕方ない。ComputeBufferを使います。

待てよ、ComputeBufferつうのは、シェーダー語のRWStructuredBufferなので、行列のindexはどうするんだ??
indexは頂点のindexと同じなので、シェーダーが今レンダ―している頂点のindexを分かればよいのです!。。。どう渡すんだ?

答え:>>>UVマップを使います!!そもそも最終的にオリジナルメッシュは見えないので、UVを使っても問題ない!!

というわけでシェーダーはこんな風になります。

screenshot-431

さすがに長すぎますので、Part 2に続きます!戻ってくるぜ。

Unityを拡張しよう!#1: .Blendファイルを使いこなそう!

どうも、チョコです。

Unityで「これやりたい!」って思ったとき、機能不足でできないこと多いよね。拡張(エディタースクリプト)を書けばいいんだけど、そもそもアセットで使えるデータが限られているからできない。。。なんて思ったことあるかな。

今回はBlenderファイルをUnityで開いて、普通じゃ手に入れられない情報を抽出してみよう!

**この文書を読むにはUnity、C#、Pythonと英語(?)の前提知識が必要です。

Blenderを背景で開く

Blendファイルを読み取るためには、ユーザーが(当然ながら)Blenderを持っていないとできないので、まずBlenderの居場所を確認する。Windowsの場合は、RegistryEditorのSOFTWAREMicrosoftWindowsCurrentVersionUninstallキーにあります。

**注意:RegistryEditorをいじる時に注意してください。変なものいじったりしまうとOSが動かなくなる場合があります。

このキーの中にはすべてインストールされたプログラムが入っているので、Blenderのキーの存在を確認します。

screenshot-246

あった。ではここからBlender.exeの場所を出そう。

<br />
using (RegistryKey key = Registry.LocalMachine.OpenSubKey (registry_key)) {<br />
    foreach (string s in key.GetSubKeyNames()) {<br />
        using (RegistryKey key2 = key.OpenSubKey(s)) {<br />
            if ((string)key2.GetValue(&quot;DisplayName&quot;, &quot;&quot;) == &quot;Blender&quot;)<br />
                location = (string)key2.GetValue(&quot;InstallLocation&quot;, &quot;&quot;) + &quot;Blender.exe&quot;;<br />
         //なんかする<br />
        }<br />
    }<br />
}<br />

**細かい説明は省略させていただきます。(レポートまだ書いてないorz

BlenderでPythonスクリプトを実行

Blenderは、アッドオンやTextEditorでPythonスクリプトを実行し、シーン内のデータを編集したりできます。これを活かしてみよう。具体的には、Pythonを実行し、Unityのアセットフォルダになんか書き込もう。

まず、「System.Diagnostics.ProcessでBlenderを起動し、Pythonを実行して、自動で閉じる」のを背景でやってもらおう。Blender APIに書いてある通り–backgroundコマンドを送ります。
fileはアセットの中の.Blendのパス(例えば、F:/MyProject/Assets/Hoge.blend)。
**以下のコードはエディタースクリプトに入れます。やり方省略

<br />
Process.Start (location, file + &quot; &#8211;background&quot;);<br />

これでBlenderは背景起動された。コマンドみたいなものが起動されますね。

では、Pythonスクリプトを実行しよう。まずはこのスクリプトを実行してみよう。

<br />
Process.Start (location, file + &quot; &#8211;background &#8211;python &quot; + Application.dataPath + &quot;/Editor/hoge.py&quot;);<br />

そして、エディターフォルダに以下のhoge.pyを入れよう。

<br />
import bpy<br />
import sys<br />
class Hoge():<br />
 def execute(self):<br />
   print (&quot;hi&quot;)</p>
<p>if __name__ == &quot;__main__&quot;:<br />
 Hoge().execute()<br />

コマンドにhiが表示されたら勝ち。

次に、pythonスクリプトにパラメータを送ろう。 — のつぎに来るものがコマンドとしてパースされないので、pythonに使えばいいね。例えば、今のアセットフォルダの位置を渡してみよう。

<br />
Process.Start (location, file + &quot; &#8211;background &#8211;python &quot; + Application.dataPath + &quot;/Editor/ExportSS.py&quot; + &quot; &#8212; &quot; + new DirectoryInfo(file).Parent.FullName);<br />

**Python側では、sys.argv[sys.argv.index(“–“) + 1:]でパラメータ行列を取れます。

さて意味のあるものができるようになった。できることはさまざまあるが、例としてシーン内の「メッシュではないオブジェクト」の名前を出力してみよう。自明のコードは省略。

<br />
args = sys.argv[sys.argv.index(&quot;&#8211;&quot;) + 1:] #パラメータを取る<br />
scene = bpy.context.scene<br />
obj = bpy.context.active_object<br />
dir = args[0]<br />
name = args[1]</p>
<p>def execute(self):<br />
    if os.access(self.path, os.W_OK) is False:<br />
        print(&quot;permission denied : &quot; + self.dir)<br />
    return False<br />
    self.path = os.path.join(self.dir, self.name + &quot;.txt&quot;)<br />
    print (&quot;writing to: &quot; + self.path)</p>
<p>    with open(self.path, &quot;wb&quot;) as file:<br />
    for obj in self.scene.objects:<br />
        if obj.type != &#8216;MESH&#8217;:<br />
            self.write(file, obj.name + &quot;rn&quot;)<br />
    sys.exit() #自殺</p>
<p>def write (self, file, _str):<br />
    file.write(_str.encode())<br />

すると、.Blendファイルと同じ名前の.txtファイルができます。

以上、拡張機能でした。なんかやりたいときに使えるとうれしい。
では。

Blender Driverでの補正ShapeKey自動化

やっはろー チョコです。夏はやはりカレーですね。

 

まず、先週にこのモデルを作りました。大好評(?)だったのでこれに沿って記事書きます。

Screenshot (783)

フルモデルはこちら。マスコットは気にしないでください。

では、目蓋のアニメーションを付けましょう。ボーンはめんどくさいのでShapeKeyを使います。

1

おや。うまくいきませんね。そりゃそうだ。目は|ではなくて)ですからね。ShapeKeyはあくまで頂点を直線にしか動かせないから。

じゃああ、頂点を前に伸ばす補正ShapeKeyを付けます。

2

髪は邪魔で消えてもらいました。

きれいになりました。しかし、アニメーションを付けるときにいちいち補正を調整したくないですね。

ここでDriverの出番。Driverというのは

とあるデータ → [おまじない] → アウトプット

のことです。

補正Shapekey(長ぇーな。以下はホシェと呼ぶ)の値に右クリック→Add Driver

そしてGraph Editor タブを開き、F-CurveをDriversに変更します。

Screenshot (785)

NツールバーでDrivers がありますね。ここをいじります。まず、Typeをsum values にし、Propをインプットデータのタイプにする(この場合、BlinkのShapeKeyの値なので、Keyですね)。

ここで、RNAを求められる。何ぞや。インプットデータの値を右クリックし、Copy Data Pathを押すと、RNAが得られますよ。これをCtrl-Vします。

そして、グラフをいじります。「アウトプット」Y=f(「インプット」X)なんですね。簡単ですね(簡単ではなかった)。

 

できました。。。と言いたいところだが、グラフのX軸は整数しか扱えない(ShapeKeyは0から1です)。その間の値がいじれないです。くそです。どうしましょう。

こうなったら、ほかの(0から10か100の)値でBlinkとホシェを操作してしまおう。CustomPropertyのことです。Blenderのオブジェクト設定の一番下で必ずある謎のタブ。ここに一個追加します。

3

↑の操作のやり直しです。書くのがめんどくさいので、分かったと信じましょう。ただ、Custom PropertyのDriverでのPropは、そのPropertyが存在するタブのタイプです。例えば、私はShapeKeyのタブ(Mesh)でやったので、MeshをPropにしました。(アイコンが同じければよい)

完成です。これで1つの値をいじれば、全部やってくれます。わーい。

役に立てるとうれしいです。

ではでは。

 

 

Cel ShadingをBlenderでやってみた

Cellの誤字ではないです。Celです。

にゃは。チョコです。まず成果を見せます。

test3

BlenderはNodeというマテリアル編集できるモードがある。こんな感じです

Screenshot (274)

注: BlenderRender(Internal)です。Cyclesではない。

Cel Shadingはつまり、光の角度がある程度大きければ、ほかの色を使うシェーディング。

数学(コード/ノード)的には lerp(lightTexture, darkTexture, ramp( dot(lightDirection, surfaceNormal) ) )

dotは内積。数学で勉強しましたね。

rampはinputの値に応じてoutputの値をマップするもので、0.3以下で0、以上で1をアウトプットみたいなことをする。

Blenderのlerpはmixで実現でき、lerp(a, b, t)は

return (a*(1-t) + b*t)

の意味を持つ。

Freestyle(アウトライン)も一応使ったが、使わなくてもいい気がする。

終わり。クロースアップを付加します。

Screenshot (266)

ちなみにキャラは蒼かなの明日香です。かわいいから作っちゃった。

では。

Unity Shader と Bitwise(変更)

チョコっす。昨日のBitwiseシェーダーですごーーい間違いをしましたので修正。

あと、普通のシェーダーは主に0か1のAをだすので、それを無視するとよい。

 

変更後のcgincファイル。シェーダー自体は変えなくていい。

Capture

 

(これもcgincのいいところであるが、dllと同じく編集するときシェーダーはいじらなくていい)

 

ではでは

Unity ShaderとBitwise

オブジェクトをレンダ―するとき、一つ主には使わないデータ値、RGB「A」 がある。それを活用したい。

例えば、イメージ効果で、この部分だけをぼかすとかは、その部分のAを0.5にするとか。(前提はシーン内Aを使うシェーダーはない)

しかし、効果が増えると、一つの値は足りない。なんで、floatをbyteとして使おう。

 

例として、0~1のAを4ビットのデータを入れる。

10012は910、上限は15、つまり値を20に割って/かけて、Aにぶち込む。

全部のプロジェクトがつかえるように、cgincludeを使う。

Capture

これを(インストールフォルダー)Unity\Editor\Data\CGIncludesに入れればいい。

*実際に使うときは、#cginclude “UnityBitwise.cginc”をかけば、関数は使える。

使いかたはさまざまが、関数読めば一目瞭然。

 

シェーダーの例

Capture

イメージ効果の例

Capture

 

使えると嬉しい。では。

屈折効果をUnityで! Part2

こんばんは、カイです

 

前の話

Screenshot (970)

プレーヤーの後ろに特に見えますが、水面のものを屈折しまうことがあります。これを解決するため、Maskを作ります。

簡単に言うと、水面と水面でない部分を分けます。

(以下は私のやり方で、すべての状況で応用できると保証しません)

 

まず、fragment シェーダーのアウトプットはfloat4ですが、そのa(アルファー)を変更します。0.5にしました。(特に0.5にこだわりはないが、水以外に存在しないaを付けます)

そして、確認のためカメラにアルファーをrgbaに変換させると、

Screenshot (981)

 

水の部分が一目瞭然です。

 

これをGrabPassの前のPassでやると、GrabTextureのaをチェックすれば、変換されたuvの色のaが0.5であれば、もとの色を使います。

Screenshot (973)

よくなりました。

 

(追加)

水は角度が大きいほど水面が白く見えます。これはfresnel効果です。

clamp(dot (i.normal, i.viewD)*_Thresholdみたいなことをします。簡単ですね。

Screenshot (983)

 

以上でした!ちなみにキャラに歯を作ったら、可愛いと自慢していたのでここに置きます

Screenshot (976)

またのご来店をお待ちしております~!

屈折効果をUnityで! Part1

こんばんは、カイです。初めての投稿です。

 

 

先週京アニのアニメ見て、水の効果に惚れました。

Screenshot (967)

(甘ブリです)

そこで、水の効果を作らないかとED先輩に相談しようとしたら、みんなラッキー☆に夢中していつの間にか合宿終わりましたorz

結局はこのページを参考に作りました。英語なんですが。

>> http://http.developer.nvidia.com/GPUGems2/gpugems2_chapter19.html

 

具体的の流れは以下です

 

1.透過しても透明じゃない?!

オブジェクトを透明にするのはいいが、屈折は得られません。透過した画像(光)を編集する必要があります。なので、

GrabPass という特別なPassを使いました。

Unity Docsで検査すると出てきますが、GrabPass{“GrabTexture”}はGrabTextureに今の画面を保存する。そして、普通のMVPでなく、Screen Spaceでuv検査をし、Tex2D(GrabTexture, i.uv2)をすればいいです。

Screenshot (982)

透明シェーダーと同じですね

 

2.仮屈折

屈折の計算をすると無駄に計算量が増えるので、ごまかせるぐらい近似なものを作ります。

まず、水のテクスチャを用意。

fountain normal

位置での明暗により、GrabTextureのuvをずらせばいいです。

中略

Screenshot (970)

こんな感じになりました。

しかし、水面の上にあるのに、映されるところがあります。解決方法はPart2で!