2016年05月

2016年05月31日

modo10の新機能を調べてみた その4

10にはテクスチャベイク作業をまとめて設定して一括して行うための「ベイクアイテム」が追加された。

fig01

ベイクアイテムにはテクスチャへベイクするタイプ(他のオブジェクトから法線マップを作ったり、テクスチャレイヤーをまとめて1つにしたりするのに使う)とレンダー出力をベイクするタイプ(アンビエントオクルージョンマップなどレンダー出力からマップを作ったりするのに使う)がある。どちらも「ゲームツール」レイアウトの「ベイク」タブにあるボタンから追加できる。

fig02

例えばマルチレゾリーシュンスカルプティングで作ってフリーズしたメッシュ(High_Mesh)からローレゾのメッシュ(Low_Mesh)に法線マップを取得する場合、

fig03

fig04

ローレゾメッシュ側のマテリアルに新規の法線画像マップ(Sphere_Normal)をUVマップで貼っておき、

fig05

「新規テクスチャベイクアイテム」ボタンを押して「テクスチャベイクアイテム」を作って下のように設定する。

fig06

高解像度のメッシュをソースに、低解像度のメッシュをターゲットにして法線マップを作成する事で形状データの量を減らしながら高いディテイルを持ったモデルが作成出来る。マップを写し取る場合は2つのメッシュがなくべく重なり合うように配置して、上の画像のように「ソースからベイク」をONにする。これがOFFの時はテクスチャ出力先の画像マップより下にあるマテリアルを合成したものをマップにベイクするモードになる。

テクスチャの出力先が法線画像マップ1つなのでセットする時はプルダウンメニューから選択出来る。

fig08

出力先が複数ある場合は出力したい画像マップをすべて選んでから「選択を追加」ボタンを押して追加する事が出来る。

fig09

あとは「選択をベイク」ボタンを押せば、出力先に設定された画像マップごとにレンダリングが行われて画像が置き換わる。

fig07

下のGIFアニメはハイレゾメッシュとそれをノーマルマップでベイクしたローレゾメッシュだ。凹凸が法線として写し取られているのがわかる。

fig10

複数の同じエフェクトのテクスチャをまとめるのも同じ方法で出来る。例えば下の画像は「Wood」に「Cruddy」を乗算するようにしたプロシージャルテクスチャをディフューズカラーとして使っている。これはプロシージャルテクスチャなので「RayGL」をONにした状態じゃないと表示出来ない。

fig12

これら2つのテクスチャを1つの画像マップにまとめるには、2つのテクスチャのすぐ上に新規画像マップの「Sphere_Diffuse」を挿入して、

fig11

「新規テクスチャベイクアイテム」ボタンを押して「テクスチャベイクアイテム」を作って下のように設定する。今度は「ソースメッシュ」は必要ないし、「ソースからベイク」はOFFだ。

fig13

これで「選択をベイク」ボタンを押せば2つのテクスチャを合成した画像がレンダリングされて置き換えられる。もし「全てをベイク」のボタンを押せば前に作ったもう一つの「テクスチャベイクアイテム」の方も一緒に処理されて法線マップもレンダリングされる。

fig14

ここでベイク元になった2つのシェーダーをOFFにすると、

fig15

このようにベイクされた画像で置き換わっているのが確認出来る。

fig16

画像マップになったので「RayGL」をOFFにしても表示される。

続きはまた次回。

modo10ブログ目次



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)modo | CG

2016年05月30日

3ds Max 2016の新機能を調べてみた その95 3dsmax 2016

引き続き「Maxクリエーショングラフ」の「MCG_lookAt」コントローラのパラメータロールアウトについて調べてみたい。「mcgOps」の中身を調べる事が出来るようになったので、今回はそこからグラフにどう値が渡されていくのかを調べてみたい。これがわからないとUIをどう作ったらいいかわからないからね。で、核となるのが「GetValueFunction」だ。このコードはMCGが自動的に生成するもので、今までの調査からこのファンクションがコントロールから値を集めてグラフを実行するものだと言う事はわかっている。

