RGSSに近い色調整機能を持たせるSprite拡張
DXRuby1.3.1devのSpriteに載せる予定はなく、RGSSにあってFreeRGSSでも作りこんである機能として、tone=、color=、flashといったメソッドがある。
これらは従来のDXRubyでは実現が不可能であり、1.3系ならShaderクラスを使うことで可能となる。実はFreeRGSSでも内部でシェーダを使っている。
それぞれの意味としては
・toneはrgbとgrayからなる配列で、画像にたいしてrgbを-255〜+255で調整しつつ、grayの値(0〜255)に応じてグレイスケール化する。
・colorはargbの色配列で、画像にその色を半透明合成する。
・flashは色配列と時間を引数で渡し、画像を指定色で塗りつぶし、時間の間で元の画像まで減衰させる。updateメソッドで1フレーム進める。
RGSSの仕様として、colorとflashの同時適用はできない。flashの色がある程度弱くなったところでcolorの色に切り替わるような動きをする。
これを実現させるコードは以下。Spriteクラスを継承してRgssSpriteを作っている。HLSLはFreeRGSSで使ったものだ。
class SpriteShader < Shader hlsl = <<EOS float4 g_blend; float4 g_tone; texture tex0; sampler Samp = sampler_state { Texture =<tex0>; }; struct PixelIn { float2 UV : TEXCOORD0; }; struct PixelOut { float4 Color : COLOR0; }; PixelOut PS(PixelIn input) { PixelOut output; float3 temp; float3 ntsc = {0.298912, 0.586611, 0.114478}; float ntscy; output.Color = tex2D( Samp, input.UV ); ntsc = ntsc * output.Color.rgb; ntscy = ntsc.r + ntsc.g + ntsc.b; temp.r = output.Color.r + ((ntscy - output.Color.r) * g_tone.a); temp.g = output.Color.g + ((ntscy - output.Color.g) * g_tone.a); temp.b = output.Color.b + ((ntscy - output.Color.b) * g_tone.a); output.Color.rgb = min(1.0, temp + g_tone.rgb) * (1.0 - g_blend.a) + g_blend.rgb * g_blend.a; return output; } technique TShader { pass P0 { PixelShader = compile ps_2_0 PS(); } } EOS @@core = Shader::Core.new(hlsl, { :g_blend => :float, :g_tone => :float, } ) def initialize super(@@core, "TShader") self.g_blend = [0.0,0.0,0.0,0.0] self.g_tone = [0.0,0.0,0.0,0.0] end def tone=(ary) self.g_tone = [ary[0] / 255.0, ary[1] / 255.0, ary[2] / 255.0, ary[3] / 255.0] end def color=(ary) self.g_blend = [ary[1] / 255.0, ary[2] / 255.0, ary[3] / 255.0, ary[0] / 255.0] end end class RgssSprite < Sprite def initialize(x=0, y=0, image=nil) super self.shader = SpriteShader.new @rgss_sprite_color = nil @rgss_sprite_flash_color = nil @rgss_sprite_flash_duration = 1 @rgss_sprite_flash_count = 0 end def tone=(ary) if ary == nil self.shader.tone = [0,0,0,0] else self.shader.tone = ary end end def color=(ary) @rgss_sprite_color = ary end def flash(color=[255,255,255,255], duration=30) @rgss_sprite_flash_color = color @rgss_sprite_flash_duration = duration @rgss_sprite_flash_count = duration end def update @rgss_sprite_flash_count -= 1 if @rgss_sprite_flash_count > 0 end def draw if @rgss_sprite_color != nil and @rgss_sprite_flash_count > 0 if @rgss_sprite_color[0] > @rgss_sprite_flash_color[0] * @rgss_sprite_flash_count / @rgss_sprite_flash_duration self.shader.color = @rgss_sprite_color else self.shader.color = [@rgss_sprite_flash_color[0] * @rgss_sprite_flash_count / @rgss_sprite_flash_duration, @rgss_sprite_flash_color[1], @rgss_sprite_flash_color[2], @rgss_sprite_flash_color[3] ] end elsif @rgss_sprite_flash_count > 0 self.shader.color = [@rgss_sprite_flash_color[0] * @rgss_sprite_flash_count / @rgss_sprite_flash_duration, @rgss_sprite_flash_color[1], @rgss_sprite_flash_color[2], @rgss_sprite_flash_color[3] ] elsif @rgss_sprite_color != nil self.shader.color = @rgss_sprite_color else self.shader.color = [0,0,0,0] end super end end
で、これを使うコード。
#!ruby -Ks require 'dxruby' require './shader/sprite' Window.width = 800 Window.height = 600 s = RgssSprite.new s.image = Image.load('./bgimage/BG10a_80.jpg') Window.loop do # Zでフラッシュさせる s.flash if Input.key_push?(K_Z) # Xを押している間グレイスケールになる if Input.key_down?(K_X) s.tone = [0,0,0,255] # Cを押している間、赤色が無くなる elsif Input.key_down?(K_C) s.tone = [-255,0,0,0] else s.tone = nil end # Vを押している間、青をブレンドする if Input.key_down?(K_V) s.color = [60,0,0,255] else s.color = nil end s.update s.draw break if Input.key_push?(K_ESCAPE) end
すっかり書き忘れていたが、DXRubyFwのSprite機能を統合する(かもしれない)のでDXRuby1.3.1devではためしにSpriteクラスを実装し始めてみている。
モノはWikiに置いてある。