どうも!2016年になって初のHoudini記事です。
今回はHoudini VFXセミナーでちょっと話したカラーマップから背景を作成する
手法を紹介したいと思います!
最終的にRPGツクールっぽいことができるようになります!
ただ、ちょっと記事が長くなりそうなので、前編後編に分けて紹介しますね。
前編はカラーマップからオブジェクトを色ごとに配置するまで。
後編はその応用編として、自分の周りのプリミティブの色を判断していろいろな処理をします。
■■■■■カラーマップからオブジェクトを色ごとに配置■■■■■
★Step1.画像の色情報をGridに転写させよう!
今回利用するVEX関数はcolormapです。これを使ってノードでいうattribute from mapを
pointでなくprimitiveに対して行います。
(↓attribute from mapはpointに適用されるのでattribute promote(point⇒primitive)しても望ましい結果になりません。)
まずはgridを持ってきます。そしてピクセルの数だけ分割します!!!(力技すぎる!!)
ピクセルの分割についてはres()で取ってくることができます。
ただしres(compositing_node, res_type)の引数はCOPのみのため
res(“$HIP/img/colormapimg1.png”, 1)
のようにファイル名を直に入れてresをとることはできません。
一度COPのfileノードに落とし込んでnullノードから取りましょう。
注意すべきはgridの分割数。
ただres()だけだと微妙にずれてしまいます。それはなぜか、意外と見落としがちなのですが、gridを作ったときRows:10、Columns:10のPrimitive数は100・・・ではなく81です。(+1をする必要がある!)
そこでres()+1の処理を行います。これでピクセル数とgridが一致しました。
res_typeは、D_XRESまたはD_YRESでXは0、Yは1に置き換えられます。
Rowsを res(“../cop2net/OUT”, 1)+1
Columnsを res(“../cop2net/OUT”, 0)+1
Sizeのxを res(“../cop2net/OUT”, 0)*ch(“scale”)
Sizeのyを res(“../cop2net/OUT”, 1)*ch(“scale”)
*gridの面積を1×1にしておくと後でいろいろ融通がきくのですが、ビューポート上の表示が
大きくなりすぎるかもしれないので ch(“scale”) の乗算を付けておきます。
*もしも間違ってデカイ画像を読んでも大丈夫なようにパラメータをExpressionで上限を付けることも可能です。
Expressionはパラメータ上で右クリック⇒Expression⇒Edit Expression かctrl+Eで編集可能になり{}で囲んでreturnで値を返します。以下の例では1000×1000がきても表示しない処理を行っています。
(Expressionは便利なのですが、処理をミスると問答無用で固まったりするので事前保存必須です)
◆Expression
{ if(res("../cop2net/OUT", 1)*res("../cop2net/OUT", 0)<1000000){ return res("../cop2net/OUT", 1)+1; }else{ return 2; } }
*左上を原点{0,0,0}にしたい場合はtransformで、$SIZEX/2 $SIZEY/2 $SIZEZ/2 してください。
★Step2:カラーマップの適用
カラーマップを敷く前にuvを設定します。
uvtextureでuvをpointに適用させ、attribpromoteでuvをpointからprimitiveに移動させます。
そしてwrangle(Primitives)でカラーマップを追加し色情報の分別を行います。
◆wrangle
v@Cd = colormap('op:`opinputpath("../cop2net/OUT",0)`', @uv.x, 1 - @uv.y, "wrap", "clamp");
この読み込んだ画像はCOP上では元ファイルが上書きされるごとに画像が更新されるのですが、
テクスチャ用に読み込んだ画像はHoudiniを立ち上げ直すまでキャッシュされてしまいます!
なんてこった!
ここはHScriptを利用して以下のようにキャッシュをクリアします。
◆HScript
texcache -c
これで、大元の画像をPhotoshopで保存しなおすとHoudiniでもすぐに反映できます。
(画像ではHDAに入れてますが、このコマンドはどこでやってもOKです。)
*colormap()の後ろにある”wrap”はmodeを色々選択することができます。
・repeat or periodic
・clamp or edge or streak
・black or decal or color
など。詳しくはHELPのOptional image filter parametersをご覧下さい。
http://www.sidefx.com/docs/houdini15.0/vex/contexts/shading_contexts#imagefilter
次!色情報を取得します。ここでやりたいのは、黒は削除でドアは赤色で、ということなので
if(v@Cd.r<0.1 && v@Cd.g<0.1 && v@Cd.b<0.1){//black removeprim(geoself(), @primnum, 1); } else if(v@Cd.r>0.8 && v@Cd.g<0.2 && v@Cd.b<0.2){//red }
…しかし、ちょっと待った!これは色情報が手入力ですね。手入力はHoudini主義に反していて美しくありません。後から色を変更する可能性もありますよね。
ということで、prameterに色と敷居値を設定してdistance()を利用して近似色かどうか判断します。
Cdも所詮vector情報なので、その距離さえ図れば色の近いかどうかを判定できるのです。
で、ついでにランダム情報も追加しておきます。
◆wrangle
//////color parameter///////// vector blast_color=chv("blast_color"); vector floor_color=chv("floor_color"); vector door_color=chv("door_color"); vector wall_color=chv("wall_color"); vector veranda_color=chv("veranda_color"); vector window_color=chv("window_color"); //////threshold parameter///////// float blast_threshold=chf("blast_threshold"); float floor_threshold=chf("floor_threshold"); float door_threshold=chf("door_threshold"); float wall_threshold=chf("wall_threshold"); float veranda_threshold=chf("veranda_threshold"); float window_threshold=chf("window_threshold"); //////random parameter///////// int blast_rand=chi("blast_rand"); int floor_rand=chi("floor_rand"); int door_rand=chi("door_rand"); int wall_rand=chi("wall_rand"); int veranda_rand=chi("veranda_rand"); int window_rand=chi("window_rand"); //seed int randomseed=int(rint(random(v@Cd)*1000)+chi("random_seed")); //////default parameter///////// if(distance(v@Cd,blast_color) < blast_threshold){//blast s@prim_name="blast"; i@my_subtype=randomseed%blast_rand; }else if(distance(v@Cd,door_color) < door_threshold){//door s@prim_name="door"; i@my_subtype=randomseed%door_rand; }else if(distance(v@Cd,wall_color) < wall_threshold){//wall s@prim_name="wall"; i@my_subtype=randomseed%wall_rand; }else if(distance(v@Cd,veranda_color) < veranda_threshold){//veranda s@prim_name="veranda"; i@my_subtype=randomseed%veranda_rand; }else if(distance(v@Cd,window_color) < window_threshold){//window s@prim_name="window"; i@my_subtype=randomseed%window_rand; }else if(distance(v@Cd,floor_color) < floor_threshold){//floor s@prim_name="floor"; i@my_subtype=randomseed%floor_rand; }else{ s@prim_name="floor"; i@my_subtype=randomseed%floor_rand; }
なんかfor文でまとめられそうですが・・・。
よし!これでそれぞれのパーツに分離できた!
あとはgroupやforeachなどでそれぞれの色の個所に自分の好きなオブジェクトを配置すればOK!
しかし、それは次回後編のお楽しみ!乞うご期待!