2018年11月08日

記事タイトルビットマップペイントツールのチュートリアルをやってみた その182 3dsmax 2018

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

256X256で粗くペイントした時に下のような穴が出来たりする不具合を見つけた。

fig01

UVマップ上ではこんな感じ。

fig02

そこでこの付近のポリゴンの状態を調べるために1つの頂点を共有するポリゴンのデータを抜き出してみた。

fig03

これがそのデータ。これだけだとよくわからないので、

fig04

これを元にポリゴンを描いてみたのが下の画像だ。見ての通り穴があいていた部分でポリゴンが欠けているのがわかった。

fig05

この隙間は0.894で1未満だ。

fig06

エッジの長さが1未満の場合は同じ位置の頂点として端折るようにしてあったので、この三角形は2点が1点になってしまってポリゴン不成立で削除されてしまったようだ。

しかし下のようにピクセルの描画ラインを描いてみると、この欠けた三角形の中にピクセルを描ける点が存在するのがわかる。つまりこのポリゴン捨てちゃまずかったんだな。

fig07

続きはまた次回。

来週は更新をお休みします。

maxまとめページ



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

2018年11月07日

Selection Assembliesについて調べてみた その19 modo12

引き続き「presets」パネルの「Selection Assemblies」にあるアセンブリを調べてみたい。

今回は「Select N-Gon Polygons」アセンブリ。

fig01

中身はこうなっていて、毎度お馴染み「Selection Operator」が今回は2つに分離されないで扱われている。ポリゴンの頂点数を「頂点カウント」チャンネルから出力して、それを特定の数値と比較してそれより多ければ選択される構造だ。

fig02

その比較している数値は4だ。だからこのアセンブリは頂点が5つ以上の多角形ポリゴンを選択するためのもののようだ。

fig03

下の例ではレイアウトにカメレオンのモデルを読み込んで、ブランクの「Mesh」アイテムに「Merge Meses」でカメレオンのモデルを取り込んで、「Assign Selection Set」で「N-GON」と言う名前でポリゴンの選択セットを割り当ててみた。

fig04

そしてその「ポリゴン選択セット」を使ってみると、下のように5角形以上のポリゴンが選択された。

fig05

続きはまた次回。

modo10-12ブログ目次



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

2018年11月06日

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

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

生成したビットマップを見るとおかしな隙間が出来ているのを見つけた。

fig01

これがどこの異常なのかを確認するために計算から出したはみ出し部分の色を無視して赤で塗ってみたのが下の画像だ。

名fig02

これを見ると隙間が無い。つまり隙間は色の算出の方に問題があるようだ。

そこで該当するポリゴンを検出したら「flg」プロパティをtrueにするようにして、その時の「colOnEdge()」内の状態を出力してみた。

fn colOnEdge px py x1 y1 x2 y2 mb2w = (
  dx = (x2-x1)
  dy = (y2-y1)
  dl = dx * dx +  dy * dy + 0.0
  c = undefined
  if dl != 0.0 do(
    d1 = dx/dl
    d2 = dy/dl
    t = (py-y1)*d1-(px-x1)*d2  
    ex = dy*t+px
    ey = -dx*t+py
    if  not checkBitmap [ex+ey*bitmapX] then (
      c   = pcol ex ey mb2w
    ) else (
      c = (getPixels theBitmap [ex,ey] 1)[1]
    )
  )
  if flg then format "c:% ckbm:% e:% %\n" c (checkBitmap [ex+ey*bitmapX]) ex ey
  if c == undefined then c = (getPixels theBitmap [px,py] 1)[1]
  return c
),

これがその結果。よく見るとカラーを(color 255 255 255)で返してくる場合、「checkBitmap」の値がtrueになっていて、ペイント済みのピクセルであり、色は「getPixcels()」で得ている事がわかった。

fig03

そしてその座標値は、「checkBitmap」と「getPixcels()」で方式が異なっていて、しかも[ex,ey]は実数座標値だ。

と言うわけで[ex,ey]を整数座標値にして両者の位置を一致させた。

fn colOnEdge px py x1 y1 x2 y2 mb2w = (
  dx = (x2-x1)
  dy = (y2-y1)
  dl = dx * dx +  dy * dy + 0.0
  c = undefined
  if dl != 0.0 do(
    d1 = dx/dl
    d2 = dy/dl
    t = (py-y1)*d1-(px-x1)*d2  
    ex = int(dy*t+px)
    ey = int(-dx*t+py)
    if  not checkBitmap [ex+ey*bitmapX] then (
      c   = pcol ex ey mb2w
    ) else (
      c = (getPixels theBitmap [ex,ey] 1)[1]
    )
  )
  
  if c == undefined then c = (getPixels theBitmap [px,py] 1)[1]
  return c
),

