2017/12/19(火) [n年前の日記]
#1 [love2d] love2dのShaderで円柱っぽいBG描画を試したり
昔、
_DXRubyのShader機能で円柱だかパイプだかっぽいBG描画を試した
ことがあったのだけど。それを love2d でもやれないものかなと思えてきたので試したり。環境は Windows10 x64 + love2d 0.10.2。
こんな感じに。
何かビミョーにおかしいような気もするけど…。まあ、それっぽくなってるから、いいか…。でも、考え方、あるいは計算式が間違ってる可能性も否定できず。
こんな感じに。
何かビミョーにおかしいような気もするけど…。まあ、それっぽくなってるから、いいか…。でも、考え方、あるいは計算式が間違ってる可能性も否定できず。
◎ 画像とソース。 :
画像は以下。
_grid_bg_640x640.png
_scifi_bg_640x640.png
ソースは以下。
_conf.lua
_main.lua
画像もソースも、License : CC0 / Public Domain ってことで。
Shader部分の仕組みというか考え方は、 _DXRuby版 と同じなのでそちらを参照してもらえればと。
_grid_bg_640x640.png
_scifi_bg_640x640.png
ソースは以下。
_conf.lua
function love.conf(t) t.window.title = "Shader test 09 pipe" 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 09 pipe
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("grid_bg_640x640.png")
-- img = love.graphics.newImage("scifi_bg_640x640.png")
img:setFilter("linear", "linear")
-- make shader
local shadercode = [[
extern number scr_dist;
extern number r;
extern number angle_max;
extern number start_x;
extern number start_y;
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ) {
float sx = texture_coords.x - 0.5;
float sy = texture_coords.y - 0.5;
float pz = r * cos(atan(sy, scr_dist));
float u = sx * pz / scr_dist;
float v = atan(sy, scr_dist) / angle_max;
texture_coords.x = mod(u + 0.5 + start_x, 1.0);
texture_coords.y = mod(v + 0.5 + start_y, 1.0);
vec4 texcolor = Texel(texture, texture_coords);
return texcolor * color;
}
]]
myshader = love.graphics.newShader(shadercode)
local scr_dist = 0.6
myshader:send("scr_dist", scr_dist)
myshader:send("r", scr_dist + 0.3)
myshader:send("start_x", 0.0)
myshader:send("start_y", 0.0)
myshader:send("angle_max", math.atan2(0.5, scr_dist))
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("start_x", v * 0.2)
myshader:send("start_y", 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 ってことで。
Shader部分の仕組みというか考え方は、 _DXRuby版 と同じなのでそちらを参照してもらえればと。
◎ 余談。 :
HLSL にはatan2() があるけれど GLSL には atan2() が無くてどうしようと思ったら、GLSL の場合、atan() が atan2() 相当らしくて。
_GLSLをHLSLに書き換える - Qiita
が参考になりました。ありがたや。ちなみに、件のページには atan(x,y) と書いてあるけど、たぶん atan(y,x) ではあるまいか。
今回、利用するテクスチャに linearフィルタを設定したら、見た目がちょっとマシになったように感じたり。処理内容によっては、その手のフィルタ設定が効果を発揮する場合もあるようだなと。
今回、利用するテクスチャに linearフィルタを設定したら、見た目がちょっとマシになったように感じたり。処理内容によっては、その手のフィルタ設定が効果を発揮する場合もあるようだなと。
[ ツッコむ ]
以上です。

