読者です 読者をやめる 読者になる 読者になる

Making Tera

たまに書く不定期ブログ

Unityのテクスチャマッピング

以前、Unityでテクスチャの貼り付けについて聞かれたので簡単な記事にしてみます。
先に書いておきます。分かりにくくてすみません!!


まずテクスチャマッピングについてです。
頂点(面や線)に色をぬる時、テクスチャ画像のどの部分から色を取ったらいいか?という話になります。
これを決めるのがマッピングであり、XY座標(UV座標ともいう)を指定することになります。
実際にシェーダー内では頂点ごとに以下のtex2D関数を呼び出してXY座標から色を取得しています。

tex2D(texture, xy)
texture: 色を取得したいテクスチャを選択します
xy:ここで指定したX座標とY座標にある色を取り出します

【まずは標準的なUVマッピング!】

俗にいうUVマッピングとは上記のxyにUV座標を渡す方法です。
UV座標とはデザイナーが頂点ごとに座標を設定するもので、大抵のモデルデータには付属しています。魚の開きみたいなあれです。
UVマッピングはモデルの大きさによってテクスチャも拡大されます。

【モデルのサイズに関わらずテクスチャを表示したい!】

モデルサイズに依存したくない場合はtex2D関数のxyの場所にワールド座標を渡します。*1
ワールド座標の取得方法はUnityのシェーダー機能を利用しているかどうかで変わってきます。

サーフェイスシェーダーの場合

  • worldPosを使って取得できます。
  • 例:IN.worldPos.x

頂点/フラグメントシェーダーの場合

  • 頂点にワールドマトリックスを適用することで取得できます。
  • 例:mul(_Object2World, IN.vertex)

ワールドマトリックスのような行列はあらかじめ用意されておりシェーダー内から参照できるようです。*2

_Object2Worldモデル行列
UNITY_MATRIX_MVPモデルビュー行列×射影行列 (world*view*projection)
UNITY_MATRIX_MV モデルビュー行列
UNITY_MATRIX_Vビュー行列
UNITY_MATRIX_Pプロジェクション行列
UNITY_MATRIX_VPビュー行列×射影行列
_World2Objectモデル行列の逆行列

【UIのようにテクスチャを画面に連動させたい!】

スクリーン座標にテクスチャを固定したい場合は少し複雑です。

結果を先に書くと頂点シェーダーから
ComputeScreenPos(mul(UNITY_MATRIX_MVP, v.vertex))
の値をピクセルシェーダー(フラグメントシェーダー)に渡します。
渡されたxとyをwで割った値をテクスチャ座標として使います。

除算の理由はの描画に関する行列の知識が無いと少し混乱するかもしれません。
ComputeScreenPos関数を検索すると「ウィンドウ座標を求める関数」と書かれていることが多かったのですが
実際には座標の範囲を[-w、w]から[0、w]に変換しているだけの関数となります。
画面上の座標を求めているのはmul(UNITY_MATRIX_MVP, v.vertex)の部分です。
wで割るのは通常はGPUが行っている処理を手動で行っていることになります。*3


他にもいろいろなマッピングがありますが、基本的な方法は上記の三種類だと思います。
参考に慣れば幸いであります!

*1:XYZ(float3)をどうやってfloat2にするかでマッピングの方法が変化します。

*2:DirectXで言うところのワールドマトリックスはUnityではモデル行列と呼ぶようです。

*3:GPUの透視変換はX[-w~w]Y[-w~w]Z[0~far]をwで除算しX[-1~1]Y[-1~1]Z[0~1]に変換します。

壊れた地蔵モデリング

瘴気漂うマップのモデルの依頼がありましたのでメイキングをまとめてみました。
色んな風に壊れたお地蔵さんが4つ!各々が△200ポリということでディテールには限界が見えます。

暗い場所に置くらしいのでディフューズマップを無くしてノーマルマップのみで細部を表現することで描写コストを下げる作戦に。
もちろん4つのテクスチャは一つのテクスチャ、マテリアルにしておきます。
では早速スタート!

お地蔵さんのような彫刻系?はスカルプトで作成したほうが早いので3Dcoatで作成。
(一時期ZBrushも試したけどカメラをはじめ、あまりに独特の操作が多くて断念)

地蔵壊す前

原型を壊す!ここが一番楽しいけどあっという間!

地蔵ベイク前

作成したハイポリをリトポ。これが一番辛い。ただただ辛い。
詳細に作成したモデルのディティールをポリ数制限によって崩していくのが辛い。
(今回は表示される大きさもあってハイポリが適当だからいいけどっ)
f:id:makingT:20170301013049j:plain

