光学迷彩の実験

かなりいい加減で実用段階ではない。
法線マップは他の画像に適用できないし、シェーダもいい加減だが、こんな感じで2Dゲーでも光学迷彩ができる可能性があることは確認した。

背景に良い絵がなかったので前に使ったトランジション画像を使った。
宇宙人が隠れているのがわかるだろうか。
あ、RenderTarget関連でいくつかバグがあったので、いまの公開しているDXRuby1.1.11devでは動かないので注意。

#!ruby -Ks
require 'dxruby'

image = Image.load("image/enemy3.png", 0, 0, 48,48).dup
normalmap = Image.new(image.width, image.height)

def count_w(x, y, image)
  c = 0
  while (image[x, y][0] != 0 and x < image.width )
    x += 1
    c += 1
  end
  return c
end

def count_h(x, y, image)
  c = 0
  while (image[x, y][0] != 0 and y < image.height )
    y += 1
    c += 1
  end
  return c
end

for y in 0..47
  x = 0
  while (x < image.width) do
    if image[x, y][0] != 0
      c = count_w(x, y, image)
      for temp in 0..c
        normalmap[x + temp, y] = [255, 255.0 / (c + 1) * (temp + 1), normalmap[x + temp, y][2], normalmap[x + temp, y][3]]
      end
      x += c
    end
    x += 1
  end
end

for x in 0..47
  y = 0
  while (y < image.height) do
    if image[x, y][0] != 0
      c = count_h(x, y, image)
      for temp in 0..c
        normalmap[x, y + temp] = [255,normalmap[x, y + temp][1],  255.0 / (c + 1) * (temp + 1), normalmap[x, y + temp][3]]
      end
      y += c
    end
    y += 1
  end
end

hlsl = <<EOS
texture Tex0;
texture Tex1;
texture Tex2;
sampler Samp0 = sampler_state
{
 Texture =<Tex0>;
};
sampler Samp1 = sampler_state
{
 Texture =<Tex1>;
};
sampler Samp2 = sampler_state
{
 Texture =<Tex2>;
};

struct PixelIn
{
  float2 UV : TEXCOORD0;
};
struct PixelOut
{
  float4 Color : COLOR0;
};

PixelOut PS(PixelIn input)
{
  PixelOut output;
  float2 temp = tex2D( Samp1, input.UV ).xy;
  float image = tex2D( Samp2, input.UV ).a;

  if (image == 0.0f)
  {
    output.Color = tex2D( Samp2, input.UV );
  }
  else
  {
    output.Color = tex2D( Samp0, input.UV + (0.5 - temp.xy)*10/48.0 );
  }
  return output;
}

technique TShader
{
 pass P0
 {
  PixelShader = compile ps_2_0 PS();
 }
}
EOS

shader = Shader.new(hlsl, "TShader")
transition = Image.load("puwa-35s.jpg")

rt = RenderTarget.new(640, 480)
rt2 = RenderTarget.new(640, 480)

x = 0
y = 0

Window.loop do
  x += Input.x*2
  y += Input.y*2
  Window.draw(0,0,transition)
  Window.update(rt)
  Window.draw(0, 0, rt)
  Window.update(rt2)

  rt2.x = x
  rt2.y = y
  rt2.width = image.width
  rt2.height = image.height
  i = rt2.to_image
  Window.draw(0,0,rt)
  Window.drawShader(x, y, [i, normalmap, image], shader)
  GC.start
end

おまけ。
ソースをアレコレ修正して、もう一つの敵も描画してみた。
法線マップがいい加減なのが見てわかる。俺にはまだまだ難しい技術だ。