mieki256's diary



2021/09/18() [n年前の日記]

#2 [love2d] love2dでテクスチャ付きポリゴンを歪めずに描画したい

love2d 11.3 上で、テクスチャ付きポリゴンを描画したい。

Mesh を使えば描画できることは分った。ただ、そのまま描画すると、四角形等を描画した際に見た目がめっちゃ歪んでしまう。

_love2dでテクスチャ付きポリゴンを描画したい

解決策は無いものか。

とりあえず、四角形を細かく分割して描画すれば、見た目ではさほど歪みが気にならなくなるのではないか…と思ったので試してみた。

ソースと使用画像。 :

ソースと使用画像は以下。

_conf.lua
function love.conf(t)
  t.window.title = "Love2d Mesh divide"
  t.window.width = 640
  t.window.height = 480
  t.window.vsync = true
  t.modules.joystick = false
  -- t.window.fullscreen = true
  -- t.window.fullscreentype = "exclusive"
end

_main.lua
-- Love2d Mesh

function makeVertices(src, xc, yc)
  xyuv = {}
  local xi, yi, u, v
  local yi = 0
  for yi = 0, yc do
    v = yi / yc
    local sx0 = (src[4][1] - src[1][1]) * v + src[1][1]
    local sy0 = (src[4][2] - src[1][2]) * v + src[1][2]
    local sx1 = (src[3][1] - src[2][1]) * v + src[2][1]
    local sy1 = (src[3][2] - src[2][2]) * v + src[2][2]
    for xi = 0, xc do
      u = xi / xc
      local x = (sx1 - sx0) * u + sx0
      local y = (sy1 - sy0) * u + sy0
      table.insert(xyuv, {x, y, u, v})
    end
  end

  vidx = {}
  for y = 1, yc do
    for x = 1, xc do
      local i0 = x + ((xc + 1) * (y - 1))
      local i1 = i0 + 1
      local i2 = i0 + (xc + 1)
      local i3 = i2 + 1
      table.insert(vidx, i0)
      table.insert(vidx, i1)
      table.insert(vidx, i2)

      table.insert(vidx, i2)
      table.insert(vidx, i1)
      table.insert(vidx, i3)
    end
  end

  vt = {}
  for j = 1, #vidx do
    local i = vidx[j]
    local x, y, u, v
    x, y = xyuv[i][1], xyuv[i][2]
    u, v = xyuv[i][3], xyuv[i][4]
    table.insert(vt, {x, y, u, v, 1.0, 1.0, 1.0, 1.0})
  end

  return vt, xyuv
end

-- init
function love.load()
  -- get window width and height
  wdw_w, wdw_h = love.graphics.getDimensions()

  img = love.graphics.newImage("uvcheckermap01-512.png")

  divide = 3

  -- src = { {270, 40}, {370, 40}, {620, 440}, {20, 440} }
  -- src = { {270, 20}, {370, 60}, {620, 350}, {20, 440} }
  src = { {270, 240}, {370, 240}, {630, 460}, {10, 460} }

  vert, xyuv = makeVertices(src, divide, divide)

  mesh = love.graphics.newMesh(vert, "triangles")
  mesh:setTexture(img)

  guide = true
  mesh_refresh = false

  ang = 0
end

-- update
function love.update(dt)
  if mesh_refresh then
    vert, xyuv = makeVertices(src, divide, divide)
    mesh = love.graphics.newMesh(vert, "triangles")
    mesh:setTexture(img)
  end

  ang = ang + 90 * dt
  local d = 140 * math.sin(math.rad(ang))

  -- change x0, x1
  src[1][1] = (wdw_w / 2) - 150 + d
  src[2][1] = (wdw_w / 2) + 150 - d

  vert, xyuv = makeVertices(src, divide, divide)
  mesh:setVertices(vert, 1)
end

