AS3:创建 BitmapData 着色副本的最有效方法
AS3: Most efficient way to create a tinted copy of a BitmapData
我有一个 BitmapData
,它是通过 draw
ing DisplayObject
生成的。我想创建一个 BitmapData
的纯白色剪影副本。似乎有两种方法可以这样做:
- 将
ColorTransform
应用到 DisplayObject
,然后得到一个具有相同尺寸 draw
的新 BitmapData
。
- 创建一个新的
BitmapData
,然后 copyPixels
原来的,然后通过 BitmapData.colorTransform
. 应用 ColorTransform
BitmapData
都不会显示在 Bitmap
中,因此不能将 ColorTransform
应用于它。它们会变成八哥 Texture
.
哪种方法效率更高?我自己会 运行 一些基准,但我担心答案将取决于所绘制的 DisplayObject 的大小和复杂性。也许copyPixels
方法在尺寸小的时候会好一些,如果尺寸大的话效果会差一些,而draw
方法在要绘制的DisplayObject简单的时候会好一些,复杂的时候会不好一些。另外,copyPixels 和 BitmapData.colorTransform 方法是在 GPU 上完成的吗?如果是这样,我想事情会朝着有利于他们的方向倾斜。
所以我做了一些基准测试,在绘制方法的最佳场景中,要绘制的 DisplayObject
只是一个彩色矩形,绘制总是比 copyPixels 快大约 33%,无论大小。然后我尝试使用一些内部有很多形状的复杂 DisplayObject
s,在那些情况下,绘制速度慢了 300% 到 400%。所以答案是"it depends"。但我不得不说,使用 draw 方法最多可以提高 33% 的速度,但如果 DisplayObject
很复杂,则存在巨大的负面潜力。
我对 copyPixels/colorTransform 方法和 getPixels/setPixels 方法做了一些额外的测试,值得注意的是 getPixels/setPixels 方法慢了 20 倍!这是我的 copyPixels 方法:
var start_time:int = getTimer();
var s1:S1 = new S1(); //S1 is simply a 100x100 red circle
var bmd1:BitmapData = new BitmapData(s1.width,s1.height,true,0x00000000);
bmd1.drawWithQuality(s1,null,null,null,null,false,StageQuality.HIGH);
var bmd2:BitmapData;
var sourceRect:Rectangle = new Rectangle(0,0,bmd1.width,bmd1.height);
var point00:Point = new Point();
var colorTransform:ColorTransform = new ColorTransform(0,0,0,1,255,255,255,0);
var w:uint = bmd1.width,
h:uint = bmd1.height,
pixelHex:uint,
pixelAlpha:uint;
var ba:ByteArray;
for (var i:uint=0; i<1000; i++) {
bmd2 = new BitmapData(w,h,true,0x00000000);
bmd2.copyPixels(bmd1,sourceRect,point00);
bmd2.colorTransform(sourceRect,colorTransform);
}
trace("execution time: ", getTimer()-start_time); //execution time: 74
这是我的循环 getPixels 方法:
for (var i:uint=0; i<1000; i++) {
ba = bmd1.getPixels(sourceRect);
ba.position = 0;
while (ba.bytesAvailable > 0) {
pixelHex = ba.readUnsignedInt();
pixelAlpha = pixelHex >>> 24;
if (pixelAlpha > 0) {
ba.position -= 4;
ba.writeUnsignedInt((pixelAlpha<<24)|0xffffff);
}
}
ba.position = 0;
bmd2 = new BitmapData(w,h,true,0x00000000);
bmd2.setPixels(sourceRect,ba);
}
trace("execution time: ", getTimer()-start_time); //execution time: 1349
我有一个 BitmapData
,它是通过 draw
ing DisplayObject
生成的。我想创建一个 BitmapData
的纯白色剪影副本。似乎有两种方法可以这样做:
- 将
ColorTransform
应用到DisplayObject
,然后得到一个具有相同尺寸draw
的新BitmapData
。 - 创建一个新的
BitmapData
,然后copyPixels
原来的,然后通过BitmapData.colorTransform
. 应用
ColorTransform
BitmapData
都不会显示在 Bitmap
中,因此不能将 ColorTransform
应用于它。它们会变成八哥 Texture
.
哪种方法效率更高?我自己会 运行 一些基准,但我担心答案将取决于所绘制的 DisplayObject 的大小和复杂性。也许copyPixels
方法在尺寸小的时候会好一些,如果尺寸大的话效果会差一些,而draw
方法在要绘制的DisplayObject简单的时候会好一些,复杂的时候会不好一些。另外,copyPixels 和 BitmapData.colorTransform 方法是在 GPU 上完成的吗?如果是这样,我想事情会朝着有利于他们的方向倾斜。
所以我做了一些基准测试,在绘制方法的最佳场景中,要绘制的 DisplayObject
只是一个彩色矩形,绘制总是比 copyPixels 快大约 33%,无论大小。然后我尝试使用一些内部有很多形状的复杂 DisplayObject
s,在那些情况下,绘制速度慢了 300% 到 400%。所以答案是"it depends"。但我不得不说,使用 draw 方法最多可以提高 33% 的速度,但如果 DisplayObject
很复杂,则存在巨大的负面潜力。
我对 copyPixels/colorTransform 方法和 getPixels/setPixels 方法做了一些额外的测试,值得注意的是 getPixels/setPixels 方法慢了 20 倍!这是我的 copyPixels 方法:
var start_time:int = getTimer();
var s1:S1 = new S1(); //S1 is simply a 100x100 red circle
var bmd1:BitmapData = new BitmapData(s1.width,s1.height,true,0x00000000);
bmd1.drawWithQuality(s1,null,null,null,null,false,StageQuality.HIGH);
var bmd2:BitmapData;
var sourceRect:Rectangle = new Rectangle(0,0,bmd1.width,bmd1.height);
var point00:Point = new Point();
var colorTransform:ColorTransform = new ColorTransform(0,0,0,1,255,255,255,0);
var w:uint = bmd1.width,
h:uint = bmd1.height,
pixelHex:uint,
pixelAlpha:uint;
var ba:ByteArray;
for (var i:uint=0; i<1000; i++) {
bmd2 = new BitmapData(w,h,true,0x00000000);
bmd2.copyPixels(bmd1,sourceRect,point00);
bmd2.colorTransform(sourceRect,colorTransform);
}
trace("execution time: ", getTimer()-start_time); //execution time: 74
这是我的循环 getPixels 方法:
for (var i:uint=0; i<1000; i++) {
ba = bmd1.getPixels(sourceRect);
ba.position = 0;
while (ba.bytesAvailable > 0) {
pixelHex = ba.readUnsignedInt();
pixelAlpha = pixelHex >>> 24;
if (pixelAlpha > 0) {
ba.position -= 4;
ba.writeUnsignedInt((pixelAlpha<<24)|0xffffff);
}
}
ba.position = 0;
bmd2 = new BitmapData(w,h,true,0x00000000);
bmd2.setPixels(sourceRect,ba);
}
trace("execution time: ", getTimer()-start_time); //execution time: 1349