2010年06月

2010年06月30日

3ds Max 2011がやって来た その12 3dsmax2011

代表お疲れさまでした。

観てるだけで汗だくになって夜中にシャツを着替えたわ。う〜脱力感・・・。

さて、前回mentalmillのシェーダーノードをマテリアル/マップブラウザに追加できるって事を書いたけど、どうも実装がちゃんとしていない部分があるようで、リリースノートにはIlluminationPhongノードがmental rayでレンダリングする時にNormals Make Normalでノーマルマップを補わないとうまくレンダリング出来ない不具合があるという事が書いてある。

さらにいろいろとマップブラウザに追加して試してみたら、mental millでは接続できるノードが接続できなかったりする事も出てきた。どうやらまだこれらは発展途上みたいだな。

例えばTexture Coordinate 2d Offsetはテクスチャ座標をU、V座標方向にオフセットしてずらすシェーダーだけど、MaxMetaSLNodeTexmap.tbxに

 <palette_item type="node_class" node_class="Texture_coordinate_2d_offset"              image="Texture_coordinate_2d_offset.bmp"/>

の行を追加してマップブラウザに追加して、ストレートマテリアルエディタに出しても、resultはどこにも繋がらない。下の画像はTexture Lookup 2dのCustom UV Inputに繋いでIllumination PhongのDiffuse Colorに割り当てたテクスチャマップをずらしてみようとしたところだ。

fig01

同様の事をmentalmillでやってみるとちゃんと繋がってTexture Coordinate 2d offsetのoffset uやoffset vの値を変化させるとPhongのテクスチャが動く。

fig03

ちなみにmental millではこうやって作ったシェーダーツリーをPhenomenonという箱に入れてまとめる事が出来る。やり方は、まとめたいシェーダーツリーを全て選択し、何も無いところで右クリックをし、「create new Phenomenon from selection」を選んで、新しいPhenomenonの名前を入力するだけだ。

fig04

これで選択したツリーがあたかも1つのシェーダーのようにまとまったものになる。中身を編集したい時は右上のボタンをクリックして展開すればいい。

fig05

これが展開したところ。このPhenominonには外部と接続する部分が設置できて、デフォルト状態で右上にresultが存在している。上の展開前のPhenominonの画像にもresultが出ているのがわかる。出力を増やしたい場合は出力パラメータの上で右クリックをして「Add〜to〜」というメニューを選べばどんどん追加できる。

fig06


同様に入力側もPhenominonの外に出せて、パラメータの部分を右クリックして「Add 〜 to 〜」を選択すれば、

fig07

左上に入力の項目が追加されていく。

fig08

Phenominonを閉じるとこのように入力パラメータも外に出てくる。

fig09

こうすることでいじられたくないパラメータを隠蔽したり出来る。これを保存で書き出してMAXのDirectXシェーダーで読み込ませると、このように入力パラメータを絞った形のノードに出来る。

fig10

ちなみに同じ構成のシェーダーツリーをPhenominonを使わないで出力するとDirectXシェーダーでのパラメータ構成はこのようになる。要するに全部出ちゃうんだね。ちなみに出力の方はDirectXシェーダーのものなので1つだけだ。

fig11

こうやって作ったシェーダーはOffsetUとOffsetVのパラメータがちゃんと働いて、2つのパラメータにベジェ実数を繋いでアニメーションさせると、貼ったテクスチャがこのようにアニメーションする。ちなみにこうやって読み込んだIllumination PhongはnormalパラメータにNormals Make Normalを割り当てなくてもmentalrayで普通にレンダリングできる。

fig12

このくらいはストレートマテリアルエディタの方で組めるといいんだけどね。それとXMSLファイルで定義されたシェーダーノードをそのままストレートマテリアルエディタに取り込むノードも欲しいよね。

それではまた次回。

maxまとめページ 



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

2010年06月29日

modoからFLASHへ書き出してみた その7 modo 401 SP4 ActionScript 3.0

