2014/01/27(月) [n年前の日記]
#1 [dxruby] タイトル画面をグネグネするアレを書いてみたり
DXRuby の Shader を使って、タイトル画面がグネグネするアレを書いてみたりして。
与えるパラメータの適切な値がよく分からなくて、オリジナルのソレとはどうも動きが違うのですけど…。それでもまあ、原理と言うか、仕組みとしては、こういう感じなのかなと。
_mbraster.rb
_logo.png
スクリプト単体でも実行できるけど、他のスクリプトから呼び出して使うこともできるはず。
スクリプトも画像も、Public Domain / CC0 ってことで。
与えるパラメータの適切な値がよく分からなくて、オリジナルのソレとはどうも動きが違うのですけど…。それでもまあ、原理と言うか、仕組みとしては、こういう感じなのかなと。
_mbraster.rb
require 'dxruby' # # Shaderを使ってMETALBLACKのタイトル画面っぽい処理をするクラス # class MbRaster @@hlsl = <<EOS float ang; float lvl; float spd; float alpha; texture tex0; sampler Samp = sampler_state { Texture =<tex0>; MinFilter = LINEAR; MagFilter = LINEAR; MipFilter = LINEAR; AddressU = WRAP; AddressV = WRAP; // AddressV = BORDER; }; struct PixelIn { float2 UV : TEXCOORD0; }; struct PixelOut { float4 Color : COLOR0; }; PixelOut PS1(PixelIn input) { PixelOut output; // input.UV.x = input.UV.x + sin(radians(input.UV.x * 360 * spd + ang)) * lvl * 0.25; input.UV.y = input.UV.y + sin(radians(input.UV.y * 360 * spd - ang)) * lvl; output.Color = tex2D( Samp, input.UV ); output.Color.a *= alpha; return output; } technique MbRasScroll { pass P0 { PixelShader = compile ps_2_0 PS1(); } } EOS attr_accessor :core, :shader, :image, :w, :h, :tilew, :tileh attr_accessor :rt, :rt_w, :rt_h, :rt_scaley # # 初期化処理 # # @param [Image] image 使用する画像 # @param [int] w 描画横幅。nilならウインドウ横幅 # @param [int] h 描画縦幅。nilならウインドウ縦幅 # def initialize(image, w=nil, h=nil) self.core = Shader::Core.new(@@hlsl, {:ang=>:float, :lvl=>:float, :spd=>:float, :alpha=>:float}) self.shader = Shader.new(self.core, "MbRasScroll") @image = image @w = (w == nil)? Window.width : w @h = (h == nil)? Window.height : h # 画面を覆い隠すタイル数を求める @tilew = @w.quo(@image.width).ceil @tileh = @h.quo(@image.height).ceil # RenderTarget の必要サイズを求める @rt_w = @image.width * @tilew @rt_h = @image.height * @tileh # y方向で拡大縮小して描画縦横幅に合わせる @rt_scaley = @h.quo(@rt_h) # Rendertarget生成 @rt = RenderTarget.new(@rt_w, @rt_h) end # # 描画処理 # # @param [int] x 描画位置x # @param [int] y 描画位置y # @param [float] u 横方向スクロール位置 # @param [float] v 縦方向スクロール位置 # @param [float] ang sinの開始角度。単位は度 # @param [float] lvl sinの振幅幅 # @param [float] spd sinの角度変化量 # @param [Hash] opts オプション # @option opts [int] z 描画奥行情報 # @option opts [float] alpha 透明度。0.0で透明。1.0で不透明 # @option opts [Object] blend 合成方法。:add や :alpha が使えるはず # def draw(x, y, u, v, ang, lvl, spd, opts={}) alpha = (opts.has_key?(:alpha))? opts[:alpha] : 1.0 blend = (opts.has_key?(:blend))? opts[:blend] : :alpha z = (opts.has_key?(:z))? opts[:z] : 0 self.shader.ang = ang self.shader.lvl = lvl self.shader.spd = spd self.shader.alpha = alpha # Shader が参照する画像を RenderTarget に作成 @rt.draw_tile(0, 0, [[0]], [@image], u, v, @tilew, @tileh).update # Shader を使って描画 Window.drawEx(x, y, @rt, :shader=>self.shader, :scaley=>@rt_scaley, :z=>z, :blend=>blend) end # # 動作確認用。グリッド画像を生成して返す # # @param [int] w 画像横幅 # @param [int] h 画像縦幅 # @return [Image] 生成した画像 # def self.get_grid_image(w, h) image = Image.new(w, h, [0, 255, 0]) image.box_fill(0, 0, w / 2 - 1, h / 2 - 1, [150,250,150]) image.box_fill(w / 2, 0, w - 1, h / 2 - 1, [100,250,100]) image.box_fill(0, h / 2, w / 2 - 1, h - 1, [200,250,200]) image.box_fill(w / 2, h / 2, w - 1, h - 1, [0,220,0]) return image end end # ---------------------------------------- # 以下は使用例 if __FILE__ == $0 image = Image.load("logo.png") bg = MbRaster.new(image) x = 0 y = 0 u = 0 v = 0 ang = 360 lvldef = 0.35 lvl = lvldef spd = 1.0 cnt = 0 font = Font.new(14) Window.loop do break if Input.keyPush?(K_ESCAPE) # マウスカーソル座標でパラメータを変えてみる ang = Input.mousePosX * 360 / 640.0 lvl = Input.mousePosY / 240.0 - 1.0 # spd = Input.mousePosY / 480.0 bg.draw(x, y, u, v, ang, lvl, spd) # u += 1 # v += 2 Window.drawFont(4, 4, "ang=#{ang} , lvl=#{lvl} , spd=#{spd}", font) Window.drawFont(4, 20, "Please move mouse cursor", font) cnt += 1 end endテスト用の画像も置いときます。
_logo.png
スクリプト単体でも実行できるけど、他のスクリプトから呼び出して使うこともできるはず。
スクリプトも画像も、Public Domain / CC0 ってことで。
[ ツッコむ ]
以上です。