mieki256's diary



2017/12/18(月) [n年前の日記]

#1 [love2d] love2dのShaderを使って某STGのアレ

昔、 _DXRubyを使って床ラスタースクロール っぽいことを _以前試した わけだけど。コレを love2d の Shader を使ってもできないかと実験。環境は Windows10 x64 + love2d 0.10.2。

こんな感じに。

shader_test08_raster2_ss_01.gif

一応それっぽくできた、のかな。どうなんだ。

画像とソース。 :

使った画像は以下。

_cloud_1024x1024.png

ソースは以下。

_conf.lua
function love.conf(t)
  t.window.title = "Shader test 08 raster 2"
  t.window.vsync = true
  t.window.resizable = true
  t.window.width = 640
  t.window.height = 480
  -- t.window.fullscreen = true
  -- t.window.fullscreentype = "exclusive"
end

_main.lua
-- Shader test 08 raster 2

function love.load()
  love.graphics.setDefaultFilter("nearest", "nearest")
  scr_w, scr_h = 640, 480
  canvas = love.graphics.newCanvas(scr_w, scr_h)

  img = love.graphics.newImage("cloud_1024x1024.png")
  -- img = love.graphics.newImage("scifi_bg_640x640.png")
  -- img = love.graphics.newImage("scifi_bg_640x640_blur.png")

  -- make shader
  local shadercode = [[
    extern number screen_distance;
    extern number floor_distance;
    extern number scroll_x;
    extern number scroll_y;
    extern number scroll_z;
    extern number upper_z_dir;

    const number z_limit = 6.0;

    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ) {
      float sx = screen_coords.x / love_ScreenSize.x - 0.5;
      float sy = screen_coords.y / love_ScreenSize.y - 0.5 - scroll_y;
      // float sx = texture_coords.x - 0.5;
      // float sy = texture_coords.y - 0.5 - scroll_y;

      float zv = (sy < 0.0)? upper_z_dir : 1.0;
      sy = abs(sy);
      // sy = max(sy, 0.0);

      float pz = (screen_distance * floor_distance) / sy;
      float px = sx * pz / screen_distance;
      texture_coords.x = mod(px + scroll_x, 1.0);
      texture_coords.y = mod(pz + scroll_z * zv, 1.0);
      vec4 texcolor = Texel(texture, texture_coords);
      texcolor.a *= (1.0 - step(z_limit, pz));
      return texcolor * color;
    }
  ]]
  myshader = love.graphics.newShader(shadercode)
  myshader:send("screen_distance", 0.7)
  myshader:send("floor_distance", 0.3)
  myshader:send("scroll_x", 0.0)
  myshader:send("scroll_y", 0.0)
  myshader:send("scroll_z", 0.0)
  myshader:send("upper_z_dir", 1.0)  -- upper half of the screen in z direction. 1.0 or -1.0

  v = 0.0
  px = (scr_w - img:getWidth()) / 2
  py = (scr_h - img:getHeight()) / 2
end

function love.update(dt)
  v = v + dt
  myshader:send("scroll_x", v * 1.2)
  myshader:send("scroll_z", v * -0.4)
end

function love.draw()
  love.graphics.setCanvas(canvas)
  love.graphics.clear(0, 0, 0, 255)

  love.graphics.setColor(255, 255, 255)
  love.graphics.setShader(myshader)
  love.graphics.draw(img, px, py)
  love.graphics.setShader()

  love.graphics.setCanvas()

  -- draw canvas to window
  wdw_w, wdw_h = love.graphics.getDimensions()
  scr_scale = math.min((wdw_w / scr_w), (wdw_h / scr_h))
  scr_ox = (wdw_w - (scr_w * scr_scale)) / 2
  scr_oy = (wdw_h - (scr_h * scr_scale)) / 2
  love.graphics.setColor(255, 255, 255)
  love.graphics.draw(canvas, scr_ox, scr_oy, 0, scr_scale, scr_scale)

  love.graphics.print("FPS: "..tostring(love.timer.getFPS()), 10, 10)
end

function love.keypressed(key, isrepeat)
  if key == "escape" then
    -- ESC to exit
    love.event.quit()
  elseif key == "f11" then
    -- toggle fullscreen
    if love.window.getFullscreen() then
      love.window.setFullscreen(false)
    else
      love.window.setFullscreen(true)
    end
  end
end

画像もソースも、License: CC0 / Public Domain ってことで。

実行の仕方は、画像ファイル、conf.lua、main.lua を1つのフォルダに入れて、「love フォルダ名」でOK。

問題点。 :

上記のような、 _ぼんやりした感じの雲模様テクスチャ を表示する分にはイイ感じに見えるのだけど。テクスチャによっては酷い結果になることに気付いてしまった。

例えば、 _境界がハッキリしたメカっぽいテクスチャ などを表示すると、画質がガビガビになってしまう。

shader_test08_raster2_ss_02.gif

このGIFアニメのフレームレートは低いから、これだとガビガビに見えないかもしれないけれど、60FPSで動いてる様子を眺めてみれば「なんじゃこりゃああ!!」って感じの酷い見た目になる。

何故かというと、Z軸方向の値に応じてテクスチャからピクセルを拾ってくる際、元のテクスチャから飛び飛びでピクセルを拾ってきてしまうので、線だの何だのがちゃんと繋がってない状態で描画されてガビガビになるという。

解決策・回避策としては…。例えば、Z軸方向 ―― テクスチャで言えばy方向にのみ、 _事前にぼかしをかけておく という手があるかなと。 *1 各ピクセルが滑らかに変化していれば、飛び飛びでピクセル値を拾ってきても結果はそれほど破綻しないはず、みたいな。

shader_test08_raster2_ss_03.gif

こうすれば、多少は見た目がマシになる。もちろん、ぼかしをかけてあるから全体的にぼやけた印象になるけれど、それでもガビガビよりはマシだろうと…。

もしかすると、love2d の Shader側・GLSL側でテクスチャにぼかしをかけつつ利用、てな処理だってできるかもしれない。面倒臭いから今回はそこまでやってないけど…。

テクスチャ画像読み込みの直後に img:setFilter("linear", "linear") を呼んで、テクスチャに使うフィルタを設定したら改善するかと思ったけれど、今回の例ではあまり効果は感じられなかった。

_FilterMode (日本語) - LOVE
_Texture:setFilter (日本語) - LOVE

*1: 今回は GIMP の、フィルター → ぼかし → _タイル化可能ぼかし を使って、垂直方向のみにチェックを入れてぼかしてみた。

以上、1 日分です。

過去ログ表示

Prev - 2017/12 -
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
31

カテゴリで表示

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


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

Powered by hns-2.19.6, HyperNikkiSystem Project