Flashゲームプログラミング講座 for ActionScript3.0

 

ブレンドについて

 


■ブレンドとは?


Photoshop などの、画像編集ツールではおなじみの機能です。
 
 
ブレンドを使用すると、「任意の表示オブジェクト」と「背景」とで、色の合成を行う事ができます。
 
ブレンドの種類として、14 パターンのモードが用意されています。
 
色の演算は、1ピクセルごとに行われ、全ピクセルが変換されます。
 

■ブレンドモード利用時の注意点


ブレンドを使用すると、自動的にビットマップキャッシュが有効になります。
 
ビットマップキャッシュについては、こちらで解説します。
 
■Flash Player 9 以前の場合
 
幅と高さが 2880 ピクセルまでのグラフィックに適用できます。
 
グラフィックのサイズがこの範囲を超えてしまうと、ブレンドが動作しません。
 
■Flash Player 10 の場合
 
幅と高さが 8192 ピクセルまでのグラフィックに適用できますが、総ピクセル数は 16777216 までとなります。(幅が 8192 なら高さは 2048 まで)
 
グラフィックのサイズがこの範囲を超えてしまうと、ブレンドが動作しません。
 
■Flash Player 11 以降の場合
 
ピクセルサイズの制限はありません
 
メモリ不足の場合、ブレンドが動作しません。
 


 

表示オブジェクトにブレンドを適用する

 

サンプルをダウンロード
 


■ブレンドを使用する


ブレンドは、表示オブジェクトであれば利用可能です。
 
表示オブジェクトにブレンドを適用するには、blendMode プロパティを使用します。
 
以下の表にある、定数をセットします。
 
■ブレンドモードの種類
 
定数 文字列 名称
BlendMode.NORMAL "normal" 標準
BlendMode.LAYER "layer" レイヤー
BlendMode.MULTIPLY "multiply" 乗算
BlendMode.SCREEN "screen" スクリーン
BlendMode.LIGHTEN "lighten" 比較(明)
BlendMode.DARKEN "darken" 比較(暗)
BlendMode.DIFFERENCE "difference" 差の絶対値
BlendMode.ADD "add" 加算
BlendMode.SUBTRACT "subtract" 減算
BlendMode.INVERT "invert" 反転
BlendMode.ALPHA "alpha" アルファ
BlendMode.ERASE "erase" 消去
BlendMode.OVERLAY "overlay" オーバーレイ
BlendMode.HARDLIGHT "hardlight" ハードライト
BlendMode.SHADER "shader" シェーダー (Flash 10 以降)
 
■使用例
 
表示オブジェクト mc を加算でブレンドする

import flash.display.BlendMode;

mc.blendMode = BlendMode.ADD;
 
表示オブジェクト mc を減算でブレンドする

import flash.display.BlendMode;

mc.blendMode = BlendMode.SUBTRACT;
 


 

ブレンドの種類について

 
 


■標準 (BlendMode.NORMAL)

 
ブレンドを使用していない状態です。通常の表示です。
 
素材 結果
 

■レイヤー (BlendMode.LAYER)

 
複数のレイヤーを持つ表示オブジェクトを半透明にすると、以下のように表示されます。
 
レイヤーごとに半透明が適用されるので、重なる部分が透けて表示されます
 
素材 半透明を適用
 
ブレンドで「レイヤー」を適用すると、描画結果に対して半透明がかかるようになります。
 
重なる部分が透けて表示される事はありません
 
素材 半透明を適用
 

■乗算 (BlendMode.MULTIPLY)

 
シャドウや深度効果に使用します。
 
黒色に近づけるのに最適です。
 
グラフィックが黒色であるほど、結果は黒色に近づきます。
 
グラフィックが白色であるほど、結果に影響はありません。
 
背景 ソース 結果
 
乗算は、以下の計算が行われます。
 
各カラーは、「0 ~ 255」までありますが、この値を「0.0 ~ 1.0」までの小数値と考えます。
 
「背景」と「小数値」を乗算して結果を出力します。
 
乗算の変換式(透過成分は除外)

新しい赤色 = (ソースの赤色 / 255) * 背景の赤色;
新しい緑色 = (ソースの緑色 / 255) * 背景の緑色;
新しい青色 = (ソースの青色 / 255) * 背景の青色;
 

■スクリーン (BlendMode.SCREEN)

 
ハイライトなどに使用します。
 
白色に近づけるのに最適です。
 
グラフィックが白色であるほど、結果は白色に近づきます。
 
グラフィックが黒色であるほど、結果に影響はありません。
 
背景 ソース 結果
 
スクリーンは、以下の計算が行われます。
 
スクリーンの変換式(透過成分は除外)