fn GetValueFunction = (
 --evaluate the graph
 local _res = Quat 0 0 0 0

 mcgOps.INodeA_PreInvoke params.Targets_UI Targets_List Targets_Tab paramsOpen

 mcgOps.FloatA_ParamPreInvoke params.Weights_UI Weights_List Weights_Tab paramsOpen

 upnodeWrapper_SetValue upnode
 parentTransformWrapper_SetValue parentTransform

 if (PreInvokeMethod != undefined ) then PreInvokeMethod()
 local args = dotnet_ValueToDotNetObject #(billboard, targetAxisFlip, Targets_List, Weights_List, parentTransformWrapper, targetAxis, upnodeAxis, srcUpnodeAxisFlip, upnodeControl, upnodeAlignAxis, upnodeWorld, upnodeWrapper, rotYOffset, rotXOffset, rotZOffset) argsType
 local v = pluginInstance_GetValue (currentTime as integer) args
 _res = Quat v.x v.y v.z v.w

 if (PostInvokeMethod != undefined ) do _res = (PostInvokeMethod _res)
  _res
)

前回の調査でわからなかった「INodeA_PreInvoke」は「MCG_function.ms」の中で以下のように定義されている。

fn INodeA_PreInvoke ui list tab paramsOpen =
(
 --update UI
 OneColArrayParamPreInvoke ui tab paramsOpen INodeToStringFunc
 --Update List
 if list.list.count == 0 then
 (
  for ele in tab do
  (
   list.AddElement (MakeNodeWrapper ele)
  )
 )
),

「GetValueFunction」のコードでこのメソッドに渡される引数は

ui:Targets_UI、list:Targets_List、tab:Targets_Tab、paramsOpen:paramsOpen

「Target_UI」コントロールはロールアウトでは非表示になってるけどグラフでは「Targets:Parameter:IArray<INode>」として値を受け取る窓口になっているので、MCGで自動生成されるコードではこのコントロールから値を受け取るコードが生成されるようだ。「Weights:Paramter:IArray<Single>」も同様だ。

fig04

「INodeA_PreInvoke」ではまず「OneColArrayParamPreInvoke」が呼び出されている。このコードは以下の通りで、

fn OneColArrayParamPreInvoke ui tab paramsOpen toStringMethod =
(
 if paramsOpen do
 (
  for n =1 to (tab.count) do
  (
   local val = lvops.GetLvItemName ui (n-1) 1
   local tabVal = toStringMethod(tab[n])
   if(val != tabVal) do
   (
    lvops.SetLvItemName ui (n-1) 1 tabVal
   )
  )
 )
),

「paramsOpen」がtureでパラメータロールアウトが表示されている時に実行されて、「Targets_Tab」が引数「tab」に渡されていて、「Targets_Tab」内の要素数を「count」で調べて1〜要素数まで変数nを増加させながらループさせる。そのループの中ではまず「lvops.GetLvItemName」が実行される。これがそのコードで、「NET_ListViewWrapper.ms」に定義されている。

function GetLvItemName lv nRow nColumn =
(
 local result = ""
 if nRow >= 0 and \
  nRow < lv.Items.count and \
  nColumn >= 0 and \
  nColumn < (lv.columns.count) then
 (
  local li = lv.Items.item[ nRow ]
  local si = li.subItems.item[ncolumn]
  result = si.text
 )
 else
 (
  result = ""
 )
 
 result
),

これは「ListView」の[nRow,ncolumn]のセルに格納されているオブジェクトを取り出して「text」メソッドで文字列化して返すファンクションのようだ。よって

local val = lvops.GetLvItemName ui (n-1) 1

は、「Targets_UI」の[n-1,1]のセルに入っているアイテム名を変数「val」に取り出す。

次に「toStringMethod(tab[n])」は「toStringMethod」が「OneColArrayParamPreInvoke」の引数で与えられていて、呼び出し側を見ると「INodeToStringFunc」が渡されている。これは以下のコードになっていて、

fn INodeToStringFunc n =
(
 if(n == undefined) then
 (
  return "undefined"
 )
 else
 (
  return n.name
 )
),

「INode」の名前が得られるから、

local tabVal = toStringMethod(tab[n])

は、「Targets_Tab」のn番目の要素の「INode」の名前が変数「tabVal」に代入される。

これら2つの名前が一致しない場合は

lvops.SetLvItemName ui (n-1) 1 tabVal

が実行される。これのコードは以下の通りで、

function SetLvItemName lv nRow nColumn newName =
(
 if nRow >= 0 and \
  nRow < lv.Items.count and \
  nColumn >= 0 and \
  nColumn < lv.columns.count then
 (
  local li = lv.Items.item[ nRow ]
  local si = li.subItems.item[ncolumn]
  si.text = newName as string
 )
),

「Targets_UI」の[n-1,1]のセルに「Targets_Tab」から取得してきたアイテム名をセットするようになっている。

以上から「INodeA_PreInvoke」の

 OneColArrayParamPreInvoke ui tab paramsOpen INodeToStringFunc

