2017/12/18(月) [n年前の日記]
#1 [love2d] love2dのShaderを使って某STGのアレ
昔、
_DXRubyを使って床ラスタースクロール
っぽいことを
_以前試した
わけだけど。コレを love2d の Shader を使ってもできないかと実験。環境は Windows10 x64 + love2d 0.10.2。
こんな感じに。
一応それっぽくできた、のかな。どうなんだ。
こんな感じに。
一応それっぽくできた、のかな。どうなんだ。
◎ 画像とソース。 :
使った画像は以下。
_cloud_1024x1024.png
ソースは以下。
_conf.lua
_main.lua
画像もソースも、License: CC0 / Public Domain ってことで。
実行の仕方は、画像ファイル、conf.lua、main.lua を1つのフォルダに入れて、「love フォルダ名」でOK。
_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。
◎ 問題点。 :
上記のような、
_ぼんやりした感じの雲模様テクスチャ
を表示する分にはイイ感じに見えるのだけど。テクスチャによっては酷い結果になることに気付いてしまった。
例えば、 _境界がハッキリしたメカっぽいテクスチャ などを表示すると、画質がガビガビになってしまう。
このGIFアニメのフレームレートは低いから、これだとガビガビに見えないかもしれないけれど、60FPSで動いてる様子を眺めてみれば「なんじゃこりゃああ!!」って感じの酷い見た目になる。
何故かというと、Z軸方向の値に応じてテクスチャからピクセルを拾ってくる際、元のテクスチャから飛び飛びでピクセルを拾ってきてしまうので、線だの何だのがちゃんと繋がってない状態で描画されてガビガビになるという。
解決策・回避策としては…。例えば、Z軸方向 ―― テクスチャで言えばy方向にのみ、 _事前にぼかしをかけておく という手があるかなと。 *1 各ピクセルが滑らかに変化していれば、飛び飛びでピクセル値を拾ってきても結果はそれほど破綻しないはず、みたいな。
こうすれば、多少は見た目がマシになる。もちろん、ぼかしをかけてあるから全体的にぼやけた印象になるけれど、それでもガビガビよりはマシだろうと…。
もしかすると、love2d の Shader側・GLSL側でテクスチャにぼかしをかけつつ利用、てな処理だってできるかもしれない。面倒臭いから今回はそこまでやってないけど…。
テクスチャ画像読み込みの直後に img:setFilter("linear", "linear") を呼んで、テクスチャに使うフィルタを設定したら改善するかと思ったけれど、今回の例ではあまり効果は感じられなかった。
_FilterMode (日本語) - LOVE
_Texture:setFilter (日本語) - LOVE
例えば、 _境界がハッキリしたメカっぽいテクスチャ などを表示すると、画質がガビガビになってしまう。
このGIFアニメのフレームレートは低いから、これだとガビガビに見えないかもしれないけれど、60FPSで動いてる様子を眺めてみれば「なんじゃこりゃああ!!」って感じの酷い見た目になる。
何故かというと、Z軸方向の値に応じてテクスチャからピクセルを拾ってくる際、元のテクスチャから飛び飛びでピクセルを拾ってきてしまうので、線だの何だのがちゃんと繋がってない状態で描画されてガビガビになるという。
解決策・回避策としては…。例えば、Z軸方向 ―― テクスチャで言えばy方向にのみ、 _事前にぼかしをかけておく という手があるかなと。 *1 各ピクセルが滑らかに変化していれば、飛び飛びでピクセル値を拾ってきても結果はそれほど破綻しないはず、みたいな。
こうすれば、多少は見た目がマシになる。もちろん、ぼかしをかけてあるから全体的にぼやけた印象になるけれど、それでもガビガビよりはマシだろうと…。
もしかすると、love2d の Shader側・GLSL側でテクスチャにぼかしをかけつつ利用、てな処理だってできるかもしれない。面倒臭いから今回はそこまでやってないけど…。
テクスチャ画像読み込みの直後に img:setFilter("linear", "linear") を呼んで、テクスチャに使うフィルタを設定したら改善するかと思ったけれど、今回の例ではあまり効果は感じられなかった。
_FilterMode (日本語) - LOVE
_Texture:setFilter (日本語) - LOVE
[ ツッコむ ]
以上、1 日分です。