2017年08月

2017年08月31日

ビットマップペイントツールのチュートリアルをやってみた その79 3dsmax 2017

引き続きMAXScriptマニュアルに載っている「チュートリアル-ビットマップペイントツールを9つの簡単なステップで作成する」 の続きを考えて見たい。

今回はペイントの状態を1フレームずつ保存して、アニメーションにしてみた。

これがその結果。

fig01

これがそのプログラム。前回のプログラムとほぼ同じなんだけど、1フレーム進むたびにファイル名を変えながら保存する部分を付け加えた。

tdm = timeDisplayMode
timeDisplayMode = #frameTicks

pt = objectPaint()
pf = $PFソース002
pt.theObj =  $Sphere002
pt.maxFaceRadius = 4.0
pt.BrushShape = 1
pt.brushsize = 4
pt.BrushColor = red
pt.init()
pstart = 0
pstop = 32
tstep =10.0
for i = (pstart * tstep) to (pstop * tstep) do (
	sliderTime = i / tstep
	count = pf.NumParticles()
	for j = 1 to count do (
		pf.particleIndex = j
		pt.brushtransform = pf.particleTM
		pt.doPaint()
	)
	if (mod i tstep) == 0 then (
		sf = "00" + ((i / tstep) as integer) as string
		temp_bitmap_filename = (getDir #preview +"/test"+ substring sf (sf.count - 2) (sf.count)  +".tga")
		pt.theBitmap.filename = temp_bitmap_filename
		pt.saveimage()
	)
)

pt.close()
timeDisplayMode = tdm

「mod i tstep」で現在時刻をフレームの分割数で割った余りを計算してそれが0の時、時刻がフレーム単位ぴったりの時なので、それをビットマップ保存のタイミングにしている。

そして「(i / tstep) as integer」でそのフレーム数を得て、「as string」でその数を文字列にして「"00"」を加えて、「0012」のように頭に「00」が付くフレーム番号の文字列にした。そして「substring sf (sf.count - 2) (sf.count) 」で後ろから3文字取り出すことで3ケタの数値を表す文字列にして、「プレビューディレクトリー/test012.tga」のようなファイルパス文字列を生成して、それをビットマップのファイル名に設定して、「pt.saveimage()」でファイル出力した。

これでフレームごとに更新されたビットマップが出力される。ディフューズマップにビットマップを割り当てて、その画像ファイルにこれらの画像ファイルを「シーケンス」オプションをONにして読み込んで割り当てれば、最初に出て来たシーンのようにマテリアルがアニメーションするようになる。

fig02

続きはまた次回。明日はお休みします。

maxまとめページ



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

2017年08月30日

自動リトポ ツールを調べてみた その4 modo11.0v3

前回に引き続き「Automatic Retopology(自動リトポ)」ツールについて調べてみたい。

今回は3つの「ポリゴン数モード」を比較してみた。比較に使ったのは頭部のモデルだ。このモデルはディテールの細かい部分とそうでもない部分が混在している。

fig01

このモデルをフリーズするとこのようになり、総ポリゴン数は38432になった。

fig04

まず「相対」モードで以下のパラメータで処理してみた。

fig06

これがその結果。「ポリゴンスケール」が「選択ウェイトマップ」になっていて、特にウェイトマップを設定していないので下のように均一な大きさのポリゴンメッシュに再構成されたため、細かいディテールは失われてしまった。

fig02

次に「絶対」モードでやってみた。「ポリゴンターゲット」はフリーズ後のポリゴン数である38432を設定してみた。

fig07

これがその結果。総ポリゴン数は38689になった。これも「相対」よりはポリゴンが細かくなったけど、ポリゴンのサイズはこれも均一のためにまぶたの所とかのディテールは失われている。

fig03

次は「アダプティブ」モードだ。

fig08

そしてこれが結果。総ポリゴン数は28075で「絶対」モードよりポリゴン数は少ないけど、ディテールがほぼ保たれたままポリゴンが再構成されていて、ディテールが細かい部分はポリゴンサイズも細かくなり、ディテールが細かくない部分はポリゴンサイズが大きくなっている。

fig05

続きはまた次回。

modo10-11ブログ目次



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

2017年08月29日

ビットマップペイントツールのチュートリアルをやってみた その78 3dsmax 2017

引き続きMAXScriptマニュアルに載っている「チュートリアル-ビットマップペイントツールを9つの簡単なステップで作成する」 の続きを考えて見たい。

今回は前回作ったプログラムの解説から。

tdm = timeDisplayMode
timeDisplayMode = #frameTicks
pt = objectPaint()
pf = $PFソース002
pt.theObj = $Sphere002
pt.BrushShape = 1
pt.brushsize = 4
pt.BrushColor = red
pt.maxFaceRadius = 4.0
pt.init()
pstart = 12
pstop = 32
tstep =10.0
for i = (pstart * tstep) to (pstop * tstep) do (
  sliderTime = i / tstep
  count = pf.NumParticles()
  for j = 1 to count do (
    pf.particleIndex = j
    pt.brushtransform = pf.particleTM
    pt.doPaint()
  )
)
pt.saveimage()
pt.close()
timeDisplayMode = tdm

このプログラムはパーティクルシステムからシーンの現在のパーティクルの変換マトリクスを取得して、それに仮想のブラシを割り当ててペイントするようになっている。だからペイントの跡は常にペイントブラシの形状のスタンプのようになる。パーティクルの速度がゆっくりの場合はそのブラシの跡が徐々に動いて行くことで連続したストロークになって行くわけだけど、パーティクルが速いとペイント跡が繋がらず、点々としたものになってしまう。これを解消する方法はいろいろ考えられるけど、上のプログラムではペイントする時間間隔を短くすることで行っている。

シーンのタイムスライダーはデフォルトでフレーム単位になっているけど、これをフレームとティック単位(1ティックは1/4800秒)で行えるように切り替えている。タイムスライダーの設定は「timeDisplayMode」から取得、設定出来るので、プログラム開始時に現在の設定を「tdm」に記録してから「#frameTicks」に設定し、プログラムの終了時に戻している。

「objectPaint」構造体のインスタンスは「pt」に格納して、ペイントする対象として「theObj」プロパティに「$Sphere002」を、ブラシの形状として「BrushShape」に1をセットして円形にし、サイズとして「brushsize」に4を、ペイント色として「BrushColor」に「red」を設定した。

そしてペイントするオブジェクトを構成する面の外接円で最大のものの半径「maxFaceRadius」に4を設定する事で、ボリューム選択で選択する範囲を絞り込んで、処理の高速化をはかった。

これらを決めてから「init()」を呼んで、ペイントするオブジェクトにマテリアルを設定したり、ペイントするビットマップを生成したりしている。

「pstart」「pstop」「tstep」はペイントの開始フレームと終了フレームと1フレームを何分割するかの値を格納している。この例では12フレームから32フレームを各1/10フレーム刻みでペイントしている。外側の「for」文はシーンの時刻を1/10フレームずつ進める役割をしている。実際の時刻の設定は「sliderTime」へのフレーム数の代入で行っている。

pstart = 12
pstop = 32
tstep =10.0
for i = (pstart * tstep) to (pstop * tstep) do (
  sliderTime = i / tstep
  count = pf.NumParticles()
  for j = 1 to count do (
    pf.particleIndex = j
    pt.brushtransform = pf.particleTM
    pt.doPaint()
  )
)

シーンに存在するパーティクルの数は「PFソースオブジェクト」の「NumParticles()」メソッドから取得出来て、個々のパーティクルには、「particleIndex」に処理したいパーティクルの番号をセットする事でアクセス可能になる。内側の「for」文は全パーティクルを巡回するためのものだ。そして、「particleTM」プロパティで「j」番目のパーティクルの変換マトリクスを取得して、「objectPaint」の「brusjtransform」にセットして、「doPaint()」を呼び出すことでパーティクルをブラシとしてペイントが実行される。この時ビットマップにペイントはされるけどオブジェクトに割り当てられているマテリアルは更新されない。

全てのペイントが終わったら、「saveimage()」を呼び出すことでイメージがファイルの保存され、マテリアルが更新される。

最後にペイントするオブジェクトに割り当てていた「ボリューム選択」などのモディファイヤを削除するために「close()」を呼び出し、タイムスライダーの設定を元に戻してプログラムの終了だ。

pt.saveimage()
pt.close()
timeDisplayMode = tdm

続きはまた次回。

maxまとめページ



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

2017年08月28日

自動リトポ ツールを調べてみた その3 modo11.0v3

前回に引き続き「Automatic Retopology(自動リトポ)」ツールについて調べてみたい。

今回は「新規メッシュ」オプションについて調べてみた。

fig01

このオプションは新規に生成したメッシュを元のメッシュと置き換えるのか、新たなアイテムとして追加するのかを切り替えるものだ。

単純にそれだけだったら良かったんだけど、実際に比較してみると随分結果が異なってくるので困る。

下のように24枚のポリゴンで出来たサブディビジョンサーフェスのオブジェクトを用意して、これがどうなるかを試してみた。

fig02

パラメータは以下の通りで「新規メッシュ」オプションだけ切り替えて比較してみた。

fig03

これがその結果(クリックすると大きくなるよ)。「新規メッシュ」をOFFにした真ん中のものとONにした右のもので明らかにまるで違うものが生成されてしまったのがわかる。また、メッシュを置き換えた場合はサブディビジョンの設定がそのまま引き継がれるのに対して新規に生成した場合はSDSをフリーズしてからメッシュを調整している感じだ。

fig04

「新規メッシュ」OFFで変換したオブジェクトのサブディビジョンをOFFにすると元になったサブディビジョンサーフェスに接する大きさのメッシュになる。

fig05

分割が細かくなればこの差異も縮まるけど、基本的にSDSに対して「新規メッシュ」OFFのまま「Automatic Retopology」をかけ続けるとどんどんオリジナルより小さくなって行くって事になる。

fig06

上の例では「ポリゴン数モード」として「相対」モードで試してみたけど、今度は「絶対」モードで試してみた。

上と同様にスタートは下のようなSDSだ。

fig02

上のメッシュで24枚のポリゴンで出来ているので、ポリゴンターゲットとして100枚にしてみた。

fig07

結果はなんとこんな破片みたいなものになってしまった。

fig08

次に今度は10000にしてみた。

fig09

結果は644ポリゴンのSDSが生成された。果たして10000はどこへ?

fig10

もしやと思ってこのSDSをフリーズしてみたのが下の画像だ。このメッシュのポリゴン数が10304。なんと「絶対」モードで指定したポリゴンターゲットの数値はフリーズした時のポリゴン数だったようだ。

fig11

ターゲットを100にして生成したSDSもフリーズしてみたら128ポリゴンになった。

「新規メッシュ」をONにしてターゲットを10000にした場合は、SDSがOFFになって、10184ポリゴンのメッシュアイテムが新たに生成された。

「絶対」モードを使って気付いたんだけど、「ポリゴンターゲット」に0以外の数値を設定した上で「相対」モードに戻した場合、「ポリゴンターゲット」の値は下の画像のようにグレー表示になって変更出来なくなる。いかにもこの値は無効っぽく感じるんだけど実際はこの数値は「相対」モードでも影響を与えるようで、「相対」モードを使う時は手動で0に戻しておく必要があるようだ。

fig12

続きはまた次回。

modo10-11ブログ目次



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

2017年08月24日

ビットマップペイントツールのチュートリアルをやってみた その77 3dsmax 2017

引き続きMAXScriptマニュアルに載っている「チュートリアル-ビットマップペイントツールを9つの簡単なステップで作成する」 の続きを考えて見たい。

今回は「objectPaint」構造体を使って、パーティクルでオブジェクトをペイントする実験をしてみた。

まずパーティクルとmassFXを使って下のようなシーンを作った。

fig01

これがパーティクルビュー。

fig02

シーン内の球体は2重になっていて、1つはペイント用の球で、もう一つはパーティクル用と衝突させるための球だ。パーティクルと衝突させる球をペイント対象に出来なくも無いんだけど、「ボリューム選択」モディファイヤを操作するとパーティクルの変換マトリクスが取得できなくなるようで、それを解消するためにはタイムスライダを再設定すればいい事は突き止めたんだけど、効率が悪くなるので2つに分けた方が賢明なようだ。

パーティクルと衝突させる球には「PFlowコリジョンシェイプ」モディファイヤを適用し、「パーティクルビュー」の「mPコリジョン」オペレータと接続した。

fig03

ペイント対象となる球体には「UVWアンラップ」モディファイヤでUVマップを設定した。これが無いとビットマップテクスチャに面が割り当てられないからね。

fig04

そしてこれが制御プログラム。これを実行する前に「objectPaint」構造体を定義するプログラムを実行する必要がある。変数「pt」に「objectPaint」構造体、「pf」にパーティクルの「PFソース」、「pt.theObj」にペイント対象の「$Sphere002」を割り当てて、12フレームから32フレームまで1フレームを10ステップ刻みでペイントしてみた。

tdm = timeDisplayMode
timeDisplayMode = #frameTicks
timeConfiguration.useTrackBar  = false
pt = objectPaint()
pf = $PFソース002
pt.theObj = $Sphere002
pt.BrushShape = 1
pt.brushsize = 4
pt.BrushColor = red
pt.maxFaceRadius = 4.0
pt.init()
pstart = 12
pstop = 32
tstep =10.0
for i = (pstart * tstep) to (pstop * tstep) do (
  sliderTime = i / tstep
  count = pf.NumParticles()
  for j = 1 to count do (
    pf.particleIndex = j
    pt.brushtransform = pf.particleTM
    pt.doPaint()
  )
)
pt.saveimage()
pt.close()
timeDisplayMode = tdm

今回のターゲットの球体は半径15で32セグメントなので1つの面のサイズの最大値「maxFaceRadius」は4に取った。これを大きく取りすぎると「ボリューム選択」の範囲が大きくなりすぎて無駄な処理が増えるし、小さすぎると面が選択されなくなってペイント出来なくなる。

fig06

そして下が「objectPaint」構造体を定義するプログラムのバグフィックス版。

struct objectPaint (
  public
    maxFaceRadius = 30.0,
    brushsize=10,
    BrushShape = 2,
    BrushColor = black,
    theObj,
    brushtransform,
    bitmapX = 512,
    bitmapY = 512,
    temp_bitmap_filename = (getDir #preview +"/microPaint_temp2.tga"),
    theBitmap,

  private
    sanim = undefined,
    fn chckClip p1 p2 w2b direction =
    (
      cplist = #()
      tlist = #()
      hsize = brushsize / 2.0
      bp1 = p1 * w2b
      bp2 = p2 * w2b

      st = 0
      t = 0.0
      case direction of (
        -- +x
        0:  (
            if bp1.x >= hsize then st = 1
            if bp2.x >= hsize then st = st + 2
            if st == 1 or st ==2 then (
              dx = bp2.x - bp1.x
              t = (hsize - bp1.x)/dx
            )
          )
        -- -x
        1:  (
            if bp1.x <= -hsize then st = 1
            if bp2.x <= -hsize then st = st + 2
            if st == 1 or st ==2 then (
              dx = bp2.x - bp1.x
              t = (-hsize - bp1.x)/dx
            )
          )
        -- +y
        2:  (
            if bp1.y >= hsize then st = 1
            if bp2.y >= hsize then st = st + 2
            if st == 1 or st ==2 then ( 
              dy = bp2.y - bp1.y
              t = (hsize - bp1.y)/dy
            )
          )
        -- -y
        3:  (
            if bp1.y <= -hsize then st = 1
            if bp2.y <= -hsize then st = st + 2
            if st == 1 or st ==2 then (
              dy = bp2.y - bp1.y
              t = (-hsize - bp1.y)/dy
            )
          )
        -- +z
        4:  (
            if bp1.z >= hsize then st = 1
            if bp2.z >= hsize then st = st + 2
            if st == 1 or st ==2 then (
              dz = bp2.z - bp1.z
              t = (hsize - bp1.z)/dz
            )
          )
        -- -z
        5:  (
            if bp1.z <= -hsize then st = 1
            if bp2.z <= -hsize then st = st + 2
            if st == 1 or st ==2 then (
              dz = bp2.z - bp1.z
              t = (-hsize - bp1.z)/dz
            )
          )
      )
      return #(st,t)  
    ),

    fn innerpoint p1 p2 t = (
      dx = p2.x - p1.x
      dy = p2.y - p1.y
      dz = p2.z - p1.z
      x = dx * t + p1.x
      y = dy * t + p1.y
      z = dz * t + p1.z
      return [x,y,z]
    ),

    fn clipface &vlist brushtransform = ( 
      for i = 0 to 5 do (
        tmp = #()
        for j = 1 to (vlist.count - 1) do (
          st = chckClip vlist[j] vlist[j+1] brushtransform i
          if st[1] == 0 then (
            append tmp vlist[j] 
          ) else if st[1] == 2 then (
            append tmp vlist[j] 
            append tmp (innerpoint vlist[j] vlist[j+1] st[2])
          ) else if st[1] == 1 then (
            append tmp (innerpoint vlist[j] vlist[j+1] st[2])
          )
        )
        if vlist.count == 0 then exit
        st = chckClip vlist[vlist.count] vlist[1] brushtransform i
        if st[1] == 0 then (
            append tmp vlist[vlist.count] 
        ) else if st[1] == 2 then (
          append tmp vlist[vlist.count]
          append tmp (innerpoint vlist[vlist.count] vlist[1] st[2])
        ) else if st[1] == 1 then (
          append tmp (innerpoint vlist[vlist.count] vlist[1] st[2])
        )
        vlist = tmp
      )
    ),

    fn selectcrossface brushtransform = (
      searchLength = sqrt(maxFaceRadius^2+brushsize^2) * 1.05
      bbox = nodeGetBoundingBox theObj theObj.transform
      sx = abs(bbox[1][1] - bbox[2][1])
      sy = abs(bbox[1][2] - bbox[2][2])
      sz = abs(bbox[1][3] - bbox[2][3])
      sanim.transform = brushtransform * inverse(theObj.transform)
      sanim.scale = [searchLength / sx,searchLength/sy, searchLength/sz]
      selfaces = getFaceSelection theObj
      return selfaces
    ),

    fn crossFaceMaps &maps theMesh theChannel brushtransform  mt2b =
    (
      invBrushTransform = inverse( brushtransform)
      crossfaces = selectcrossface brushtransform
      for faceIndex in crossfaces do (
        vlist = #()
        sufFace = getFace theMesh  faceIndex
        append vlist (getVert theMesh sufFace.x)
        append vlist (getVert theMesh sufFace.y)
        append vlist (getVert theMesh sufFace.z)
        mg2w=(matrix3 [vlist[1].x,vlist[1].y,vlist[1].z] [vlist[2].x,vlist[2].y,vlist[2].z] [vlist[3].x,vlist[3].y,vlist[3].z] [0,0,0])
        texFace = meshop.getMapFace theMesh theChannel faceIndex
        tv1= meshop.getMapVert theMesh theChannel texFace.x
        tv2= meshop.getMapVert theMesh theChannel texFace.y
        tv3= meshop.getMapVert theMesh theChannel texFace.z
        mg2t=(matrix3 [tv1.x,tv1.y,1] [tv2.x,tv2.y,1] [tv3.x,tv3.y,1] [0,0,0])
        
        mg2b = mg2t * mt2b
        mb2g = inverse mg2b
        mb2w = mb2g * mg2w

        clipface &vlist invBrushTransform

        if vlist.count == 0 then continue
        maplist =  #()
        for v in vlist do (
          mp = (meshop.getBaryCoords theMesh faceIndex v) * mg2t
          append maplist mp
        )
        append maps #(maplist , mb2w)
      )
    ),

    fn scanx p1 p2 y = (
      dx = p2[1] - p1[1]
      dy = p2[2] - p1[2]
      return int( dx * (y - p1[2]) / dy + p1[1] )
    ),

    fn drawline x1 x2 y theBitmap mb2w bpos = (
      for x = x1 to x2 do (
        if BrushShape == 1 then (
          p = [x,y,1.0] * mb2w
          if distance p bpos <= BrushSize/2 then setPixels theBitmap  [x,y] #(BrushColor)
        )
        else if BrushShape == 2 then setPixels theBitmap  [x,y] #(BrushColor)
      )
    ),

    fn paintFace vface theBitmap mb2w bpos = (
      maxy = miny = vface[1][2]
      top = bottom = 1
      for i = 2 to vface.count do
      (
        if vface[i][2] >= maxy then (
          maxy = vface[i][2]
          bottom = i
        )
        if vface[i][2] <= miny then (
          miny = vface[i][2]
          top = i
        )
      )
      side = #(#(),#())
        
    -- side1 vertex list
      sptr = 1
      vptr = top
      nvptr =  int(mod (vptr) vface.count) + 1
      safty = 1
      while vface[vptr][2] == vface[nvptr][2] do
      (
        vptr = int(mod (vptr) vface.count) + 1
        nvptr =  int(mod (vptr) vface.count) + 1
        safty +=1
        if safty > vface.count then return()
      )
      append side[sptr] vface[vptr]
      safty = 1
      do (
        vptr = int(mod (vptr) vface.count) + 1
        append side[sptr] vface[vptr]
        safty +=1
        if safty > vface.count then return()
      )
      while vface[vptr][2] != maxy
      
    -- side2 vertex list
      sptr = 2
      vptr = bottom
      nvptr =  int(mod (vptr) vface.count) + 1
      safty = 1
      while vface[vptr][2] == vface[nvptr][2] do
      (
        vptr = int(mod (vptr) vface.count) + 1
        nvptr =  int(mod (vptr) vface.count) + 1
        safty +=1
        if safty > vface.count then return()
      )
      
      append side[sptr] vface[vptr]
      safty = 1
      do (
        vptr = int(mod (vptr) vface.count) + 1
        append side[sptr] vface[vptr]
        safty +=1
        if safty > vface.count then return()
      )
      while vface[vptr][2] != miny
    --line scan
      side2ptr = side[2].count
      ix1 = scanx side[1][1] side[1][2] miny
      ix2 = scanx side[2][side2ptr] side[2][side2ptr-1] miny
      drawline ix1 ix2  miny theBitmap mb2w bpos

      for i = 1 to ( side[1].count - 1) do
      (
        for iy = side[1][i][2]+1 to side[1][i+1][2] do
        (
          while iy > side[2][side2ptr - 1][2] do (
            side2ptr -= 1  
          )
          if side2ptr == 1 then side2ptr = 2
          ix1 = scanx side[1][i] side[1][i+1] iy
          ix2 = scanx side[2][side2ptr] side[2][side2ptr-1] iy
          drawline ix1 ix2 iy theBitmap mb2w bpos
        )
      )
    ),

    fn delmodifier obj mtype = (
      local index = -1
      for i = 1 to obj.modifiers.count do (
      if (classof obj.modifiers[i]) == mtype then index = i
      )
      if index != -1 then (
        deletemodifier obj index
      )
    ),
  mt2b,
  public
    fn init = (
      theBitmap = bitmap bitmapX bitmapY color:white filename:temp_bitmap_filename
      if theObj.material == undefined do theObj.material = Standard()
      if theObj.material.diffusemap == undefined do
        theObj.material.diffusemap = bitmapTexture filename:temp_bitmap_filename
      showTextureMap theObj.material true
      
      --select theObj
      if theObj.modifiers[#Vol__Select] == undefined do (
        addModifier theObj (volumeselect())
      )
      if (classof theObj) != Editable_mesh do (
        addModifier theObj  (Turn_to_Mesh ())
      )
      vmod = theObj.modifiers[#Vol__Select]
      vmod.level = 2
      vmod.type = 1
      vmod.volume = 0
      sanim = vmod.gizmo
      mt2b=(matrix3 [bitmapX,0,0] [0,-bitmapY,0] [0,bitmapY,1] [0,0,0])
    ),
    fn doPaint = (
      local theMesh = snapshotAsMesh theObj
      local theChannel = 1
      local maps = #()
      crossFaceMaps &maps theMesh theChannel brushtransform mt2b
      for map in maps do (
        vface = #()
        for p in map[1] do (
          append vface [int(p.x * bitmapx), int(bitmapy - p.y * bitmapy)]
        )
        paintFace vface theBitmap map[2] brushtransform.pos
      )
    ),
    fn redraw = (
      theObj.material.diffusemap.bitmap = theBitmap
    ),
    fn saveimage = (
      save theBitmap
      theObj.material.diffusemap.bitmap = theBitmap
    ),
    fn close = (
      delmodifier theObj Vol__Select
      delmodifier theObj Turn_to_Mesh
    )
)

そして実行結果がこれ。球体にパーティクルが接触して行った跡がペイントできた。

fig05

続きはまた来週。明日はお休みします。

maxまとめページ



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