これがその実行結果。謎の隙間は解消された。

fig04

続きはまた次回。

maxまとめページ



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

2018年11月05日

Selection Assembliesについて調べてみた その18 modo12

引き続き「presets」パネルの「Selection Assemblies」にあるアセンブリを調べてみたい。

今回は「Select Edges By Length」アセンブリ。

fig01

これはエッジの長さが「Minimum Length」から「maximum Length」の間にあるものを選択するアセンブリだ。

中身はこんか感じ。毎度お馴染み「選択オペレータ:エッジ」からエッジの長さを「長さ」チャンネルから取得して、4つの条件式ノードの組みあわせで、そのエッジの長さが「Minimum Length」と「maximum Length」の大きい方と「maximum Length」の間の長さだったら「選択」チャンネルにtrueを渡してそのエッジが選択対象であることを出力する。

fig02

これを使ってみると、例えば下のようにシーンに円柱を追加して中心にベンドエフェクタを仕込んで曲がるようにしておく。

fig03

これに「Edge Extrude」を追加して、「インセット」と「シフト」を適当にセットする。

fig04

これをスケマティックビューにドロップして、「Select Edge By Length」と接続して、

fig05

プロパティを以下のように設定して円柱のエッジの長さが150mm〜1mの間にある時に選択されるようにする。

fig05

そしてベンドしてみると、伸びて150mmを超えたエッジだけ「Edge Extrude」されるようになる。

fig06

続きはまた次回。

modo10-12ブログ目次



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

2018年11月01日

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

引き続きMAXScriptマニュアルに載っている「チュートリアル-ビットマップペイントツールを9つの簡単なステップで作成する」 の続きを考えて見たい。
まだまだいろいろ不具合はあるんだけど、ブラシサイズを大きくして実行してみたらエラーで止まってしまう事があった。調べてみるとはみ出し塗りをする時のカラーデータがundefinedになってしまっているようで、「colOnEdge()」が吐き出してる。「colOnEdge()」は最後の段でカラーがundefinedであればペイントする地点のカラーを拾って返してるのでundefinedを返しているのは「getPixels()」と言う事になる。

fn colOnEdge px py x1 y1 x2 y2 mb2w = (
  dx = (x2-x1)
  dy = (y2-y1)
  dl = dx * dx +  dy * dy + 0.0
  c = undefined
  if dl != 0.0 do(
    d1 = dx/dl
    d2 = dy/dl
    t = (py-y1)*d1-(px-x1)*d2  
    ex = dy*t+px
    ey = -dx*t+py
    if  not checkBitmap [ex+ey*bitmapX] then (
      c   = pcol ex ey mb2w
    ) else (
      c = (getPixels theBitmap [ex,ey] 1)[1]
    )
  )
  if c == undefined then c = (getPixels theBitmap [px,py] 1)[1]
  return c
),

「getPixels()」がundefinedを返すのはなんだろうと思って渡している引数を調べてみたらpyの値がマイナスになっていて、ビットマップの範囲外のピクセルを調べている事がわかった。これはUVマップがビットマップの外周ギリギリまで存在しているためにはみ出し塗りをする時に外にはみ出してしまうせいだ。

名称未設定 2

そこでY座標値についてビットマップの範囲を超えたらタイリングしてビットマップの反対側に座標が回るように変更した。

