簡易エッジ抽出シェーダー

ふと思いついたのでテキトーに作ってみた。テキトーすぎてあまり品質はよろしくない。

α値が変化している部分を残す方法なので、アンチエイリアスがかかった画像だと綺麗にならない。どんな絵でもうまくできるようにするのも大変だから、どっちかというと絵にあわせてロジックを変えたほうが簡単だが汎用性はなくなる。難しいもんだ。

require 'dxruby'

  hlsl = <<EOS
  float g_width, g_height;
  texture tex0;

  sampler Samp0 = sampler_state
  {
   Texture =<tex0>;
   AddressU=BORDER;
   AddressV=BORDER;
  };

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

  PixelOut PS(PixelIn input)
  {
    PixelOut output;
    float c[9];
    c[0] = tex2D( Samp0, input.UV ).a;
    c[1] = tex2D( Samp0, input.UV - float2(1/g_width, 0) ).a;
    c[2] = tex2D( Samp0, input.UV + float2(1/g_width, 0) ).a;
    c[3] = tex2D( Samp0, input.UV - float2(0, 1/g_height) ).a;
    c[4] = tex2D( Samp0, input.UV + float2(0, 1/g_height) ).a;
    c[5] = tex2D( Samp0, input.UV - float2(1/g_width, 1/g_height) ).a;
    c[6] = tex2D( Samp0, input.UV + float2(1/g_width, 1/g_height) ).a;
    c[7] = tex2D( Samp0, input.UV + float2(1/g_width, -1/g_height) ).a;
    c[8] = tex2D( Samp0, input.UV + float2(-1/g_width, 1/g_height) ).a;

    if( c[0] == c[1] && c[1] == c[2] && c[2] == c[3] && c[3] == c[4] &&
        c[4] == c[5] && c[5] == c[6] && c[6] == c[7] && c[7] == c[8] )
    {
      output.Color = float4(0,0,0,0);
    }
    else
    {
      output.Color = tex2D( Samp0, input.UV );
    }

    return output;
  }

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

  core = Shader::Core.new(
    hlsl,
    {
      :g_width => :float,
      :g_height => :float,
    }
  )

Window.width = 300
Window.height = 300

shader = Shader.new(core,"Edge")
shader.g_width = 200
shader.g_height = 200

image = Image.load("logo.png").set_color_key([0,0,0])

Window.loop do
  Window.draw_shader(50,30,image,shader)
end