mieki256's diary



2017/12/14(木) [n年前の日記]

#1 [love2d] love2dでShaderを使ってラスタースクロールその2

随分昔に、 _DXRubyでラスタースクロール処理 を試したのだけど、それを love2d + Shader機能でもできるか実験。

こんな感じに。環境は、Windows10 x64 + love2d 0.10.2。

shader_test07_raster_ss.gif

64ドット分スクロールしたらまた0に戻す、みたいなことをしているけど、元画像の作り方次第で誤魔化せる、みたいな。

ソースは以下。 :

画像は、 _DXRubyでラスタースクロール処理 で使った _bg_ras_c.png を使用。

ソースは以下。

_conf.lua
function love.conf(t)
  t.window.title = "Shader test 07 raster"
  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 07 raster

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("bg_ras_c.png")

  -- make shader
  local shadercode = [[
    extern vec2 imgsize;
    extern number factor;

    vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ) {
      texture_coords.x = mod(texture_coords.x + ((factor + (factor * texture_coords.y)) / imgsize.x), 1.0);
      vec4 texcolor = Texel(texture, texture_coords);
      return texcolor * color;
    }
  ]]
  myshader = love.graphics.newShader(shadercode)
  myshader:send("imgsize", {img:getWidth(), img:getHeight()})
  myshader:send("factor", 0.0)

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

function love.update(dt)
  v = v + 128 * dt
  myshader:send("factor", v % 64.0)
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()
  end
end

#2 [love2d] love2dのShaderでなんだかよく分からないエフェクトになったり

love2dの、 _公式Wikiサンプル を動かしていたらなんだかよく分からないエフェクトになってきたのでアップロードしてみるテスト。

こんな感じに。

shader_test06_sincos_ss.gif

自分は頭が悪いので、どうしてこういう効果になるのかは分かってないのだけど、これはこれでなんだか面白いなと。

画像とソース。 :

使用画像。

_hsvbar.png

_conf.lua
function love.conf(t)
  t.window.title = "Shader test 06 sin cos"
  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 06 sin cos
--
-- love.graphics.newShader - LOVE
-- https://love2d.org/wiki/love.graphics.newShader

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("hsvbar.png")

  -- make shader
  myshader = love.graphics.newShader("shader.fs")
  myshader:send("factor", 0.0)

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

function love.update(dt)
  angle = (angle + 30 * dt) % 360.0;
  myshader:send("factor", 1.0 * (1.0 - math.sin(math.rad(angle))))
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()
  end
end

_shader.fs
extern number factor;
varying vec4 vpos;

#ifdef VERTEX
vec4 position( mat4 transform_projection, vec4 vertex_position ) {
  vpos = vertex_position;
  return transform_projection * vertex_position;
}
#endif

#ifdef PIXEL
vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ) {
  texture_coords += vec2(factor * cos(0.1 * vpos.x), factor * sin(0.075 * vpos.y));
  vec4 texcolor = Texel(texture, texture_coords);
  return texcolor * color;
}
#endif

今回は Shader部分を別ファイルに分けてみたり。

2017/12/13(水) [n年前の日記]

#1 [love2d] love2dのShaderで実験中

love2dのShaderを使って色々実験中。

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

#1 [love2d] love2dのShaderを使ってパレット書き換えっぽいことをする

love2dのShaderを使えば特定の色だけをぽわーんぽわーんと点滅させたりできるのではないか、つまりは大昔の2Dゲーム画面でよく見かけたパレット書き換えっぽいソレがビミョーに再現できるのではないかと思えてきたので、そのあたりを実験してみたり。環境は Windows10 x64 + love2d 0.10.2。

こんな感じに。

shader_test04_palettechange_ss.gif

画像とソース。 :

使用画像は以下。

_colorbar_circle01.png

ソースは以下。

_conf.lua
/function love.conf(t)
  t.window.title = "Shader test 04 palette change modoki"
  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 04