は、「Targets_UI」の「ListView」を「Targets_Tab」で更新するわけだ。結局のところこの「Targets_UI」は勝手に生成されちゃってるから放置してるだけで特に必要無いね。

次に「Targets_List」の要素数が0の時は「Targets_Tab」の要素を「MakeNodeWrapper」でとあるクラスにラップして「Targets_List」に追加して「Targets_List」を「Targets_Tab」で更新するようになっている。

if list.list.count == 0 then
(
 for ele in tab do
 (
  list.AddElement (MakeNodeWrapper ele)
 )
)

このラッパークラスは「MakeNodeWrapper」で「Autodesk.Max.MaxPlus.INode」になっているのがわかる。

fn MakeNodeWrapper obj =
(
 if(NodeWrapperClass == undefined) do
 (
  NodeWrapperClass = dotNetClass "Autodesk.Max.MaxPlus.INode"
 )
 return (NodeWrapperClass._CreateWrapper obj)
),

つまりMCGで作ったプラグインにINodeを渡すにはこのラッパークラスのオブジェクトで渡す必要があるみたいだね。

「Targets_List」については「on Targets_Tab tabChanged」ハンドラなどの冒頭で必ずクリアするコードが入ってたから「Targets_Tab」の値が更新されたら必ず「GetValueFunction」の中でも更新されるって事だね。

on Targets_Tab tabChanged action index count do
(
 Targets_List.clear()
 if (paramsOpen) do (
       :

以上の事から「GetValueFunction」冒頭の、

mcgOps.INodeA_PreInvoke params.Targets_UI Targets_List Targets_Tab paramsOpen

の部分はパラメータロールアウトが表示されている時に「Targets_Tab」の値で「Targets_UI」と「Targets_List」を更新するものだとわかった。

続きはまた次回。

maxまとめページ



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)3ds Max | CG

2016年05月27日

modo10の新機能を調べてみた その3

さて、前回Unityにモデルを出力しようとしたら警告が出てうまく出力できなかったってところまでやった。これについてインポータースクリプト添付のマニュアルを読むと以下の記述が見つかった。

・Detail UV - Modo assumes that all of your main textures are using the first set of UVs on your mesh. This works similarly in Texture Wrap values. If the UV map of your Albedo texture and Detail Albedo texture differ, Modo assumes that your detail map uses a second UV set. The material importer script then sets the detail maps to use the second UV set.

つまりインポーターが生成するシェーダーは1つのメッシュに「main」と「second」の2つのUVセットが使える仕様にはなってるけど「second」でマッピング出来るのは「Detail」マップだけのようで、同じエフェクトで異なるUVマップという割り当ては出来ないようだ。

そこで詳細な表現が必要な「Head」側のマップのエフェクトを以下のように変更した。そしてイベントログに出てきた忠告通りUVマップの順番が明確になるように名前をちょっと書き換えた。

fig20

これで改めて「出力」ボタンを押すと、今度はちゃんと出力された。

Unity側で確認すると「Project」パネルは下のようになって、マテリアルやテクスチャなどが読み込まれている。

fig21

ここで読み込まれたモデルをシーンにドロップしてみた。

fig22

するとこのように頭部に画像がマッピングされていない・・・。

fig23

「Project」パネルの「Materials」をあけると「BMan0015-Head」が見つかるのでこれを選択すると、

fig24

「Inspector」パネルに頭の方のマテリアルの設定が表示される。これを見ると2枚の画像が「Secondary Maps」として読み込まれているのが確認できる。で、よく見ると「UV Set」が「UV0」になっていて、2枚目のUVマップが割り当てられていない事がわかった。

fig25

そこでこれを「UV1」に変更すると

fig26

このようにやっとちゃんとマッピングされた。

fig27

それではまた来週。

modo10ブログ目次



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)modo | CG

2016年05月26日

3ds Max 2016の新機能を調べてみた その94 3dsmax 2016

引き続き「Maxクリエーショングラフ」の「MCG_lookAt」コントローラのパラメータロールアウトについて調べてみたい。

今回は「Weights」の「Set」ボタン。

fig03

このボタンの定義を見ると名前が「updateSelected_Weights_UI」になっているので、

fig01

このボタンが押された時のハンドラは「on updateSelected_Weights_UI pressed」になる。

fig02

ここではまず「mcgAPOps.GetSelectionIndices Combined_UI」で「ListView」で選択されている項目の番号リストを「indicies」に取り込む。そしてこの番号に対応する「Weights_Tab」の要素の値をスピナーの値で置き換える。

