2014/01/12(日) [n年前の日記]
#1 [dxruby][game] DXRubyでHLSL勉強中
DXRubyでラスタースクロールをやってみたいわけですよ。配列の中に入ってるスクロール値を使ってラスタースクロールさせる、みたいなことをやってみたい。てなわけで、Shader だか HLSL だかを勉強中。
ググってるうちに、 HLSL でも配列を ―― int param[50]; みたいな書き方をすれば確保はできるらしい、と知ったものの。DXRuby から「このグローバル変数は配列だよ」と伝える記述が不明で。
また、HLSLで配列を用意すると、レジスターサイズ云々という問題も出てくるらしいと知り、実際に使えそうなのかどうか、ちょっとよく分かってない状態。
その前に、ラスター単位でスクロール量を変更することができるのかどうか、確認してみないといかんなと。そこで、昔の2Dゲームでよくやってた、天井だの床だのをラスタースクロールをするソレを実験。
しかし、上手く行かない。何故か、画面がやたらとチラチラする…。
色々ググってるうちに、もしかしたらフィルターとやらが関係してたりするのかなと。試しに、以下のように変更してみたり。
とりあえず、それっぽく動いた版を貼ってみたり。
_shader_test7_b.rb
ググってるうちに、 HLSL でも配列を ―― int param[50]; みたいな書き方をすれば確保はできるらしい、と知ったものの。DXRuby から「このグローバル変数は配列だよ」と伝える記述が不明で。
また、HLSLで配列を用意すると、レジスターサイズ云々という問題も出てくるらしいと知り、実際に使えそうなのかどうか、ちょっとよく分かってない状態。
その前に、ラスター単位でスクロール量を変更することができるのかどうか、確認してみないといかんなと。そこで、昔の2Dゲームでよくやってた、天井だの床だのをラスタースクロールをするソレを実験。
しかし、上手く行かない。何故か、画面がやたらとチラチラする…。
色々ググってるうちに、もしかしたらフィルターとやらが関係してたりするのかなと。試しに、以下のように変更してみたり。
sampler Samp0 = sampler_state
{
Texture =<tex0>;
// こっちだと画面がチラチラする (´・ω・`)
// MinFilter = LINEAR;
// MagFilter = LINEAR;
// MipFilter = LINEAR;
// こっちならチラチラしない
MinFilter = POINT;
MagFilter = POINT;
MipFilter = NONE;
AddressU = WRAP;
AddressV = WRAP;
};
かなり改善された。ただ、これでもまだ、チラチラしてるけど…。とりあえず、それっぽく動いた版を貼ってみたり。
_shader_test7_b.rb
# Shaderを使ってラスタスクロールのテスト
# 天井、壁、床をラスタースクロールさせるっぽい感じの処理
require 'dxruby'
hlsl = <<EOS
float2 size;
float d;
float dd;
texture tex0;
sampler Samp0 = sampler_state
{
Texture =<tex0>;
// こっちだと画面がチラチラする (´・ω・`)
// MinFilter = LINEAR;
// MagFilter = LINEAR;
// MipFilter = LINEAR;
// こっちならチラチラしない
MinFilter = POINT;
MagFilter = POINT;
MipFilter = NONE;
AddressU = WRAP;
AddressV = WRAP;
};
struct PixelIn
{
float2 UV : TEXCOORD0;
};
struct PixelOut
{
float4 Color : COLOR0;
};
PixelOut PS1(PixelIn input)
{
PixelOut output;
input.UV.x = input.UV.x + ((d + (d * input.UV.y * dd)) / size.x);
output.Color = tex2D( Samp0, input.UV );
return output;
}
PixelOut PS2(PixelIn input)
{
PixelOut output;
input.UV.x = input.UV.x + ((d + (d * (1.0 - input.UV.y) * dd)) / size.x);
output.Color = tex2D( Samp0, input.UV );
return output;
}
PixelOut PS3(PixelIn input)
{
PixelOut output;
input.UV.x = input.UV.x + d / size.x;
output.Color = tex2D( Samp0, input.UV );
return output;
}
// float4 PS(float2 input : TEXCOORD0) : COLOR0
// {
// float4 output;
// // input.x -= ((d / size.x) + ((d / size.x) * input.y * dd));
// input.x = input.x - ((d + (d * input.y * dd)) / size.x);
// output = tex2D( Samp0, input);
// return output;
// }
technique FloorScroll
{
pass P0
{
PixelShader = compile ps_2_0 PS1();
}
}
technique CeilingScroll
{
pass P0
{
PixelShader = compile ps_2_0 PS2();
}
}
technique WallScroll
{
pass P0
{
PixelShader = compile ps_2_0 PS3();
}
}
EOS
core = Shader::Core.new(hlsl, {:size=>:float, :d=>:float, :dd=>:float})
shader1 = Shader.new(core, "CeilingScroll")
shader2 = Shader.new(core, "WallScroll")
shader3 = Shader.new(core, "FloorScroll")
# 画像に対してランダムにドットを打つ
def plot_random_dot(image)
dt = [[10, [255, 0, 64, 255]],
[5, [255, 0, 255, 255]],
[3, [255, 255, 255, 255]]]
srand(0)
image.height.times do |y|
# next if y % 2 != 0
dt.each do |d|
d[0].times {|i| image[rand(image.width), y] = d[1]}
end
end
end
image1 = Image.new(640, 150, [0, 0, 0, 0]) # 天井
image2 = Image.new(640, 180, [0, 0, 0, 0]) # 壁
image3 = Image.new(640, 150, [0, 0, 0, 0]) # 床
plot_random_dot(image1)
plot_random_dot(image2)
plot_random_dot(image3)
shader1.size = [image1.width, image1.height]
shader1.d = 0
shader1.dd = 2.0 # yが1ドット進むごとにつける角度
shader2.size = [image2.width, image2.height]
shader2.d = 0
shader2.dd = 0
shader3.size = [image3.width, image3.height]
shader3.d = 0
shader3.dd = 16.0
# Window.fps = 10
x = 0
Window.loop do
break if Input.keyPush?(K_ESCAPE)
x += 1
shader1.d = x # スクロール量を指定
shader2.d = x
shader3.d = x
y = 0
Window.draw_shader(0, y, image1, shader1)
y += image1.height
Window.draw_shader(0, y, image2, shader2)
y += image2.height
Window.draw_shader(0, y, image3, shader3)
end
HLSLについては、サンプルスクリプトをコピペして、数行書き換えてるだけなので…。サンプルと同様に Public Doamin として扱ってくれれば、と。
◎ 画像を用意するのが一番の問題。 :
プログラム部分は動いたので、天井だの床だのに使う画像を作ってみようとしたのだけど、これがまったく上手く行かず。GIMP で、タイル画像を並べて、遠近法変形?をしてみる、等の作業をしていたのだけど…。実際に表示してスクロールさせてみると、見た目がどんどんグチャグチャになっていく。
スクロール量と、画像内の傾き具合が一致してないと、見た目がおかしくなるのだなと。また、ラスター毎にループするようにしておいて、一定量変化したらスクロール値をリセット、等の処理が必要かもしれないなと。何にせよ、元画像を用意する際に、何か制作上のコツがありそうな。
しかし、考えてみたら、そもそもHLSLを使ってるのだから…。ただのタイリング画像を渡して、プログラム側で遠近法っぽい変形を ―― ラスター毎の拡大縮小をして表示したほうがいいんじゃないかと思えてきたり。元画像を遠近法のソレっぽい見た目にしなきゃいけないのは、ハードウェア的に縦横のスクロールしかできなかった、大昔のゲーム機に限定された話だよなと。今なら、というかDXRubyなら、XEXEXや、レイディアントシルバーガンの背景みたいな見せ方もできるはず。
まあ、そのあたりの処理は、今後の課題です…。
背景も何もかもポリゴン描画するのが当たり前になってしまった時代に、自分は一体何をやってるのだろう、てな気もしますが。
スクロール量と、画像内の傾き具合が一致してないと、見た目がおかしくなるのだなと。また、ラスター毎にループするようにしておいて、一定量変化したらスクロール値をリセット、等の処理が必要かもしれないなと。何にせよ、元画像を用意する際に、何か制作上のコツがありそうな。
しかし、考えてみたら、そもそもHLSLを使ってるのだから…。ただのタイリング画像を渡して、プログラム側で遠近法っぽい変形を ―― ラスター毎の拡大縮小をして表示したほうがいいんじゃないかと思えてきたり。元画像を遠近法のソレっぽい見た目にしなきゃいけないのは、ハードウェア的に縦横のスクロールしかできなかった、大昔のゲーム機に限定された話だよなと。今なら、というかDXRubyなら、XEXEXや、レイディアントシルバーガンの背景みたいな見せ方もできるはず。
まあ、そのあたりの処理は、今後の課題です…。
背景も何もかもポリゴン描画するのが当たり前になってしまった時代に、自分は一体何をやってるのだろう、てな気もしますが。
[ ツッコむ ]
以上です。