ハイポリからローポリにベイクすると差分が法線マップとして作成される。
このとき表面の材質などはあとから合成するのでモデルの差だけを焼き込む!
f:id:makingT:20170301013604j:plain

SubstanceDesignerを使って材質の法線画像を合成する。
高ポリに材質を彫り込んじゃうと、大抵あとから「材質が綺麗に出てないな~」ってなります。
なぜか本番環境でだけ綺麗にでないっす。泣きます。
ってことでトライアンドエラーが気楽にできる方法を選択しておくのがお勧めっす。
f:id:makingT:20170301013726j:plain

あとはUnity上でどう表示されるか確認しながら微調整!

黄泉 瘴気エリア地蔵

枝垂桜モデリング

ある日、サークルの方から「枝垂れ桜」のモデルが欲しいと言われまして、分かってはいたのですがポリ数との戦いでした。
Unity用のモデルをModoで作成しております、誰かの役にたてば…とせっかくなので記事にしました。

まず最初に、普通に綺麗に見えるモデルを作成したのですが、四角ポリで7万ポリ!植物特有のやばい予感。
これをリトポ→ベイクしようと思ったはいいものの案の定ビジョンが見えない!!
さっくりモデルを捨てて作戦を立て直しました。


まずはバランスを見ながら幹をローポリで作成
f:id:makingT:20170226003903j:plain

細かい枝はすぐに頂点数が増えるので板ポリで作成
f:id:makingT:20170226004119j:plain

拡大すると分かりますが板ポリを「Ctrl+C → Ctrl+V → F(反転)→ 移動」で裏側にも同様の板ポリが配置されています。
シェーダーで両面描写してもよさそうですが、マテリアル分離などを考えるとこちらのほうがコストが低いと思われます。
f:id:makingT:20170226004441j:plain


物理演算で枝を垂らすことにしました。
まずはサーフェイスジェネレータでポイントを作成
次にリプリケータでカーブを配置
f:id:makingT:20170226005139j:plain

カーブを一つのメッシュにまとめたらダイナミックカーブを適用
プロパティウィンドウのダイナミクスの中にあるカーブ項目でカーブ始点をピン留めしてジョイント角度やピンの角度を調整
カーブパーティクルジェネレータで枝のメッシュを配置してから物理演算を行う!

物理演算


これである程度、完成が見えたと思ったのですが実際にゲーム内に置いてみると「見下ろし視点」の影響でシルエットが思ったように定まりません。
結局すべて手動で配置しなおすことにしました。
カーブにメッシュを沿わせるあたりは一緒ですが、カーブに対してペイントタブにある「ヘアツール」を多用します。
今回のような場合は大きいブラシで「分離」が使いやすいかも
f:id:makingT:20170226193131j:plain

ローポリのモデルが完成したらテクスチャの作成に移ります。
今回、「桜のモデルは暗いマップでライトアップしたい」とのことで通常のワークフローとは異なります。

まずは少ないポリ数でも綺麗に見えるようにノーマルマップを高ポリからベイクして作成。
エミッション用テクスチャも欲しくなるのでAO画像を代用
f:id:makingT:20170226012907j:plain

幹はライトのせいで色が飛ぶと思われるので暗いベース色+法線による表現で。
植物の高ポリモデルはスカルプトで作成するのが楽で早いです。
今回はModoではなくCoatを利用。
気合いを入れてもローポリによってはベイクに限界があるのでここは元モデルにさっと肉付けして終わり。
f:id:makingT:20170226013708j:plain

ここまで来たらゲーム内に持って行って画像を見ながら調整します。
Modoのゲームツールタブを利用するとワンクリックでUnity内で描画の様子を確認できるので捗ります!
(「表示の切替→選択したものだけ書き出し」の部分をマクロ化してショートカットに割り当てておくと便利です)

桜テスト

Modoで自動マップ生成機能を作成しようと格闘中

最近、時間があったのでマップ自動作成機能を作ろうと格闘しておりました。

せっかくModoもバージョンアップしたばかりなので手を付けていなかったスケマティックまわりにようやく触れました!
ノードはやはり強力ですね。

完成したららせつのMAP作成に使えるかなぁ・・・。
Unityに持っていくことも考えないとですね。

とりあえず現状は以下のような感じになってます。

分割数、凹ませ具合、地形の形などはすべてあとから変更できる仕組みです。


AutoGround

次は境界にアイテムを自動で置いたり、テクスチャあたりに着手予定!

今年は色々やれそうです!

去年は引っ越しなどで色々と忙しかったのですが、
今年は時間が取れそうなので3Dやゲーム制作に力を入れていきたいと思っています。