新しい赤色 = 255 - ((255 - ソースの赤色) / 255) * (255 - 背景の赤色);
新しい緑色 = 255 - ((255 - ソースの緑色) / 255) * (255 - 背景の緑色);
新しい青色 = 255 - ((255 - ソースの青色) / 255) * (255 - 背景の青色);
 
スクリーンの変換式(最適化)(透過成分は除外)

新しい赤色 = ソースの赤色 + 背景の赤色 - ソースの赤色 * 背景の赤色 / 255;
新しい緑色 = ソースの赤色 + 背景の赤色 - ソースの赤色 * 背景の赤色 / 255;
新しい青色 = ソースの赤色 + 背景の赤色 - ソースの赤色 * 背景の赤色 / 255;
 

■比較(明) (BlendMode.LIGHTEN)

 
背景とソースのカラーを比較して、大きい(明るい)方を採用して出力します。
 
背景 ソース 結果
 
比較(明)は、以下の計算が行われます。
 
比較(明)の変換式(透過成分は除外)

新しい赤色 = (ソースの赤色 > 背景の赤色) ? ソースの赤色 : 背景の赤色;
新しい緑色 = (ソースの緑色 > 背景の緑色) ? ソースの緑色 : 背景の緑色;
新しい青色 = (ソースの青色 > 背景の青色) ? ソースの青色 : 背景の青色;
 

■比較(暗) (BlendMode.DARKEN)

 
背景とソースのカラーを比較して、小さい(暗い)方を採用して出力します。
 
背景 ソース 結果
 
比較(暗)は、以下の計算が行われます。
 
比較(明)の変換式(透過成分は除外)

新しい赤色 = (ソースの赤色 < 背景の赤色) ? ソースの赤色 : 背景の赤色;
新しい緑色 = (ソースの緑色 < 背景の緑色) ? ソースの緑色 : 背景の緑色;
新しい青色 = (ソースの青色 < 背景の青色) ? ソースの青色 : 背景の青色;
 

■差の絶対値 (BlendMode.DIFFERENCE)

 
背景とソースのカラーを比較します。
 
大きい値から小さい値を減算して結果を出力します。
 
背景 ソース 結果
 
差の絶対値は、以下の計算が行われます。
 
差の絶対値の変換式

新しい赤色 = (ソースの赤色 > 背景の赤色) ? (ソースの赤色 - 背景の赤色) : (背景の赤色 - ソースの赤色);
新しい緑色 = (ソースの緑色 > 背景の緑色) ? (ソースの緑色 - 背景の緑色) : (背景の緑色 - ソースの緑色);
新しい青色 = (ソースの青色 > 背景の青色) ? (ソースの青色 - 背景の青色) : (背景の青色 - ソースの青色);
 

■加算 (BlendMode.ADD)

 
光源の効果などに利用します。
 
白飛びするほど明るい表現に最適です。
 
グラフィックが白色であるほど、結果は白色に近づきます。
 
グラフィックが黒色であるほど、結果に影響はありません。
 
背景 ソース 結果
 
加算は、以下の計算が行われます。
 
「背景」と「ソース」のカラーを加算します。
 
計算した結果 255 より大きくなる場合は、255 となります。
 
加算の変換式(透過成分は除外)

新しい赤色 = ソースの赤色 + 背景の赤色;
新しい緑色 = ソースの緑色 + 背景の緑色;
新しい青色 = ソースの青色 + 背景の青色;

if(新しい赤色 > 255)	新しい赤色 = 255;
if(新しい緑色 > 255)	新しい緑色 = 255;
if(新しい青色 > 255)	新しい青色 = 255;
 

■減算 (BlendMode.SUBTRACT)

 
黒つぶれするほど暗い表現に最適です。
 
ソースのグラフィックが黒色であるほど、結果に影響はありません。
 
ソースのグラフィックが白色であるほど、結果は黒色に近づきます。
 
背景 ソース 結果
 
減算は、以下の計算が行われます。
 
「背景のカラー」から「ソースのカラー」を減算します。
 
計算した結果 0 より小さくなる場合は、0 となります。
 
加算の変換式(透過成分は除外)

新しい赤色 = 背景の赤色 - ソースの赤色;
新しい緑色 = 背景の緑色 - ソースの緑色;
新しい青色 = 背景の青色 - ソースの青色;

if(新しい赤色 < 0)	新しい赤色 = 0;
if(新しい緑色 < 0)	新しい緑色 = 0;
if(新しい青色 < 0)	新しい青色 = 0;
 

■反転 (BlendMode.INVERT)

 
背景カラーを反転して結果を出力します。
 
背景 ソース 結果
 
反転は、以下の計算が行われます。
 
加算の変換式(透過成分は除外)

