2019年06月18日

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

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

とりあえず今のところの全リストが下の通り。アンチエイリアスなしで1X1のUVマップで0.01の距離のはみ出し量に設定してある。

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

  private
    sanim,
    tmpm,
    maps,
    muw,
    cmuw = false,
    offpoint,
    borders,
    bareas,
  
    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 w2b = ( 
      for i = 0 to 5 do (
        vtmp = #()
        for j = 1 to (vlist.count - 1) do (
          st = chckClip vlist[j] vlist[j+1] w2b i
          if st[1] == 0 then (
            append vtmp vlist[j]
          ) else if st[1] == 2 then (
            append vtmp vlist[j] 
            append vtmp (innerpoint vlist[j] vlist[j+1] st[2])
          ) else if st[1] == 1 then (
            append vtmp (innerpoint vlist[j] vlist[j+1] st[2])
          )
        )
        if vlist.count == 0 then exit
        st = chckClip vlist[vlist.count] vlist[1] w2b i
        if st[1] == 0 then (
            append vtmp vlist[vlist.count]
        ) else if st[1] == 2 then (
          append vtmp vlist[vlist.count]
          append vtmp (innerpoint vlist[vlist.count] vlist[1] st[2])
        ) else if st[1] == 1 then (
          append vtmp (innerpoint vlist[vlist.count] vlist[1] st[2])
        )
        vlist = vtmp
      )
    ),

    fn selectcrossface = (
       searchLength = sqrt(maxFaceRadius^2+brushsize^2) * 1.05
      sanim.length = searchLength 
      sanim.height = searchLength 
      sanim.width = searchLength
      centerpivot sanim  
      sanim.transform = brushtransform
      selfaces = getFaceSelection theObj
      return selfaces
    ),
    
    fn crosspoint2D p1 p2 p3 p4 = (
      a = p2.y - p1.y
      b = p1.x - p2.x
      c = p4.y - p3.y
      d = p3.x - p4.x
      e = p1.x * p2.y - p2.x * p1.y
      f =  p3.x * p4.y - p4.x * p3.y
      g = a*d - b*c
      if g^2 < 0.0000001 then return p2

      x = (d * e - b * f) / g
      y = (-c * e + a * f) / g

      return [x,y,0]
    ),

    fn is_unce v1 v2 obj tch useEdges = (
      faces1 = meshop.getMapFacesUsingMapVert obj tch #{v1}
      faces2 = meshop.getMapFacesUsingMapVert obj tch #{v2}
      if (faces1 * faces2).numberSet == 1 then (
        if useEdges[v1]==undefined  then (useEdges[v1] = #(v2)) else (append useEdges[v1] v2)
        if useEdges[v2]==undefined  then (useEdges[v2] = #(v1)) else (append useEdges[v2] v1)
        return true
      )
      return false
    ),
    
    fn get_offpoints = (
      offpoint = #()
      borders = #()
      useEdges = #()

      islands = #()
      select theObj
      muw = theObj.modifiers[#unwrap_uvw]
      max modify mode
      cmod = modPanel.getCurrentObject()
      modPanel.setCurrentObject muw
      muw.setTVSubObjectMode 3
      n = muw.numberPolygons()

      allpolys = #{1..n}
      do (
      sseed = (allpolys as array)[1]
      muw.selectFaces #{sseed}
      a = muw.getSelectedFaces()
      do (
        b = a
        muw.expandSelection() 
        a = muw.getSelectedFaces()
      ) while not (a-b).isempty
      append islands (a as array)
      allpolys -= a
      ) while not allpolys.isempty
      muw.selectFaces #{}
      modPanel.setCurrentObject  cmod
      theMesh = snapshotAsMesh theObj
      theChannel = 1
      edges = #{}
      --t2v = #()
      for island in islands do (
        for faceIndex in island do(
          texFace = (meshop.getMapFace theMesh theChannel faceIndex)
          
          --for i = 1 to 3 do t2v[texFace[i]] = (muw.getVertexIndexFromFace faceIndex i)
          border = #{}
          if is_unce texFace[1] texFace[2] theObj theChannel useEdges then (
            edges += #{texFace[1],texFace[2]}
            border[1] = true
          )
          if is_unce texFace[2] texFace[3] theObj theChannel useEdges then (
            edges += #{texFace[2],texFace[3]}
            border[2] = true
          )
          if is_unce texFace[3] texFace[1] theObj theChannel useEdges then (
            edges += #{texFace[3],texFace[1]}
            border[3] = true
          )
          borders[faceIndex] = border
        )
      )
      loopEdges = #()
      edgeVerts = edges as array
      for i = 1 to edgeVerts.count do (
        v1 = edgeVerts[i]
        if edges[v1] then (
          loopEdge = #(v1)
          edges[v1] = false
          nfind = true
          do (
            v2 = useEdges[v1][1]
            if edges[v2] then (
              append loopEdge v2
              edges[v2] = false
            ) else (
              v2 = useEdges[v1][2]
              if edges[v2] then (
                append loopEdge v2
                edges[v2] = false
              ) else (nfind = false)
            )
            v1 = v2
          ) while nfind 
          append loopEdges loopEdge
        )
      )

      for loopEdge in loopEdges do (
        tmp = #(#())
        av = [0,0,0]
        zv = bv = meshop.getMapVert theobj theChannel loopEdge[1] - meshop.getMapVert theobj theChannel loopEdge[loopEdge.count]
        for i=1 to (loopEdge.count-1) do (
          v = meshop.getMapVert theobj theChannel loopEdge[i+1] - meshop.getMapVert theobj theChannel loopEdge[i]
          av += cross v bv
          bv = v
        )
        av += cross zv bv
        if av[3] >= 0 then mR = (rotateYPRMatrix 0 0 90) else mR = (rotateYPRMatrix 0 0 -90)
        for i = 1 to (loopEdge.count-1) do (
          v1 = meshop.getMapVert theobj theChannel loopEdge[i]
          v2 = meshop.getMapVert theobj theChannel loopEdge[i+1]
          nvec = normalize ((v2 - v1) * mR) *overpaint
          append tmp #(v1+nvec , v2+nvec)
        )
        v1 = meshop.getMapVert theobj theChannel loopEdge[loopEdge.count]
        v2 = meshop.getMapVert theobj theChannel loopEdge[1]
        nvec = normalize ((v2 - v1) * mR) *overpaint
        append tmp #(v1+nvec , v2+nvec)
        tmp[1] = #(v1+nvec , v2+nvec)
        for i = 1 to (tmp.count-1) do (
          offpoint[loopEdge[i]] = (crosspoint2D tmp[i][1] tmp[i][2] tmp[i+1][1] tmp[i+1][2])
        )
      )
     ),

    fn crossFaceMaps theMesh theChannel mt2b =
    (
      invBrushTransform = inverse( brushtransform)
      crossfaces = selectcrossface()
      maps = #()
      bareas = #()

      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
        mw2b = (inverse mg2w) * mg2b
        mb2w = inverse mw2b
        mt2w = (inverse mg2t) * mg2w
        
        for i = 1 to 3 do (
          if borders[faceIndex][i] then (
            j = i + 1
            if j == 4 then j = 1
            barea = #()
            append barea vlist[i]
            append barea vlist[j]
            offpoint[texFace[j]][3] = 1.0
            append barea (offpoint[texFace[j]] * mt2w)
            offpoint[texFace[i]][3] = 1.0
            append barea (offpoint[texFace[i]] * mt2w)
            

            clipface &barea invBrushTransform 

            if barea.count != 0 then (
              bmaplist =  #()
              for v in barea do (
                append bmaplist (v * mw2b)
              )
              append bareas #(bmaplist,mb2w)
            )
          )
        )
        
        clipface &vlist invBrushTransform 

        if vlist.count != 0 then (
          maplist =  #()

          for v in vlist do (
            mp = v * mw2b
            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 paintPixel bm x y dx dy cl = (
      for i = 0 to overpaint-1 do (
        setPixels bm [x+dx*i,y+dy*i] cl
      )
    ),
    
    fn inoutMesh p = ( 
      pin = false
      for i = 1 to maps.count while not pin do (
        v = #()
        n = maps[i][1].count
        for j = 1 to n do (
          append v ( maps[i][1][j] - p )
        )
        c = (cross v[n] v[1])[3]
        if c == 0.0 then (
          pin = true 
        ) else (
          if c < 0.0 then dr = -1 else dr = 1
          pout = false
          for j = 1 to (n-1) while not pin do (
            c = (cross v[j] v[j+1])[3]
            if c == 0.0 then (
              pin = true
            )
            if c < 0.0 then d = -1 else d = 1
            if dr * d < 0 then (
              pout = true
            )
          )
          if not pout then pin = true
        )
      )
      return pin
    ),
    
    fn pcol px py mb2w ovr = (
      case BrushShape of (
        1: (
          gr = 0.0
          if ovr then (
            p = [px,py,1.0] * mb2w
            if distance p brushtransform.pos <= BrushSize/2 then gr = 1.0
          ) else (
            p1 = [px-0.25,py-0.25,1.0] * mb2w
            p2 = [px-0.25,py+0.25,1.0] * mb2w
            p3 = [px+0.25,py-0.25,1.0] * mb2w
            p4 = [px+0.25,py+0.25,1.0] * mb2w
            if distance p1 brushtransform.pos <= BrushSize/2 then gr += 0.25
            if distance p2 brushtransform.pos <= BrushSize/2 then gr += 0.25
            if distance p3 brushtransform.pos <= BrushSize/2 then gr += 0.25
            if distance p4 brushtransform.pos <= BrushSize/2 then gr += 0.25
          )
          if gr > 0.0 then
          (
            bcol = (getPixels theBitmap [px,py] 1)[1]
            return ((BrushColor * gr) + (bcol * (1.0 - gr)))
          ) else (
            return undefined
          )
        )
        2: (
          gr = 0.0
          if ovr then (
            return BrushColor
          ) else (
            p1 = [px-0.25,py-0.25,0]
            p2 = [px-0.25,py+0.25,0]
            p3 = [px+0.25,py-0.25,0]
            p4 = [px+0.25,py+0.25,0]
            if  inoutMesh p1 then gr += 0.25
            if  inoutMesh p2 then gr += 0.25
            if  inoutMesh p3 then gr += 0.25
            if  inoutMesh p4 then gr += 0.25
            bcol = (getPixels theBitmap [px,py] 1)[1]
            return ((BrushColor * gr) + (bcol * (1.0 - gr)))
          )
        )
        3: (
          p = [px,py,1.0] * mb2w
          bcol = (getPixels theBitmap [px,py] 1)[1]
          theFactor = (distance p brushtransform.pos) / (BrushSize / 2.0)
          if theFactor <= 1.0 then (
            theFactor = sin ( 90.0 * theFactor)
            return ((bcol * theFactor) + (BrushColor * (1.0 - theFactor))) 
          ) else (
            return undefined
          )
        )
      )
    ),

    fn is_in px py = (
      x = px - bitmapX/2
      y = bitmapY/2 - py
      dstx = toX.value
      dsty = toY.value
      if dstx == 0.0 then (
        if x<0.0 then  false else true 
      ) else (
        if (y > dsty/dstx * x) then  false else true 
      )
    ),    

    fn drawline x1 x2 y mb2w = (
      if y<1 then y += bitmapY
      if y> bitmapY then y -= bitmapY
      for x = x1 to x2 do (
        if not checkBitmap [x+y*bitmapX] do(
          pcolor = pcol x y mb2w true
          if pcolor != undefined then (
            setPixels theBitmap  [x,y] #(pcolor)
            checkBitmap [x+y*bitmapX] = true
          )
        )
      )
    ),
    
    fn delty v1 v2 = (
      dy = v2.y - v1.y
      if dy == 0 then 0
      else if dy > 0 then 1
      else -1
    )
    ,
    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 = #()
      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 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
           (
             s=0
             while iy > (floor(side[s2][side2ptr - 1][2])) do (
               side2ptr -= 1
               s +=1
               if s > 100 then exit
             )
             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
             if ix1 < ix2 then drawline ix1 ix2 iy mb2w else drawline ix2 ix1 iy mb2w
           )
         )
      )
    ),

    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 = 3
      --sanim = vmod.gizmo
      sanim = box()
      vmod.node = sanim
      mt2b=(matrix3 [bitmapX,0,0] [0,-bitmapY,0] [0,bitmapY,1] [0,0,0])
      

      if theObj.modifiers[#Unwrap_UVW] == undefined then (
        addModifier theObj (Unwrap_UVW ())
        cmuw = true
        muw = theObj.modifiers[#Unwrap_UVW]
        modPanel.setCurrentObject theObj.modifiers[#Unwrap_UVW]
      )
      else  modPanel.setCurrentObject theObj.modifiers[#Vol__Select]
      get_offpoints()
    ),
    fn doPaint = (
      local theMesh = snapshotAsMesh theObj
      local theChannel = 1
      maps = #()
      crossFaceMaps  theMesh theChannel mt2b
      checkBitmap = #{}

      for map in maps do (
        if map[1].count >2 then paintFace map[1] map[2]
      )

      for map in bareas do (
        if map[1].count >2 then paintFace map[1] map[2]
      )
    ),
    fn redraw = (
      theObj.material.diffusemap.bitmap = theBitmap
    ),
    fn saveimage = (
      save theBitmap
      theObj.material.diffusemap.bitmap = theBitmap
    ),
    fn close = (
      if cmuw then (
        deleteModifier theObj muw
      )
      delete sanim
      delmodifier theObj Vol__Select
      delmodifier theObj Turn_to_Mesh
    )
)

(
  ParticlePaint_Rollout = undefined
  pt = objectPaint()
  pf = undefined

  fn lerp t1 t2 w = (
    q1 = t1 as quat
    q2 = t2 as quat
    p1 = t1.pos
    p2 = t2.pos
    q = slerp q1 q2 w
    p = ((p2-p1)*w+p1)
    tr = q as matrix3
    tr[4] = p
    return tr
  )

  fn write_bitmap frame = (
    sf = "00" + (frame as string)
    temp_bitmap_filename = (getDir #preview +"/test"+ substring sf (sf.count - 2) (sf.count)  +".tga")
    pt.theBitmap.filename = temp_bitmap_filename
    pt.saveimage()
  )

  fn stroke tmp_file startframe stopframe write_by = (
    particleTMs = #()
    particleScls = #()
    pt.theBitmap = bitmap pt.bitmapX pt.bitmapY color:ParticlePaint_Rollout.blankColor.color
    LTM = matrix3 1
    frame = 0
    while ((not (eof tmp_file)) and (frame < stopframe)) do 
    (
      frame = readvalue tmp_file
      count = readvalue tmp_file
      sliderTime = frame
      FTM = LTM * pt.theObj.transform
      for i =  1 to count do
      (
        id = readvalue tmp_file
        tm = readvalue tmp_file
        scl = readvalue tmp_file

        if particleTMs[id] == undefined then (
          particleTMs[id] = tm
          particleScls[id] = scl
        ) else (          
          t1 = particleTMs[id] * FTM
          t2 = tm
          s1 = particleScls[id]
          s2 = scl
          d = distance t1.pos t2.pos
          if ParticlePaint_Rollout.BrushSizeRef.state == 2 then (
            div = d/((s1+s2) / 2.0 * (1.0 - ParticlePaint_Rollout.BrushOverlap.value))-1
          ) else (
            div = d/(pt.brushsize *  (1.0 - ParticlePaint_Rollout.BrushOverlap.value))-1
          )
          dcount = (div as integer) 
          if dcount < 0 then dcount = 0
          for j = 0 to dcount do (
            if div ==0.0 then w = 0.0 else w = j / div
            pt.brushtransform = lerp t1 t2 w
            if ParticlePaint_Rollout.BrushSizeRef.state == 2 then (
              pt.brushsize = s1 * (1 - w) + s2 * w
            )
            pt.doPaint()
          )
          particleTMs[id] = tm
          particleScls[id] = scl
        )
      )
      LTM = inverse pt.theObj.transform
      if write_by == #frame do write_bitmap frame
    )
    if write_by == #stroke do write_bitmap frame
  )

  fn myseek fp dest= (
    seek fp 0
    seek fp dest
  )

  fn run = (
    pt.BrushShape = ParticlePaint_Rollout.BrushShape.state
    pt.brushsize = ParticlePaint_Rollout.BrushSize.value
    pt.BrushColor = ParticlePaint_Rollout.inkColor.color 
    pt.init()
    pstart = ParticlePaint_Rollout.StartFrame.value
    pstop =ParticlePaint_Rollout.StopFrame.value

    frames =#()

    filename = (getDir #temp +"/particlePaint_temp.txt")
    tmp_file = createfile filename
    for i = pstart to pstop do (
      sliderTime = i
      count = pf.NumParticles()
      frames[i+1] = filePos tmp_file  
      format "%,%\n" i count to:tmp_file
      for j = 1 to count do (
        pf.particleIndex = j
        id = pf.particleID 
        tm = pf.particleTM
        scl = pf.particleScale
        format "%,%,%\n" id tm scl to:tmp_file
      )
    )
    close tmp_file

    tmp_file = openFile filename
    
    eser = showEndResult
    showEndResult = false


    if ParticlePaint_Rollout.StorokeType.state == 2 then (
      stl = ParticlePaint_Rollout.FalloffFrame.value
      for cf = pstart to pstop do (
        sf = cf - stl
        if sf < pstart do sf = pstart
        myseek tmp_file (frames[sf+1])
        stroke tmp_file sf cf #stroke
      )
    )
    else (
      stroke tmp_file pstart pstop #frame
    )

    modPanel.setCurrentObject pt.theObj.modifiers[1]
    showEndResult = eser

    pt.close()
    close tmp_file
  )

  fn edgelength e obj =
  (
    verts = (meshop.getVertsUsingEdge obj e) as array
    v1 = meshop.getvert obj verts[1]
    v2 = meshop.getvert obj verts[2]
    d = distance v1 V2
  )

  fn getMaxFaceRadius = (
    --global ParticlePaint_Rollout
    theMesh = snapshotAsMesh pt.theObj
    maxlength = 0.0
    edgecount = theMesh.edges.count
    for i = 1 to edgecount do (
      l = edgelength i theMesh
      if l > maxlength then  maxlength = l
    )
    br = ParticlePaint_Rollout.BrushSize.value
    pt.maxFaceRadius = sqrt((maxlength^2+3*br^2)/3)
  )
  dialogWidth = 200
  dialogHeight =550
  
  --global ParticlePaint_Rollout
  try(destroyDialog ParticlePaint_Rollout)catch()
  
  fn BitmapSaveAs = (
    theSaveName = getSaveFileName types:"BMP (*.bmp)|*.bmp|Targa (*.tga)|*.tga|JPEG (*.jpg)|*.jpg"
    if theSaveName != undefined do
    (
      ParticlePaint_Rollout.BitmapFiles.caption = theSaveName
    )
  )
  
  rcMenu PaintMenu
  (
    -- ここにメニューの内容を定義
    subMenu"File"
    (
      menuItem SaveAs "Save As..."
      menuItem quit_tool "Quit"  
    )

    subMenu"Help"
    (
      menuItem about_tool "About ParticlePaint..." 
    )
    
    on about_tool picked do messagebox "Particle Paint " title:"About..."
    on quit_tool picked do destroyDialog ParticlePaint_Rollout
    on SaveAs picked do (
      print "pick"
      BitmapSaveAs()
    )
  )
  
  fn mesh_filter obj = superclassof obj == GeometryClass and classof obj != TargetObject and obj != PF_Source
  fn pfs_filter obj = classof obj == PF_Source

  rollout ParticlePaint_Rollout "Partilce Paint"
  (
    pickbutton pickMesh "Pick Mesh"  height:30 filter:mesh_filter autodisplay:true
    pickbutton pickPFS "Pick PFSource"  height:30 filter:pfs_filter autodisplay:true
    colorpicker inkColor "BrushColor" height:16 modal:false color:black 
    colorpicker blankColor "BlankColor" height:16 modal:false color:white 
    spinner StartFrame "Start Frame"  type:#integer
    spinner StopFrame "Stop Frame" type:#integer
    radiobuttons StorokeType "Stroke Type" labels:#("constant", "Falloff")
    radiobuttons BrushSizeRef "Brush Size Reference" labels:#("Brush Size","Particle Size")
    spinner BrushSize "Brush Size" type:#integer
    spinner FalloffFrame "Falloff Frame" type:#integer
    
    spinner BrushOverlap "Brush Overlap" type:#float range:[0.0,0.99,0.7]
    
    radiobuttons BrushShape "Brush Shape" labels:#("Circle","Box","Circle Smooth")
    button BitmapFiles "Bitmap Files" width:150 height:16
    button btnMaxFaceRadius  "Get Max Face Radius" width:100 height:30
    spinner spnMaxFaceRadius "Max Face Radius"  type:#float
    spinner spnbitmapX "bitmapX"  type:#integer range:[0,4096,512]
    spinner spnbitmapY "bitmapY"  type:#integer range:[0,4096,512]
    button Painting  "Paint" width:100 height:30
    on ParticlePaint_Rollout open do (
      StartFrame.value = animationRange.start
      StopFrame.value = animationRange.end
      BrushSize.value = 5
      FalloffFrame.value = 5
      FalloffFrame.enabled = false
      btnMaxFaceRadius.enabled = false
      BitmapFiles.caption = (getDir #preview +"/test000.tga")
      Painting.enabled = false
      spnMaxFaceRadius.value = pt.maxFaceRadius
      spnbitmapX.value = pt.bitmapX
      spnbitmapY.value = pt.bitmapY
    )

    on BitmapFiles pressed do (
      BitmapSaveAs()
    )
    on pickMesh picked obj do (
      if pickPFS.object != undefined  then Painting.enabled = true
      btnMaxFaceRadius.enabled = true
      pt.theObj = obj

    )
    on pickPFS picked obj do (
      if pickMesh.object != undefined then Painting.enabled = true
      pf = obj
    )
    
    on StorokeType changed btn do (
      if btn == 1 then FalloffFrame.enabled = false else FalloffFrame.enabled = true
    )

    on Painting pressed do (
      run()
    )
    on btnMaxFaceRadius pressed do (
      getMaxFaceRadius()
      spnMaxFaceRadius.value = pt.maxFaceRadius
    )
    on spnbitmapX changed val do (
      pt.bitmapX = val
    )
    on spnbitmapY changed val do (
      pt.bitmapY = val
    )
  )
  createDialog ParticlePaint_Rollout dialogWidth dialogHeight menu:PaintMenu
)

これで実験用の球体にパーティクルを落すシーンに対して試してみた。

fig 1

モディファイヤスタックはこんな感じ。今のところメッシュオブジェクトのメソッドを使っているからポリゴンに対して処理するにはメッシュに変換モディファイヤが必要になるかな。

fig 2

13〜14フレームの間で処理してみると、

fig 3

このようにUV境界の隙間が埋まっているのが確認出来る。

fig 4

これがUVマップとビットマップで、

fig 5

はみ出しだけじゃなくて不連続UVの反対側のペイントも出て来るのでなんか不思議な感じになっちゃってるけど、こうなってる方が境界で隙間が発生しない筈だ。

fig 6

続きはまた次回。

maxまとめページ



take_z_ultima at 11:30│Comments(0)3ds Max | CG

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 

Archives