早速、ずっとやっていなかったModo10のアップデートを行いました!
f:id:makingT:20170107001819j:plain
酉年ということで・・・。

とりあえずプロシージャナルモデリングが気になります。
Mapの自動生成なんかに使えないかなぁ~と。

C#(WPF)とDLLでシステムコマンドをグローバルフックする

先日、BUFFALO製のマウスやキーボードを他の機器にBlueToothを飛ばせる製品を購入しました

BlueTooth製品の入力を別のBlueToothとして飛ばしたりできて非常に面白いし使いやすい商品!

 

・・・・だった・・のですが!

飛ばす元でAltキーを単発で押すとメニューにフォーカスが移ってしまい、

気付かないうちに設定を変更してしまうという問題に直面しました

 

「その動きだけ制約加えるソフト作成してみよっかな」と思い立って作り始めたのですが

・どうもグローバルフックが必要 しかもDLL化しないとダメ。言語はもう忘れ気味のC++

・資料が古いものばかり DEFファイルなんてほとんど作ったことないよ・・・

・APP側がC#で作成されているサンプルが少ない

・フック横取りして無効化しているのはキー入力ばかりでシステム系のものが見当たらない

 

ということでブログに書くことにしました!

製作環境はVS2015の無料のやつです

 

まずはDLLから始めます

 

新規作成 > C++Win32プロジェクト > 名前はHook > OK > 次へ >DLLにチェック > 完了

 

dllmain.cppを以下に書き換える(ヘッダー追加するまでエラーでてるけど気にしない)

 

次にソリューションのヘッダーファイルを右くり > 追加 > 新しい項目 > Hook.h を作成

中身は以下

 

ビルドしたらDLL完成

次にC#側でAPPを作成開始!

 

新規作成 > WPFアプリケーション > LockAltMenuという名前で作成

 

常駐ソフトにするので、まずはソリューションにあるMainWindowsを削除

App.xaml内 の StartupUri="MainWindow.xaml" という部分も削除

App.xaml.csを以下に書き換える

参照にSystem.Windows.FormsとSystem.Drawingを追加

プロジェクト右クリック > プロパティ > リソース > icon.ico という適当な画像をドラッグしてアイコンリソースを作成

最後に先ほど作ったDLLを実行ファイルと同じ場所に移動※!これで完成!!

 

※ 同じ断層に作成してある場合はプロジェクトプロパティのビルド前イベントに

Copy "../../../../Hook\Debug\Hook.dll" $(TargetDir)Hook.dll と追加しておくと便利

 

 

 

【解説らしきもの】

ソースがすべてですが、注意点だけ抜き出しておきます

 

・フック内容を書き換えたい場合はSetWindowsHookExの第一引数に気をつけろ!

・グローバルフックDLLをC#で扱う場合、DllImportはエントリポイントまで記入しないと動作しない

・似たような方法でDLLインジェクション+サブクラス化を検討している場合は、SetWindowLongPtr(GWL_WNDPROC指定)で拾えるシステムコマンドの種類は少ないので実装前に確認したほうが無駄な時間を食わずに済むよ!

・操作したいターゲットが決まっている場合はSetWindowsHookExの第3,4引数を変えてローカルフックにする(コメント参照)

・実験に失敗したらOS再起動しないと治らなくなるので注意されたし!

 

技術が古いためか動作しないサンプルもチラホラあり、簡単にできると思ったのに意外に大変だった orz

誰かのお役に立てば幸いです

SmartMaterialについて

SmartMaterialの機能を知ってかなり感動したんですが、日本語の記事がほとんどヒットしないという悲しさ。

SPの基本的な考え方は

素材を割り当て→マスクして隠す

です

マスクの部分にはペイントだけではなくジェネレータを利用できます。

ジェネレーターは非常に強力なのですが、PositionMapやAOMap、ThicknessMap等、モデルから抽出した固有の情報が必要になります。(ジェネレーターによって種類が異なります)

SPはこの情報をモデルごと(正確にはTextureSetごと)に記憶することしました。

(どの情報も好きなタイミングでMeshからベイクできます。)

これにより「ジェネレータと必要情報の自動紐づけ」が可能となり、

モデルにより異なる情報は無視して、ジェネレータ(エフェクト)を含む素材をテンプレートとして保存できる仕組みが完成しました。

これが「SmartMaterial」です。

PositionMap等が必要な複雑な素材であってもテンプレートとして保存できるのは非常に強力で、時間短縮に繋がります。

現時点ではSmartMaterialを読み込んだ時に必要なマップがベイクされていない状態でもそのまま読み込めます。

警告のようなものが出るか、読み込み時に必要マップが確認できる仕組みがあってもいい気がします。