新しい赤色 = (255 - 背景の赤色);
新しい緑色 = (255 - 背景の緑色);
新しい青色 = (255 - 背景の青色);
 

■アルファ (BlendMode.ALPHA)

 
アルファを動作させるには、親の表示オブジェクトのブレンドモードが、「BlendMode.LAYER (レイヤー)」である必要があります。
 
背景カラーの 赤 緑 青 成分はそのままで、透過成分はソースから出力します。
 
背景 ソース 結果
 
アルファは、以下の計算が行われます。
 
アルファの変換式(背景の透過成分は除外)

新しい赤色 = 背景の赤色;
新しい緑色 = 背景の緑色;
新しい青色 = 背景の青色;
新しい透過色 = ソースの透過色;
 

■消去 (BlendMode.ERASE)

 
消去を動作させるには、親の表示オブジェクトのブレンドモードが、「BlendMode.LAYER (レイヤー)」である必要があります。
 
背景カラーの 赤 緑 青 成分はそのままで、透過成分はソースから反転して出力します。
 
背景 ソース 結果
 
消去は、以下の計算が行われます。
 
消去の変換式(背景の透過成分は除外)

新しい赤色 = 背景の赤色;
新しい緑色 = 背景の緑色;
新しい青色 = 背景の青色;
新しい透過色 = 255 - ソースの透過色;
 

■オーバーレイ (BlendMode.OVERLAY)

 
背景のカラーが 127 以下であれば、乗算として動作します。
 
背景のカラーが 129 以上であれば、スクリーンとして動作します。
 
背景のカラーが 128 であるほど、ソースのカラーがそのまま出力されます。
 
背景のグラフィックが白色であるほど、結果は白色に近づきます。
 
背景のグラフィックが黒色であるほど、結果は黒色に近づきます。
 
背景 ソース 結果
 
オーバーレイは、以下の計算が行われます。
 
オーバーレイの変換式(透過成分は除外)

if(背景の赤色 > 129)      新しい赤色 = -255 + 2 * (ソースの赤色 + 背景の赤色) - ソースの赤色 * 背景の赤色 / 127.5;
else if(背景の赤色 < 127) 新しい赤色 = (ソースの赤色 / 127.5) * 背景の赤色;
else                      新しい赤色 = ソースの赤色;

if(背景の緑色 > 129)      新しい緑色 = -255 + 2 * (ソースの緑色 + 背景の緑色) - ソースの緑色 * 背景の緑色 / 127.5;
else if(背景の緑色 < 127) 新しい緑色 = (ソースの緑色 / 127.5) * 背景の緑色;
else                      新しい緑色 = ソースの緑色;

if(背景の青色 > 129)      新しい青色 = -255 + 2 * (ソースの青色 + 背景の青色) - ソースの青色 * 背景の青色 / 127.5;
else if(背景の青色 < 127) 新しい青色 = (ソースの青色 / 127.5) * 背景の青色;
else                      新しい青色 = ソースの青色;
 

■ハードライト (BlendMode.HARDLIGHT)

 
ソースのカラーが 127 以下であれば、乗算として動作します。
 
ソースのカラーが 129 以上であれば、スクリーンとして動作します。
 
ソースのカラーが 128 であるほど、背景のカラーがそのまま出力されます。
 
ソースのグラフィックが白色であるほど、結果は白色に近づきます。
 
ソースのグラフィックが黒色であるほど、結果は黒色に近づきます。
 
背景 ソース 結果
 
ハードライトは、以下の計算が行われます。
 
ハードライトの変換式(透過成分は除外)

if(ソースの赤色 > 129)      新しい赤色 = -255 + 2 * (ソースの赤色 + 背景の赤色) - ソースの赤色 * 背景の赤色 / 127.5;
else if(ソースの赤色 < 127) 新しい赤色 = (ソースの赤色 / 127.5) * 背景の赤色;
else                        新しい赤色 = 背景の赤色;

if(ソースの緑色 > 129)      新しい緑色 = -255 + 2 * (ソースの緑色 + 背景の緑色) - ソースの緑色 * 背景の緑色 / 127.5;
else if(ソースの緑色 < 127) 新しい緑色 = (ソースの緑色 / 127.5) * 背景の緑色;
else                        新しい緑色 = 背景の緑色;

if(ソースの青色 > 129)      新しい青色 = -255 + 2 * (ソースの青色 + 背景の青色) - ソースの青色 * 背景の青色 / 127.5;
else if(ソースの青色 < 127) 新しい青色 = (ソースの青色 / 127.5) * 背景の青色;
else                        新しい青色 = 背景の青色;
 

■シェーダー (BlendMode.SHADER) (Flash 10 以降)

 
■ Shader を指定する
 