-- palette change modoki

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

  -- load image
  img = love.graphics.newImage("colorbar_circle01.png")

  -- make shader
  myshader = love.graphics.newShader(
    [[
      extern number factor;
      extern vec3 checkcolor;
      extern vec3 replacecolor;

      vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
        vec4 pixel = Texel(texture, texture_coords);
        if (pixel.r == checkcolor.r && pixel.g == checkcolor.g && pixel.b == checkcolor.b) {
          pixel.r = pixel.r * (1.0 - factor) + replacecolor.r * factor;
          pixel.g = pixel.g * (1.0 - factor) + replacecolor.g * factor;
          pixel.b = pixel.b * (1.0 - factor) + replacecolor.b * factor;
        }
        return pixel * color;
      }
    ]]
  )

  myshader:send("checkcolor", {0.0, 1.0, 0.0})  -- R,G,B
  myshader:send("replacecolor", {0.0, 0.0, 0.0})  -- R,G,B
  angle = 0
end

function love.update(dt)
  angle = (angle + 90 * dt) % 360.0
  local v = 1.0 - math.abs(math.sin(math.rad(angle)))
  myshader:send("factor", v)  -- set 0.0 - 1.0

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

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

  love.graphics.setShader(myshader)
  love.graphics.setColor(255, 255, 255)
  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_ofsx = (wdw_w - (scr_w * scr_scale)) / 2
  scr_ofsy = (wdw_h - (scr_h * scr_scale)) / 2
  love.graphics.setColor(255, 255, 255)
  love.graphics.draw(canvas, scr_ofsx, scr_ofsy, 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()
  end
end

特定色が見つかったら、その時だけピクセルのRGB値を変更、てな処理をしてる。

ただ、こういうGLSLの書き方はあまりよくないらしい。GLSL関連の説明ページを見ると、「条件分岐(if文)はコストがかかる」と言われてたりするわけで。とは言え、if文を使わずにこういう処理を書けるのか、そこらへんよく分からんわけで。この場合、違う書き方はできるのかな…?

hsv変換をして色を変えてみる。 :

上記のソースを書いて動作確認しているうちに、もしかして、RGBをHSV(色相、彩度、明度)に変換して色々処理ができるのでは、と思えてきたわけで。

しかし、GLSLでRGB to HSV や HSV to RGB ってどうやるのかな…。と思ってググってみたら、以下のページで「このやり方が速いよ!」てな書き方が公開されてた。

_Blog: Fast branchless RGB to HSV conversion in GLSL - Lol Engine

また、HSV to RGB なら、love2dの公式wikiにも説明があった。

_HSV color (日本語) - LOVE

ありがたい。試しに使わせてもらったり。

結果はこんな感じに。

shader_test05_hsv_ss.gif


使用画像は以下。

_hsvbar.png

ソースは以下。

_conf.lua
function love.conf(t)
  t.window.title = "Shader test 05 hsv"
  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 05 hsv
--
-- reference
-- Blog: Fast branchless RGB to HSV conversion in GLSL - Lol Engine
-- http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl

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

  -- load image
  img = love.graphics.newImage("hsvbar.png")

  -- make shader
  myshader = love.graphics.newShader(
    [[
      extern number factor;

      vec3 rgb2hsv(vec3 c) {
        vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
        vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);
        vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);
        float d = q.x - min(q.w, q.y);
        float e = 1.0e-10;
        return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
      }

      vec3 hsv2rgb(vec3 c) {
          vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
          vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
          return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
      }

      vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ){
        vec4 pixel = Texel(texture, texture_coords);
        vec3 hsv = rgb2hsv(pixel.rgb);
        hsv.x = mod(hsv.x + factor, 1.0);
        vec3 rgb = hsv2rgb(hsv);
        pixel.r = rgb.r;
        pixel.g = rgb.g;
        pixel.b = rgb.b;
        return pixel * color;
      }
    ]]
  )
  factor = 0.0
  angle = 0
end

function love.update(dt)
  factor = factor + 0.25 * dt
  myshader:send("factor", factor)  -- set 0.0 - 1.0

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

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

  love.graphics.setShader(myshader)
  love.graphics.setColor(255, 255, 255)
  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_ofsx = (wdw_w - (scr_w * scr_scale)) / 2
  scr_ofsy = (wdw_h - (scr_h * scr_scale)) / 2
  love.graphics.setColor(255, 255, 255)
  love.graphics.draw(canvas, scr_ofsx, scr_ofsy, 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()
  end
end

RGB値からHSVを求めて、H(色相)を少し変化させて、またRGB値に戻して描画する、みたいな。

#2 [nitijyou] 雪がそこそこ積もった

昨晩から結構雪が降ったようで。犬の散歩も一苦労。

以上、3 日分です。

過去ログ表示

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