-- draw
function love.draw()
  -- fill BG color
  love.graphics.setColor(0.1, 0.2, 0.4)
  love.graphics.rectangle("fill", 0, 0, wdw_w, wdw_h)

  -- draw mesh
  love.graphics.setColor(1, 1, 1)
  love.graphics.draw(mesh, 0, 0)

  if guide then
    -- draw lines
    love.graphics.setColor(1, 1, 1, 0.5)
    for i=1, #vert, 3 do
      local vlst = {vert[i][1], vert[i][2], vert[i+1][1], vert[i+1][2], vert[i+2][1], vert[i+2][2]}
      love.graphics.polygon("line", vlst)
    end

    --draw points
    love.graphics.setColor(0, 1, 1, 0.5)
    for i = 1, #xyuv do
      local x = xyuv[i][1]
      local y = xyuv[i][2]
      love.graphics.ellipse("line", x, y, 3, 3)
    end
  end

  -- print FPS
  love.graphics.setColor(1, 1, 1)
  love.graphics.print("FPS: "..tostring(love.timer.getFPS()), 2, 2)
  love.graphics.print("Divide: "..tostring(divide), 2, 20)
  love.graphics.print("G key : Guide on/off", 2, 40)
  love.graphics.print("Up, Down : Divide +/-", 2, 60)
end

function love.keypressed(key, isrepeat)
  -- ESC to exit
  if key == "escape" then
    love.event.quit()
  end
  if key == "g" then
    guide = not guide
  end
  if key == "up" then
    if divide < 32 then
      divide = divide + 1
    end
    mesh_refresh = true
  end
  if key == "down" then
    if divide > 2 then
      divide = divide - 1
    end
    mesh_refresh = true
  end
end

使用画像は以下。

_uvcheckermap01-512.png

以下で公開されてる画像を利用させてもらいました。ありがたや。

_Arahnoid/UVChecker-map: A collection of free images what can be used during unwrapping of 3D models

実行結果。 :

実行すると、Gキーで分割状態表示のON/OFFが切り替えられる。また、カーソルキーの上下で、分割数を 2 - 32 まで変更できる。




一応、 _LoVE Web Builder を利用させてもらって、Webブラウザ上でも動かせるようにしてみた。

_06_mesh_divide_c

Windows10 x64 21H1 + Firefox 92.0 64bit、Google Chrome 93.0.4577.82 64bit では動いているけど、どうだろう。

ちなみに、CPU は Ryzen 7 1700 (8コア、16スレッド、3.0GHz)、GPU(ビデオカード)は GeForce GTX 1060 6GB で動作確認した。このスペックなら 60FPS で動いてるように見える。ただ、それはローカルで動かした場合の話で、Webブラウザ上で動かすと11x11分割あたりから60FPSでは間に合わなくなってくる…。

雑感。 :

4x4分割、もしくは、8x8分割ぐらいで、そこそこ歪みが気にならなくなった印象を受けた。16x16分割まで行けば、全然歪んでるようには見えない。まあ、描画面積も関係してくるのだろうけど…。今回、ウインドウサイズは 640x480 だけど、1280x720 や 1920x1080 なら歪みが感じられる可能性もありそう。

ただ、毎フレーム、四角形の頂点の描画位置が変わるとなると、分割のための再計算も毎フレーム必要になるわけで…。4x4分割なら25個の頂点を、8x8分割なら81個の頂点を再計算しないといけない。1〜2枚を処理するなら問題無いかもしれんけど、例えば何十枚も処理をしたらどうなるのかちょっと分からないなと。実際、前述したように、Webブラウザ上で動かしたら11x11分割あたりで処理落ちが始まった。

また、あくまで2D的に分割しているので、こういうソレを使って3D的な見せ方をしようとするなら、元テクスチャ自体に遠近感を盛り込む等の工夫が必要になるのかもしれない。

遠近感を意識した分割はできないのだろうか。やろうと思えばできるはず。ていうか、以前DXRubyを使ってやったことがあるし。

_DXRuby上で射影変換ができた
_DXRubyのShaderで射影変換

でも、使い道が…。そもそも 3Dっぽく見せたいなら Unity や Godot Engine を使ったほうが、という気分にもなるわけで。2Dゲームエンジンの love2d で無理してやらんでも、みたいな。

以上です。

過去ログ表示

Prev - 2021/09 - Next
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project