別途、blendShader プロパティを使用します。
 
このプロパティに、Shader オブジェクトを渡します。
 
このプロパティにアクセスすると、blendMode も連動して変化します。
 
■ Pixel Bender での実装について
 
入力変数(ビットマップ)は、最低でも2つ宣言します。
 
1枚目の入力ビットマップは、背景側です。
 
2枚目の入力ビットマップは、前面側です。
 
入力変数は image4 型、出力変数は、pixel4 型で統一します。
 
■使用例(Pixel Bender 側のコード)
 
「1枚目のイメージ」「2枚目のイメージ」間をマージする(ブレンド用)

<languageVersion : 1.0;>

// ------------------------------------------------------------
// カーネルを宣言
// ------------------------------------------------------------
kernel MyKernel < namespace:""; vendor:""; version:1; > {

	// ------------------------------------------------------------
	// 入力変数の宣言(ビットマップ)
	// ------------------------------------------------------------
	// 1枚目の入力イメージ(背景グラフィック)
	input image4 src_back;
	// 2枚目の入力イメージ(前面グラフィック)
	input image4 src_front;

	// ------------------------------------------------------------
	// 出力変数の宣言(ピクセルカラー)
	// ------------------------------------------------------------
	output pixel4 dst;

	// ------------------------------------------------------------
	// パラメータ変数の宣言
	// ------------------------------------------------------------
	parameter float marge
	<
		minValue     : 0.0;
		maxValue     : 1.0;
		stepInterval : 0.01;
		defaultValue : 0.25;
	>;

	// ------------------------------------------------------------
	// ピクセルごとに実行される関数
	// ------------------------------------------------------------
	void evaluatePixel() {

		// 現在のピクセル位置を取得する
		float2 pos = outCoord();

		// 位置を指定して、画像からピクセルカラーを取得する(ニアレストネイバー)
		pixel4 color_b = sampleNearest(src_back  , pos);
		pixel4 color_f = sampleNearest(src_front , pos);

		// ピクセルカラーを出力する
		color_f.rgb = (color_f.rgb - color_b.rgb) * color_f.a + color_b.rgb;
		color_f.a   = 1.0;
		dst = (color_f - color_b) * marge + color_b;
	}
}
 
■使用例(Flash 側のコード)
 
シェーダーを渡して、ブレンドを動作させる

import flash.utils.ByteArray;
import flash.display.Shader;
import flash.display.ShaderData;
import flash.display.ShaderParameter;
import flash.display.Shape;
import flash.display.Graphics;
import flash.display.GradientType;
import flash.geom.Matrix;

// ------------------------------------------------------------
// 埋め込みアセットクラス
// ------------------------------------------------------------
[Embed( source="./blend.pbj" , mimeType="application/octet-stream" )]
var MyByteCode:Class;

// ------------------------------------------------------------
// 埋め込んだファイルから、ByteArray オブジェクトを作成する (自作クラス "MyByteCode" )
// ------------------------------------------------------------
var byte_code:ByteArray = new MyByteCode();

// ------------------------------------------------------------
// Shader オブジェクトを作成する
// ------------------------------------------------------------
var shader_obj:Shader = new Shader(byte_code);

// ------------------------------------------------------------
// パラメータに値を渡す
// ------------------------------------------------------------
// ShaderData オブジェクトを取得する
var shader_data:ShaderData = shader_obj.data;

// ShaderParameter オブジェクトを取得する
var parameter_marge:ShaderParameter = (shader_data["marge"]) as ShaderParameter;

// 値情報を渡す
if(parameter_marge){
	parameter_marge.value = [ 0.8 ];
}

// ------------------------------------------------------------
// Shape オブジェクトを作成する
// ------------------------------------------------------------
var shape:Shape = (function():Shape{

	// Shape オブジェクトを作成
	var shape:Shape = new Shape();

	// Shape に矩形を描画
	var g:Graphics = shape.graphics;
	var mtx:Matrix = new Matrix(256/1638.4 , 0 , 0 , 256/1638.4 , 128 , 128);
	g.beginGradientFill ( GradientType.RADIAL , [0xff0000,0x00ff00,0x0000ff] , [1.0,0.5,0.0] , [0,128,255] , mtx );
	g.moveTo (   0 ,   0 );
	g.lineTo (   0 , 256 );
	g.lineTo ( 256 , 256 );
	g.lineTo ( 256 ,   0 );
	g.endFill();

	return shape;
})();

// ステージに配置する
stage.addChild(shape);

// ------------------------------------------------------------
// シェーダーを渡して、ブレンドを動作させる
// ------------------------------------------------------------
shape.blendShader = shader_obj;