前回はポリゴンの向きによって処理が必要ないデータを切り捨てて処理速度を稼ぐことをやってみた。それでも元の処理ルーチンに比べるとかなり重たいので、もう少し最適化を進めておきたい。

そこでどこを効率化させるのが一番効率的なのかを調べるためにModelDataクラスのdrawメソッドの中に時間計測の仕組みを挿入してみた。

それはflash.utilsパッケージのgetTimer()メソッドだ。このメソッドはFlashランタイム仮想マシンが起動してから経過したミリ秒数を返すので、コードの中に挿入してその行を通過したミリ秒数を変数に記録しておけば、その差から処理時間が計測できる。これを使うためにimport文を1つ挿入して、

import flash.utils.getTimer;

drawメソッドには以下の赤い文字の部分を挿入した。

  public function draw(s:Sprite,m:Matrix3D,projection:Matrix3D):void {
   var zdist:Array=new Array();
   var cullcon:Vector.<int>=new Vector.<int>();
   var wcon:Vector.<int>=new Vector.<int>();
   var i:int;
   var avz:Number;
   var z1:Number;
   var z2:Number;
   var z3:Number;
   var xmin:Number;
   var ymin:Number;
   var xmax:Number;
   var ymax:Number;
   var v1x:Number;
   var v2x:Number;
   var v1y:Number;
   var v2y:Number;
   var ptr1:int;
   var ptr2:int;
   var ptr3:int;
   var t1:uint;
   var t2:uint;
   var t3:uint;
   var t4:uint;
   var t5:uint;
   var t6:uint;   
   var t7:uint;

   t1 = getTimer();
   s.graphics.beginBitmapFill(_image);
   m.transformVectors(_vertices3D2,vert3D);
   Utils3D.projectVectors(projection,vert3D,vert2D,_uvtData);
   t2 = getTimer();
   for ( i=0;i<_conData.length/3;i+=1){
    ptr1=_conData[i*3]*3;
    ptr2=_conData[i*3+1]*3;
    ptr3=_conData[i*3+2]*3;
    v1x=vert3D[ptr2]-vert3D[ptr1];
    v2x=vert3D[ptr3]-vert3D[ptr1];
    v1y=vert3D[ptr2+1]-vert3D[ptr1+1];
    v2y=vert3D[ptr3+1]-vert3D[ptr1+1];
    if(v1x*v2y-v1y*v2x<0){
     cullcon.push(_conData[i*3],_conData[i*3+1],_conData[i*3+2]);
    }
   }
   t3 = getTimer();
   for ( i=0;i<cullcon.length/3;i+=1){
    z1=vert3D[cullcon[i*3]*3+2];
    z2=vert3D[cullcon[i*3+1]*3+2];
    z3=vert3D[cullcon[i*3+2]*3+2];
    avz=(z1+z2+z3)/3
    z1=Math.abs(z1-avz);
    z2=Math.abs(z2-avz);
    z3=Math.abs(z3-avz);
    if (z1<z2) z1=z2;
    if (z1<z3) z1=z3;
    xmin=xmax=vert2D[cullcon[i*3]*2];
    ymin=ymax=vert2D[cullcon[i*3]*2+1];
    if (xmin>vert2D[cullcon[i*3+1]*2]) xmin=vert2D[cullcon[i*3+1]*2];
    else if (xmax<vert2D[cullcon[i*3+1]*2]) xmax=vert2D[cullcon[i*3+1]*2];
    if (xmin>vert2D[cullcon[i*3+2]*2]) xmin=vert2D[cullcon[i*3+2]*2];
    else if (xmax<vert2D[cullcon[i*3+2]*2]) xmax=vert2D[cullcon[i*3+2]*2];
    if (ymin>vert2D[cullcon[i*3+1]*2+1]) ymin=vert2D[cullcon[i*3+1]*2+1];
    else if (ymax<vert2D[cullcon[i*3+1]*2+1]) ymax=vert2D[cullcon[i*3+1]*2+1];
    if (ymin>vert2D[cullcon[i*3+2]*2+1]) ymin=vert2D[cullcon[i*3+2]*2+1];
    else if (ymax<vert2D[cullcon[i*3+2]*2+1]) ymax=vert2D[cullcon[i*3+2]*2+1];
    zdist.push(new Poly3(avz,z1,xmin,xmax,ymin,ymax));
   }
   t4 = getTimer();
   zdist=zdist.sort(compare,Array.DESCENDING|Array.RETURNINDEXEDARRAY);
   t5 = getTimer();
   for each(i in zdist){
    wcon.push(cullcon[i*3],cullcon[i*3+1],cullcon[i*3+2]);
   }
   t6 = getTimer();
   s.graphics.drawTriangles(vert2D,wcon,_uvtData,TriangleCulling.POSITIVE);
   t7 = getTimer();
   trace("-----");
   trace(t2-t1);
   trace(t3-t2);
   trace(t4-t3);
   trace(t5-t4);
   trace(t6-t5);
   trace(t7-t6);
  }