終わったら「FillTargetsListView()」で「Combined_UI」の「ListView」を更新する。

「FillTargetsListView()」が実行されると選択状態が解除されるので、最後に「SelectListviewTargets indicies」で「indicies」に記録されている番号のリストアイテムを再び選択状態に戻す。

これで「ListView」コントロールに表示されているアイテムで選択さrているもののウェイト値がスピナーの値で置き換えられて、対応する「Weights_Tab」の値も修正される事になる。

ところで「Weights_Tab」が修正されると「on Weights_Tab set」ハンドラが呼び出される。

fig03

このハンドラの中でも「FillTargetsListView()」が呼び出されて「ListView」が更新される事になる。これはなんか無用なような・・・。

以上で「ListView」のUI関係はだいたい把握出来たかな。

それではまた次回。

maxまとめページ



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)3ds Max | CG

2016年05月25日

modo10の新機能を調べてみた その2

前回は「Unityマテリアル」のパラメータについて調べてみた。今回はゲームレイアウトでモデルをUnityに出力してみたい。

まずUnity側で新しいプロジェクトを作って、そこにmodoマテリアルのインポートスクリプトを読み込む。そのためにまずスクリプトをダウンロードする。Unityの「Window」メニューから「Asset Store」を選んでアセットストアに接続する。

fig01

次に検索ワード「modo」でストアを検索する。

fig02

「MODO Material Importer」が見つかったらこれをクリックして開くと、

fig03

このような画面になるので「ダウンロード」ボタンを押してダウンロードする。

fig04

そして「インポート」ボタンを押せば、

fig05

インポートダイアログが出るので「Import」ボタンを押す。

fig06

これで「Project」パネルの「Assets」フォルダに下のようにフォルダーが出来てスクリプトがインポートされる。

fig07

他のプロジェクトでこのスクリプトを使う時は同様のフォルダを「Assets」フォルダにコピーすればいい。

modo10で「レイアウト」レイアウトに切り替えて「メッシュ」タブから「Man aXYZ design01.lxl」をダブルクリックでシーンに読み込んだ。これをUnityに出力してみたい。

fig08

まずマテリアルを修正する。このモデルはイメージマップとして「BMan0015-Body-D」、「BMan0015-Head-D」が「法線」「ディフューズの色」としてメッシュアイテム「Man aXYZ design 01.lxl」に割り当てられている。

fig09

UVマップは1つのメッシュレイヤに

「BMan0015-Body」

fig12

「BMan0015-Head」

fig13

の2つが割り当てられている。

そして画像の方はディフューズカラー用の「−D」バージョンと法線マップ用の「−N」バーションが読み込まれる。せっかくあるんだからこっちを法線マップ用に使うことにする。

fig11

そしてシェーダーツリーをとりあえず修正したのが以下だ(「とりあえず」と書いたのは実はこれだとエラーが出るからなんだけどそれはまた後で)。「BMan0015-Body-N」と「BMan0015-Head-N」を読み込んでエフェクトを「Unity Normal」に、「ディフューズの色」を「Unity Albedo」に、「material」を「Unity Material」にした。

fig14

また、「BMan0015-Body-N」のプロジェクションタイプを「UVマップ」に、UVマップを「BMan0015-Body」に、「BMan0015-Head-N」も同様にUVマップを「BMan0015-Head」にした。

これで「ゲームツール」レイアウトでこのように表示されて効果が確認出来る。

fig15

「ゲームツール」レイアウトで「ゲームプリセット」として「Unity」を指定して、「出力ディレクトリ」としてUnityのプロジェクトの「Assets」フォルダを設定する。

fig16

さらに「テクスチャをコピー」をONにする。Unityを起動してモデルを渡したいプロジェクトを開いておいて「出力」ボタンを押すと、

fig17

これでUnityにモデルが渡されたら良かったんだけど下のように警告ダイアログが出る。とりあえず「いいえ」を押して出力は中止した。

fig18

イベントログを表示してみると以下のようになっている。

fig19

つまり「BMan0015-Head-〜」のUVマップのインデックスが1より大きくなっちゃったのが原因らしい。modoのビューポートでは問題なく表示出来てるのにね。

このように1つのメッシュに対して単純に2つのUVマップを設定して画像マップを貼り付けるのはこの方法じゃダメなようだ。

続きはまた次回。

modo10ブログ目次



take_z_ultima at 11:30|この記事のURLComments(0)TrackBack(0)modo | CG
Archives