affineCopyは-0.5せよ

Posted 2013.05.16 in 吉里吉里

今回は

『affineCopy を affine=false で使う場合は、
 出力座標を-0.5しなければならない!』

というお話。

-0.5しないと起きる問題

-0.5しないとどうなるのか。
一言で言えば

-0.5しないと画像がずれて描画される!

のである。

サンプルスクリプト

とりあえず、affineCopy を使って普通に画像を描画する tjs スクリプトを書いてみよう。

Box.png
Box


class TestWindow extends Window
{
  function TestWindow()
  {
    super.Window();
    
    // プライマリレイヤー作成
    add(new Layer(this, null));
    primaryLayer.setImageSize(200,200);
    primaryLayer.setSizeToImageSize();
    setInnerSize(primaryLayer.width, primaryLayer.height);
    
    // 画像をロード
    var image = new Layer(this, primaryLayer);
    image.loadImages("Box");
    
    // 画像を描画
    var w = image.imageWidth;
    var h = image.imageHeight;
    var x = 50;
    var y = 50;
    primaryLayer.affineCopy(image, 0, 0, w, h
      , false, x, y, x+w, y, x, y+h, stNearest);

    // 後始末
    invalidate image;
  }
}

var win = new TestWindow();
win.visible = true;

KiriKiri_AffineCopy_Test1

何も問題ないように見える。

線形補間の場合に起こる問題

サンプリング方法を線形補間など(stFastLinear, stLinearなど)にすると現象を明らかに確認できる。


    var x = 50;
    var y = 50;
    primaryLayer.affineCopy(image, 0, 0, w, h
      , false, x, y, x+w, y, x, y+h, stFastLinear);

KiriKiri_AffineCopy_Test2

なんだか変にぼやけている。
というか

画像が右下に
0.5 ピクセル分ずれて描画されている!

では出力座標を-0.5してみよう。


    var x = 50-0.5;
    var y = 50-0.5;
    primaryLayer.affineCopy(image, 0, 0, w, h
      , false, x, y, x+w, y, x, y+h, stFastLinear);

KiriKiri_AffineCopy_Test3

ずれがなくなった!

stNearest の場合に起こる問題

描画がずれる現象は補間を行う場合だけの問題なのだろうか。
そうではない。
stNearest の場合にも、一見わかりにくいが描画がずれている。
症状は画像をわずかに拡大させると確認できる。


    var x = 50;
    var y = 50;
    primaryLayer.affineCopy(image, 0, 0, w, h
      , false, x, y, x+w, y, x, y+h+0.1, stNearest);

KiriKiri_AffineCopy_Test4

サイズが1ピクセル大きくなり、上辺のラインが太くなっている。
+0.2にしても、+0.3にしても上辺のラインが常に太い状態になる。
それの何が問題なのかと思うかもしれないが、
これは不自然な画像の拡大の仕方であると言える。

出力座標を-0.5してみよう。


    var x = 50-0.5;
    var y = 50-0.5;
    primaryLayer.affineCopy(image, 0, 0, w, h
      , false, x, y, x+w, y, x, y+h+0.1, stNearest);

KiriKiri_AffineCopy_Test5

サイズは変化せず、上辺のラインが太くならなくなった。

じりじり拡大させるテスト

stNearest の場合の問題のポイントは、描画サイズのわずかな変化で
実際に描画される画像サイズに大きな変化が起こる点だ。
画像をゆっくりとじりじり拡大させるような演出を行う際、この問題は顕著に現れる。


class TestWindow extends Window
{
  var image;
  var timer;
  
  function TestWindow()
  {
    super.Window();
    
    // プライマリレイヤー作成
    add(new Layer(this, null));
    primaryLayer.setImageSize(200,200);
    primaryLayer.setSizeToImageSize();
    setInnerSize(primaryLayer.width, primaryLayer.height);
    
    // 画像をロード
    image = new Layer(this, primaryLayer);
    image.loadImages("Box");
    
    // タイマー作成
    timer = new Timer(onTimer, "");
    timer.interval = 1000;
    timer.enabled = true;
    onTimer();
  }
  
  function finalize()
  {
    invalidate timer;
    invalidate image;

    super.finalize();
  }
  
  var step = 0;
  function onTimer()
  {
     caption = "step:"+step;
     primaryLayer.fillRect(0, 0
       , primaryLayer.width, primaryLayer.height, 0xFFFFFFFF);
     
     // 画像を描画
     var w = image.imageWidth;
     var h = image.imageHeight;
     var x = 50;
     var y = 50;
     primaryLayer.affineCopy(image, 0, 0, w, h
       , false, x, y, x+w, y, x, y+h+step/10, stNearest);

     step++;
  }
}

var win = new TestWindow();
win.visible = true;

これを実行すると動き出しの部分で画像全体が一気にビクっとずれるのがわかる。
描画サイズのわずかな変化で、大きな変化が起きてしまっているからだ。

これの出力座標を-0.5すると、動き出しで画像が大きく動かなくなる。
そしてサイズの変化に応じてじりじり画像が動くようになる。
わずかな変化で大きく動く前の状態より、こちらの方がより自然な動きだと思わないだろうか。

まとめ

なぜこの問題が起き、なぜ-0.5すると問題が改善するのか。
詳しくは次回~


Leave a Reply

*