Shader再び
DXRuby1.1で一度作ったが、とても使いにくかったので再設計。
シェーダのアルゴリズムとパラメータ名・型を保持するImmutableのShaderクラスと、Shaderオブジェクトとパラメータを保持するShaderSetクラスに分けてみた。
これでShaderSetを描画プリミティブごとに持つことができるようになる。Window.drawShaderに渡すのはShaderSetオブジェクトのほう。
ためしにトランジションのコードを昔の記事から引っ張り出してきて動かしてみた。ルール画像は吉里吉里のトランジションライブラリから拝借。
ただ、HLSLの都合でパラメータの設定がわかりにくいことになるから、そのへんはサポートクラスを用意して扱いやすくする必要があるだろう。
そのへんはまた後日。
あと、クラスの名前は仮。実装もまだ手抜き。設計もとりあえず作ってみた実験的なもので、変わる可能性はおおいにあることを付け加えておく。
#!ruby -Ks require 'dxruby' map = [[0, 0, 0, 0, 0, 0, 0, 0, 29, 11, 11, 30, 34, 66, 67, 67], [0, 0, 0, 24, 25, 26, 0, 0, 29, 11, 11, 39, 40, 6, 34, 34], [0, 0, 24, 17, 31, 35, 0, 0, 12, 20, 11, 11, 11, 39, 40, 40], [0, 24, 17, 34, 7, 44, 0, 28, 28, 29, 11, 11, 11, 11, 11, 11], [0, 33, 31, 34, 35, 0, 28, 3, 37, 38, 11, 11, 11, 18, 19, 19], [0, 42, 43, 43, 44, 28, 3, 38, 11, 11, 11, 18, 19, 13, 28, 28], [0, 0, 0, 0, 3, 37, 38, 11, 11, 18, 19, 13, 28, 28, 28, 0], [0, 0, 0, 3, 38, 11, 11, 11, 18, 13, 28, 28, 51, 52, 52, 52], [0, 0, 3, 38, 11, 11, 18, 19, 13, 51, 52, 52, 86, 58, 61, 76], [28, 0, 29, 11, 11, 18, 13, 28, 51, 86, 58, 58, 61, 61, 58, 62], [0, 28, 29, 11, 18, 13, 28, 0, 60, 58, 61, 61, 61, 61, 76, 71], [0, 28, 29, 11, 27, 28, 28, 51, 86, 61, 61, 58, 76, 70, 71, 0], [0, 0, 29, 11, 36, 4, 28, 60, 58, 61, 58, 76, 71, 0, 1, 2], [0, 28, 29, 11, 11, 36, 4, 69, 70, 70, 70, 71, 0, 1, 2, 0], [0, 0, 12, 20, 11, 11, 27, 0, 1, 0, 1, 1, 1, 2, 2, 0], [0, 0, 28, 12, 20, 11, 27, 0, 0, 0, 2, 2, 0, 2, 2, 0], [0, 0, 0, 2, 29, 11, 27, 1, 2, 2, 2, 0, 0, 2, 2, 2], [0, 0, 0, 2, 29, 11, 27, 1, 0, 1, 1, 2, 2, 0, 0, 2], [0, 0, 0, 0, 29, 11, 27, 1, 0, 2, 2, 2, 1, 1, 2, 2], [0, 45, 47, 2, 29, 11, 36, 4, 1, 2, 2, 0, 0, 2, 2, 0], [45, 82, 56, 0, 29, 11, 11, 36, 4, 1, 2, 2, 2, 2, 0, 0], [54, 0, 56, 0, 12, 20, 11, 11, 36, 37, 4, 0, 2, 2, 2, 2], [54, 55, 81, 46, 47, 12, 20, 11, 11, 11, 36, 4, 1, 1, 1, 2], [54, 55, 0, 0, 56, 0, 12, 19, 20, 11, 11, 36, 37, 4, 1, 1], [54, 0, 55, 55, 56, 0, 0, 0, 12, 20, 11, 11, 11, 36, 37, 37], [63, 73, 55, 55, 56, 0, 0, 2, 2, 29, 11, 11, 11, 11, 11, 11], [0, 54, 0, 55, 81, 47, 0, 2, 3, 38, 11, 11, 11, 11, 11, 11], [0, 54, 0, 0, 55, 56, 2, 0, 29, 11, 11, 11, 21, 22, 22, 22], [0, 63, 64, 64, 64, 65, 0, 0, 29, 11, 11, 21, 15, 48, 49, 49], [0, 0, 0, 0, 0, 0, 0, 0, 29, 11, 11, 30, 34, 57, 34, 34], ] hlsl = <<EOS float g_min; float g_max; texture tex0; texture tex1; sampler Samp0 = sampler_state { Texture =<tex0>; }; sampler Samp1 = sampler_state { Texture =<tex1>; }; struct PixelIn { float2 UV : TEXCOORD0; }; struct PixelOut { float4 Color : COLOR0; }; PixelOut PS(PixelIn input) { PixelOut output; output.Color = tex2D( Samp0, input.UV ); output.Color.a = smoothstep(g_min, g_max, tex2D( Samp1, input.UV ).r ); return output; } technique TShader { pass P0 { PixelShader = compile ps_2_0 PS(); } } EOS shader = Shader.new(hlsl, "TShader", # 2つ目のパラメータはtechniqe名 { # 3つ目のパラメータはシェーダに渡すパラメータ名と型のHash :g_min => :float, :g_max => :float, :tex1 => :texture, } ) shaderset = ShaderSet.new(shader) # ShaderSetがShaderオブジェクトとパラメータの値を持つ rt = RenderTarget.new(640, 480) transition = Image.load("右渦巻き.png") image = Image.loadToArray("image/maptile.png", 9, 10) min = 0.0 max = 0.1 Window.loop do min += 0.01 max += 0.01 rt.drawTile(150, 16, map, image, 0, 0, 12, 14) rt.update # ShaderSetオブジェクトには特異メソッドでSetter/Getterが定義される shaderset.tex1 = transition shaderset.g_min = min shaderset.g_max = max # drawShaderに渡すのはShaderSetオブジェクト Window.drawShader(0, 0, rt, shaderset) end