これでogreモデルを表示させて数回回転させた結果が以下だ。上から順にt2−t1、t3−t2のように各通過時間の差になっている。

-----
1
11
67
225
2
0
-----

予想通りt4〜t5のところ(ポリゴンをソートしている部分)が220ミリ秒程度で一番時間を消費している。それに続いて多いのがt3〜t4の部分でポリゴンの奥行きを粗く比較するかどうかのデータを生成している部分だ。これに70ミリ秒程度の時間を要している。そしてt2〜t3のポリゴンの裏表判定をしている部分。ここに12ミリ秒程度の時間を要している。それに対して座標変換を2回もしてるのにt1〜t2は1ミリ秒しかかかっていないし、t5〜t6のソートし終わったポリゴンを再構成している部分やt6〜t7のポリゴンを描画している部分も殆ど時間がかかっていない。

以上の事からやはり一番力を入れなきゃならないのはソートの部分で、そこから呼び出している比較関数compare()を最適化するのが最も処理速度向上に効果がありそうだ。

そこでまず、最もムダっぽく、かつ簡単に直せそうなところで、poly3クラスのインスタンスメンバーにアクセスする際に使っているアクセッサメソッドをやめて、メンバーに直接アクセスするようにしてみた。Poly3クラスのメンバー変数をprivateからpublicに書き換えて、

 public class Poly3 {
  public var depth:Number;
  public var zrange:Number;
  public var xmin:Number;
  public var xmax:Number;
  public var ymin:Number;
  public var ymax:Number;
      :

アクセッサメソッドは全部削除し、iscover( )メソッド内でアクセッサメソッドが使われている部分は全部直接メンバー変数を参照する形に書き換えた。

if(this.xmin<p.getXmin( )){
      ↓
if(this.xmin<p.xmin){

同様にModelDataクラスのcompare( )内で使われているアクセッサメソッドもメンバー名に書き換えた。

以下がその結果。

-----
1
11
68
176
1
1
-----

225ミリ秒だったソートが176ミリ秒に減った。呼び出しのオーバーヘッドは結構大きいようだ。そこでPoly3クラスのメソッドだったiscover( )をModelDataクラスのcompare()メソッド内に移した。

-----
1
11
68
165
1
1
-----

ソートの次にオーバーヘッドが大きいのはPoly3データを生成してzdistにpushする部分で、この部分はvert3Dやvert2Dをcullconに格納されたデータを使って間接参照している。参照のたびにそのアドレス計算をしているけど、同じアドレスなら1度計算すればいいわけだし、そこで得られたデータを変数に格納しておけば、配列を参照する必要すらなくなる。そこでそういう無駄を取り除いて展開したのが次のコードで、

   for ( i=0;i<cullcon.length/3;i+=1){
    ptr1=cullcon[i*3];
    ptr2=cullcon[i*3+1];
    ptr3=cullcon[i*3+2];
    ptr21=ptr1*2;
    ptr22=ptr2*2;
    ptr23=ptr3*2;
    ptr31=ptr1*3;
    ptr32=ptr2*3;
    ptr33=ptr3*3;
    z1=vert3D[ptr31+2];
    z2=vert3D[ptr32+2];
    z3=vert3D[ptr33+2];
    avz=(z1+z2+z3)/3
    z1=z1-avz;
    if (z1<0) z1=-z1;
    z2=z2-avz;
    if (z2<0) z2=-z2;
    z3=z3-avz;
    if (z3<0) z3=-z3;
    if (z1<z2) z1=z2;
    if (z1<z3) z1=z3;
    xmin=xmax=vert2D[ptr21];
    ymin=ymax=vert2D[ptr21+1];
    tx=vert2D[ptr22];
    if (xmin>tx) xmin=tx;
    else if (xmax<tx) xmax=tx;
    tx=vert2D[ptr23];
    if (xmin>tx) xmin=tx;
    else if (xmax<tx) xmax=tx;

    ty=vert2D[ptr22+1];
    if (ymin>ty) ymin=ty;
    else if (ymax<ty) ymax=ty;
    ty=vert2D[ptr23+1];
    if (ymin>ty) ymin=ty;
    else if (ymax<ty) ymax=ty;
    
    zdist.push(new Poly3(avz,z1,xmin,xmax,ymin,ymax));
   }

極力配列へのアクセスや重複する計算を削除してみた。その結果が以下で、68ミリ秒あった処理時間が16ミリ秒に短縮された。これでトータル120ミリ秒くらいは削れた。でもフレームレートを24にしようと思ったら40ミリ秒程度で処理が終わらないとならないわけで、これはかなり無理があるな。

-----
1
12
16
169
2
0
-----

ちなみにソートを3角ポリゴンの平均Z値でソートするようにソート部分を書き換えると処理時間はこうなる。

-----
1
12
16
3
1
0
-----

ソートにたった3ミリ秒しかかかってない。トータルで23ミリ秒で40ミリ秒を大きく下回っている。これなら24フレーム/秒も可能なわけだ。

以上の事から結論としてはソートの比較関数をいじっても高速化には限度があることがわかった。逆に深度だけのソートなら12000ポリゴン程度扱ってもまだまだ余裕があるって事だ。

と言う事は、ポリゴンの平均Z値でソートする方法を使う替わりに、その方法でも正確に表示されるようにポリゴンを分割して増やすというのがフラッシュ3Dでは有効な手段なのかもしれない。ただしこれを動的にやってしまうとまたオーバーヘッドも大きくなるので、ポリゴンを読み込む段階で行うか、modoからエクスポートする時に行うくらいがいいのかな?ただしアニメーションさせても追従しない欠点は残るね。

それではまた次回。

modoカテゴリー別ページ

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

2010年06月28日

3ds Max 2011がやって来た その11 3dsmax2011

最初に書いとくけど自分はマテリアルライブラリーをロードする方法は知ってるけど、MetaSLのマップノードをブラウザにロードする方法がわからない。もしそういう方法があれば今回のような事はする必要がない。

前回も書いた通り、MAXのストレートマテリアルで表示されるMetaSLシェーダーの数がmentalmillのものと比べて非常に少ない。

fig01こっちがMAXのストレートマテリアルでレンダラをQuickSilverかMentalrayにした時に出てくる。

fig02そしてこっちがmentalmill。シェーダーの数が多過ぎてフォルダを閉じたままでも上の画像より多くなっている。

そしてMAXのインストールフォルダーにはmentalmillのシェーダーノードと同様の名前のファイル群が存在する。もちろんmentalmillから出力したXMSLファイルをDirectXシェーダーで読み込めるようになっているからこれらのファイルはただそっちのために使われているとも考えられたけど、やっぱり腑に落ちない。

そこで前回書いたようにMAXの方にあってmentalmillの方に無い「NormalsBumpmap」が記述されている場所をMAXのファイルから探し出してみることにした。そうすればマテリアルマップブラウザで現れるリストがどんな仕組みになっているかわかると思ったからだ。さっそくgrepを使ってテキスト検索したら、「C:¥Program Files¥Autodesk¥3ds Max 2011¥mentalimages¥shaders_standard¥metaSL¥Config」フォルダに「MaxMetaSLNodeTexmap.tbx」というファイルが見つかった。

<palette name="MaxDefault">
       :
 <palette_item type="node_class" node_class="Normals_bumpmap"                image="make_normal.bmp"/>
       :
</palette>

他の行も見るとマップブラウザのリストそっくりだ。そこで試しに1つシェーダーノードを書き加えてみた。

 <palette_item type="node_class" node_class="Texture_lookup_1d"              image="texture_lookup_1d.bmp"/>

これは1次元のビットマップから色をピックアップするもので、maxのブラウザには2次元のビットマップから色をピックアップするTexture lookup 2dが存在する。

そしてこれがMAXを再起動してマップブラウザを表示したもの。確かに1dが増えている。

fig03


そしてこれがストレートマテリアルエディタにドラッグ&ドロップしてみたもの。比較のために2dの方もドラッグ&ドロップしてみた。

fig04

1dの方はTexure という1次元入力なのに対して2dの方はTexture UVで2次元になっている。どうやらこの方法でmentalmillのシェーダーノードを追加できそうだ。ただしブラウザの方が多階層構造の表示が出来ない感じなので、このまま全部登録したらやっぱり酷いことになるんだろうね。どうしたもんだろう。

それではまた次回。

maxまとめページ 

 



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

2010年06月27日

米の栽培キットを買ってみた その9

毎日暑くて人間はげんなりして来ているけど稲の方はどんどん活気が出てきた。もうヒョロヒョロの苗だった面影はどこにもない。稲すげぇ。

fig01

なんだかどんどん株が増えてたくましくなってきた。どこまで株は増えるんだろう。

fig02

稲は今のところ食われて無いんだけど枝豆の葉とかが食べられていて、犯人探しをしていたら、どうやらこいつが犯人らしい。青虫ばかり探してたけど、こういう飛んでくる虫が葉を食べるとなると、駆除はなかなか難しいね。

カナブン



take_z_ultima at 23:52|この記事のURLComments(0)TrackBack(0)園芸 | Goods

ネギの再生 その1

セコい話だけどネギは再生できる。

だからネギを買う時は根の部分をよく見て生きていそうなものを選ぶようにしている。

ほんの半月前に買ったネギの根っこの部分をこのように水に浸して、

切ったネギの根の部分


暑いと腐りやすいので、暗くて涼しい場所に置いて日に1~2度水を変えながら根が出るのを待った。

ここでダメなネギは根も出ないまま腐っておしまいになる。今回のものはなんとか根が出たようだ。でも上側のものは1本しか根が出てないから育つかどうかは微妙だ。

根が出たネギ

あまり水に浸しておくと本体が腐ってくるのである程度根が出たら土に植える。

根が出たネギを植える

そして再び涼しくて暗い場所に、水を切らさないようにしながら置いておく。

うまく行けば暫くするとネギの中央部分が盛り上がって伸びてくる。

ネギの芽が出てきた

もうちょっと伸びたら明るいところに出して10cmくらい伸びるまでポットで育てる。

果たしてこのまま育つかな

これは以前に再生させたネギ。直径10cm以上の葱坊主が3つも付いている。一緒に生えているのはアスパラ。すでに人の背丈より高く成長してしまった。

以前に再生させたネギ

これを引っこ抜いて食べて、切り株をまた再生させて行けば無限に食べられるねw



take_z_ultima at 23:43|この記事のURLComments(0)TrackBack(0)園芸 
Archives