fn paintFace vface mb2w = (
  corner_n = #()
  corner_y = #()
  center = [0,0,0]
  n = vface.count
  dlt1 = delty vface[n] vface[1]
  for i = 1 to n do
  (
    nexti = int(mod i n ) + 1
    dlt2 = delty vface[i] vface[nexti]
    chng = dlt1 * dlt2
    if chng <= 0 and (dlt1 !=0 or dlt2 !=0)then (
      append corner_n i
      append corner_y (int(vface[i].y))
    )
    dlt1 = dlt2
    center += vface[i]
  )
  center /= n
  append corner_n corner_n[1]  
  append corner_y corner_y[1]
      
  side = #()
  cap = #()
  for i = 1 to (corner_n.count-1) do (
    border = #()
    ptr = corner_n[i]
    s = 0
    do (
      append border vface[ptr]
      ptr = int(mod ptr n ) + 1
      s = s + 1
      if s > 100 then exit
    ) while (ptr != corner_n[i + 1])
    append border vface[ptr]
    if (corner_y[i] - corner_y[i+1]) == 0 then (
      append cap border
    ) else (    
      append side border
    )
  )
  if side.count>=2 then (
    if side[1][2][1] > side[2][2][1] then (
      tmps = side[1]
      side[1] = side[2]
      side[2] = tmps
    )
    s1 = s2 = 0  
    if side[1][1][2] > side[1][side[1].count][2] then (
      s1 = 2
      s2 = 1
    ) else (
      s1 = 1
      s2 = 2
    )
    side2ptr = side[s2].count
    for i = 1 to ( side[s1].count - 1) do
    (
      for iy = (ceil(side[s1][i][2])) to (floor(side[s1][i+1][2])) do
      (
        while iy > (floor(side[s2][side2ptr - 1][2])) do (
          side2ptr -= 1  
        )
        if side2ptr == 1 then side2ptr = 2
        ix1 = scanx side[s1][i] side[s1][i+1] iy
        ix2 = scanx side[s2][side2ptr] side[s2][side2ptr-1] iy
        drawline ix1 ix2 iy mb2w 
      )
    )

    for ed in cap do (
      for p = 1 to (ed.count - 1) do (
        if ed[p][3] == 1.0 then (

          if ed[p][1] < ed[p+1][1] then (
            x1 = ed[p][1]
            x2 = ed[p+1][1]
            y1 = ed[p][2]
            y2 = ed[p+1][2]
          ) else (
            x2 = ed[p][1]
            x1 = ed[p+1][1]
            y2 = ed[p][2]
            y1 = ed[p+1][2]
          )
          l = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
          nx =  - (y2-y1) / l * overpaint
          ny =  (x2-x1) / l * overpaint
          if ny < 0 then (
            nx = -nx
            ny = -ny
          )
          sy = 0
          if ed[1][2] < center[2] then (
            x4 = x1 - nx
            x3 = x2 - nx
            y4 = y1 - ny
            y3 = y2 - ny
          ) else (
            x4 = x1 + nx
            x3 = x2 + nx
            y4 = y1 + ny
            y3 = y2 + ny
          )
          arx = sort #(x1,x2,x3,x4)
          ary = sort #(y1,y2,y3,y4)
          
          
          det=(x2-x1)*y4+(-x4+x1)*y2+(x4-x2)*y1
          m11 = (y4-y1)/det
          m12 = -(y2-y1)/det
          m21 = -(x4-x1)/det
          m22 = (x2-x1)/det
          m31 = -(x1*y4-x4*y1)/det
          m32 = (x1*y2-x2*y1)/det
          
          for y = int(ary[1]) to int(ary[4]) do (
            for x = int(arx[1]) to int(arx[4]) do (
              tx = m11 * x + m21 * y + m31
              ty = m12 * x + m22 * y + m32
              if tx >=0 and tx <=1 and ty >=0 and ty <= 1 then (
                lx = int(mod (x+bitmapx) bitmapx)
                ly = int(mod (y+bitmapy) bitmapy)
                c = colOnEdge lx ly x1 y1 x2 y2 mb2w
                if c != undefined then setPixels theBitmap  [lx,ly] #(c)
              )
            )
          )
          
        )
      )
    )

    for ed in side do (
      for p = 1 to (ed.count - 1) do (
        if ed[p][3] == 1.0 then (
          x1 = ed[p][1]
          x2 = ed[p+1][1]
          y1 = ed[p][2]
          y2 = ed[p+1][2]
          l = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
          nx =  - (y2-y1) / l * overpaint
          ny =  (x2-x1) / l * overpaint
((((x1 - center[1]) + (x2 - center[1])) * nx) +((y1 - center[2]) + (y2 - center[2])) * ny))
          if ((((x1 - center[1]) + (x2 - center[1])) * nx) +((y1 - center[2]) + (y2 - center[2])) * ny) < 0.0 then (
            nx = -nx
            ny = -ny
          )
          x4 = x1 + nx
          x3 = x2 + nx
          y4 = y1 + ny
          y3 = y2 + ny

          arx = sort #(x1,x2,x3,x4)
          ary = sort #(y1,y2,y3,y4)
          
          
          det=(x2-x1)*y4+(-x4+x1)*y2+(x4-x2)*y1
          m11 = (y4-y1)/det
          m12 = -(y2-y1)/det
          m21 = -(x4-x1)/det
          m22 = (x2-x1)/det
          m31 = -(x1*y4-x4*y1)/det
          m32 = (x1*y2-x2*y1)/det
          
          for y = ceil(ary[1]) to floor(ary[4]) do (
            for x = ceil(arx[1]) to floor(arx[4]) do (
              tx = m11 * x + m21 * y + m31
              ty = m12 * x + m22 * y + m32
              if tx >=0 and tx <=1 and ty >=0 and ty <= 1 then (
                lx = int(mod (x+bitmapx) bitmapx)
                ly = int(mod (y+bitmapy) bitmapy)
                c = colOnEdge lx ly x1 y1 x2 y2 mb2w
                if c != undefined then setPixels theBitmap  [lx,ly] #(c)
              )
            )
          )
          
        )
      )
    )
  )
),

続きはまた次回。

maxまとめページ



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