colorTransformとBitmapData.drawの相性

Filed under AS3, Flash
Tagged as , , ,

Tweenerなどで色を変えたものをBitmapData.drawで描画しても、色変更が適用されない、という現象に悩んだので、ちょっと仕組みを調べてみました。
(2009/09/10夜:dskさんにコメントをいただき完全解決しましたので、その情報も下部に追記しました)

問題発生

「Tweenerで色を変更してもそれをBitmapDataにdrawしたら変更前の状態が描画される」という問題ですが、いろいろ調べていたら、どうやら「Tweenerなどで色を変える方法はtransform.colorTransformを使用している」ことが分かりました。
この問題のやっかいなところは、colorTransformが適用されないだけであり、別にエラーも出ないし、FlashPlayerも落ちたりしないので、何が悪いのか分からないところです。

処理の流れを想像してみる

描画対象はDisplayObjectの派生クラス(とBitmapDataクラス)なのですが、これらは「DisplayObjectのサイズと同じサイズの描画領域に現在の状態を描画しておくメソッド」と「最終的に描画メモリ領域に出力させるために呼ばれる描画メソッド」を持っていると思うのです。
仮に、前者をrender()、後者をtransfer() と呼ぶことにすると、次のような処理になっているのではないでしょうか。

  • 毎フレームの処理というのは、描画リストにあるDisplayObjectのtransferを呼び出す処理、となる。
  • そのときDisplayObjectにtransformが指定されていたら、renderで準備した画像に対してtransformを適用したものをtransferさせる。

まぁ、内部的にはもっと複雑だとは思いますが、何となくこうじゃないのかなぁ、と思っています。

「処理されない」を再現するコード

以上のテストは次のようにして再現してみました。

  • 描画元となるMovieClipを用意し、それを_sourceと名付け、stage(下のあたり)に配置します。
  • 描画先となるBitmapDataは _bmpdとして作成し、それを保持するBitmapインスタンスをstage(上部に広目)に配置します。
  • 毎フレーム、_sourceにtransform.colorTransformを適用します。
  • 毎フレーム、_bmpdに_sourceを描画します。(位置はカーソル位置)
  • (具体的なソースコードはこのエントリ最後に載せておきます)

TestTransform-FlashIDE
これで実行してみた結果は以下のようになり、colorTransformが適用されてない様子が分かるかと思います。(緑色のものがcolorTransformを適用している状態です)
TestTransform-Result

colorTransform代替手法

以上で終わっても、あまり得にならないエントリになるので、colorTransformの代わりになり、BimapData.drawしてもそれが適用される、という方法を紹介しておきます。
それは、ColorMatrixFilterを使う方法で、具体的には以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
// [1] colorTransformを使う処理.
//_source.transform.colorTransform
//  = new ColorTransform( 0.5, 0.5, 0.5, 1, 0, 120, 0, 0 );
 
// [2] [1]と同等の色変化があるColorMatrixFilter処理.
var cm:Array    = [ 0.5,    0,      0,      0,      0,
                    0,      0.5,    0,      0,      120,
                    0,      0,      0.5,    0,      0,
                    0,      0,      0,      1,      0 ];
var cmf:ColorMatrixFilter	= new ColorMatrixFilter( cm );
_source.filters	= [cmf];

追記:Tweenerの変化を適用させることもできた!

この項目は2009/09/10追記しました。
コメント欄で、dskさんに「BitmapData.draw()ファンクションの第三引数にColorTransformを渡せます。」と教えていただきました。ありがとうございます!
で、早速検証してみました。
Tweenerで_sourceの色を変化させます。するとその変化は_source.transform.colorTransformに入っているはずなので、この値をそのままBitmapData.draw()の第3引数に渡してみたところ、問題なく、色の変化を描画することができました!

1
2
3
  var posmat:Matrix = new Matrix();
  posmat.translate( mouseX, mouseY );
  _bmpd.draw( _source, posmat, _source.transform.colorTransform );  // マウスの位置に描画.

TestTransform-Result2
これにて完全解決!


全テストコードは以下のようになります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package {
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.filters.ColorMatrixFilter;
  import flash.geom.ColorTransform;
  import flash.geom.Matrix;
 
  public class TestTransformRoot extends Sprite {
    public var  _source:Sprite;
    public var  _bmpd:BitmapData;
 
    // コンストラクタ.
    public function TestTransformRoot()
    {
      _bmpd = new BitmapData( 400, 200, false, 0xDDDDFF );
      addChild( new Bitmap( _bmpd ) );
 
      addEventListener( Event.ENTER_FRAME, process );
    }
 
    private function process(e:Event) :void
    {
      // test.
      //_source.transform.colorTransform  = new ColorTransform( 0.5, 0.5, 0.5, 1, 0, 120, 0, 0 );
      // test2.
      var cm:Array  = [ 0.5,  0,    0,    0,    0,
                0,    0.5,  0,    0,    120,
                0,    0,    0.5,  0,    0,
                0,    0,    0,    1,    0 ];
      var cmf:ColorMatrixFilter = new ColorMatrixFilter( cm );
      _source.filters = [cmf];
 
      var posmat:Matrix = new Matrix();
      posmat.translate( mouseX, mouseY );
      _bmpd.draw( _source, posmat );  // マウスの位置に描画.
    }
  }
}

Tweenerで色の変化を行い、BitmapData.draw()に適用させるバージョンはこちら。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package {
  import caurina.transitions.Tweener;
  import caurina.transitions.properties.ColorShortcuts;
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.filters.ColorMatrixFilter;
  import flash.geom.ColorTransform;
  import flash.geom.Matrix;
 
  public class TestTransformRoot extends Sprite {
    public var  _source:Sprite;
    public var  _bmpd:BitmapData;
 
    // コンストラクタ.
    public function TestTransformRoot()
    {
      _bmpd = new BitmapData( 400, 200, false, 0xDDDDFF );
      addChild( new Bitmap( _bmpd ) );
 
      addEventListener( Event.ENTER_FRAME, process );
 
      ColorShortcuts.init();
      tweenFunc0(); // Tweenerで色の変化を行います.
    }
 
    private function tweenFunc0() :void
    {
      Tweener.addTween( _source,
         { _color:0x3333aa, time:2, onComplete:tweenFunc1 } );
    }
    private function tweenFunc1() :void
    {
      Tweener.addTween( _source,
        { _color:0xaa3333, time:2, onComplete:tweenFunc0 } );
    }
 
    private function process(e:Event) :void
    {
      var posmat:Matrix = new Matrix();
      posmat.translate( mouseX, mouseY );
      _bmpd.draw( _source, posmat, _source.transform.colorTransform );  // マウスの位置に描画.
    }
  }
}

初めてのActionScript 3.0 ―Flashユーザーのためのステップアップガイド

著者/訳者:Rich Shupe Zevan Rosser

出版社:オライリージャパン( 2008-08-25 )

定価:¥ 3,570

Amazon価格:¥ 3,570

大型本 ( 480 ページ )

ISBN-10 : 4873113717

ISBN-13 : 9784873113715


2 Comments

  1. dsk より:

    BitmapData.draw()ファンクションの第三引数にColorTransformを渡せます。
    _bmpd.draw(_source, posmat, _source.transform.colorTransform);

    http://help.adobe.com/ja_JP/AS3LCR/Flash_10.0/flash/display/BitmapData.html#draw()

  2. octech より:

    >dskさん
    なるほど!!第三引数に渡せたのですね!!気づきませんでした・・。有益な情報、ありがとうございます!

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*