如何制作涂抹工具算法?
How to make smudge tool algorithm?
我正在为涂抹工具创建一个算法,但它必须逐个像素地完成。
涂抹工具的概念很简单
onMouseMove - 使用画笔模板将旧点的像素复制到新点
我在按位运算中遇到问题。该算法未正确绘制像素。(我是从头开始创建此算法,因此可能会出现一些愚蠢的错误)
diameter = brush.size;
_bitData = _canvas.bitmapData;
_bitwidth = _bitData.rect.width;//width of canvas
_bitVector = _bitData.getVector();//1d vector of uint
_brushVector = brush.bitmapData.getVector();//1d vector of uint
brushVectorIndex = 0;
for(yIndex = 0; yIndex < diameter; yIndex++)
{
for(xIndex = 0; xIndex < diameter; xIndex++)
{
yCor = yIndex + oldY;
xCor = xIndex + oldX;
if(_bitData.rect.contains(xCor,yCor))
{
bitVectorIndex_old = (yCor * _bitWidth) + xCor;
bitVectorIndex_new = ((Y+yIndex) * _bitWidth) + X+xIndex;
//Creating alpha map of brush and old mouse point's pixel
brushPixelAlpha = (_brushVector[brushVectorIndex] & _bitVector[bitVectorIndex_old] & 0xFF000000);
//Adding colors to the aplha map according to old mouse point's pixel
brushPixel = brushPixelAlpha | (_bitVector[bitVectorIndex_old] & 0x00FFFFFF);
//Create alpha map for new pixel
pixelAlpha = ((brushPixel | _bitVector[bitVectorIndex_new]) & 0xFF000000)
//Adding color to pixel alpha map using brush's stamp
pixel = pixelAlpha | (brushPixel & 0x00FFFFFF);
_bitVector[bitVectorIndex_new] = pixel;
}
brushVectorIndex++;
}
}
_bitData.setVector(_bitVector);
如果您能建议如何优化这段代码,那也会很有帮助,因为这段代码每帧 运行 10000 秒。
编辑:制定了一个有效的解决方案。上面的位运算是非常错误的。下面的代码没有优化,但可以工作。
private function smudgeIt(brush:uint,oldMouse:uint,newMouse:uint):uint
{
var pixel:uint;
var bA:uint = (brush>>24)&0xff;
var oA:uint = (oldMouse>>24)&0xff;
var oldAlpha:uint = oA<bA?oA:bA;
var rOld:uint,gOld:uint,bOld:uint;
var rNew:uint,gNew:uint,bNew:uint;
rOld = (oldMouse >>16) & 0xff;
gOld = (oldMouse >>8) & 0xff;
bOld = (oldMouse & 0xff);
rNew = (newMouse >>16) & 0xff;
gNew = (newMouse >>8) & 0xff;
bNew = (newMouse & 0xff);
var newAlpha:uint = ((newMouse>>24)&0xff)-oldAlpha;
newAlpha = newAlpha<0?0:newAlpha;
rNew = (rNew*newAlpha + rOld*oldAlpha)/255;
gNew = (gNew*newAlpha + gOld*oldAlpha)/255;
bNew = (bNew*newAlpha + bOld*oldAlpha)/255;
var finalAlpha:uint = ((newMouse >> 24) & 0xff)+oldAlpha;
finalAlpha = finalAlpha>255?255:finalAlpha;
pixel = finalAlpha<<24 | rNew << 16 | gNew << 8 | bNew;
return pixel;
}
Alpha 通道的含义有些混淆。
如果用旧的和刷子的混合物覆盖新位置的 RGB 通道,您显示的代码:
RGB_new = RGB_old | RGB_brush;
alpha_new = alpha_new | (alpha_old & alpha_brush);
这不是你想要的,你丢失了新位置的所有颜色信息(因此没有混合它),更糟糕的是,如果画笔真的有RGB信息,你会饱和所有通道直到你获得纯白.
让我们暂时忘掉 alpha 通道,让我们从普通的不透明 RGB 形式开始。
正如您所描述的那样,画笔作为位掩码运行:如果某个位设置为 1,则从旧位置获取像素,否则将像素从新位置保留。假设一个8位mask8 = mask1*16rFF
),应用于1个像素的1-8位通道:
R_new = (R_new & (256-mask8)) | (R_old & mask8);
现在假设一个 24 位掩码(8 位掩码重复 3 次,(mask8<<16)|(mask8<<8)|mask8
或 mask8*0x10100
或 mask1*16rFFFFFF
),这可以同时应用于 3 个通道:
RGB_new = (RGB_new & (~mask24)) | (R_old & mask24);
如果你想用 alpha 通道使事情复杂化(这是某种逐渐透明而不是全有或全无),那么你将不得不描述如何混合新旧位,但我认为然后画笔将成为 alpha 通道本身。
一种经典算法(alpha 混合)具有 R_new = R_new * (1-alpha) + R_old * alpha
,其中 alpha 是 0 到 1 之间的分数。它可以在 alpha 介于 0(透明)和 0xFF(不透明)之间的整数算法中执行:
R_new = (R_new * (255-alpha) + R_old*alpha) / 255;
通过一些小技巧,您可以在 R_B 通道和 A_G_ 通道上进行多路复用操作。您可以在此站点上找到其中一些 alpha 混合位技巧。我确实将其中一些应用于 Squeak VM http://bugs.squeak.org/view.php?id=7803, after all BitBlt operations where invented by Dan Ingalls in the Smalltalk context https://en.wikipedia.org/wiki/Bit_blit,所以我们必须回馈凯撒。
在这里,我们没有考虑新旧像素的固有透明度,我们可以定义更复杂的操作来考虑这些,但这意味着什么?如果它们是透明的,我们看到后面是什么?
我正在为涂抹工具创建一个算法,但它必须逐个像素地完成。
涂抹工具的概念很简单
onMouseMove - 使用画笔模板将旧点的像素复制到新点
我在按位运算中遇到问题。该算法未正确绘制像素。(我是从头开始创建此算法,因此可能会出现一些愚蠢的错误)
diameter = brush.size;
_bitData = _canvas.bitmapData;
_bitwidth = _bitData.rect.width;//width of canvas
_bitVector = _bitData.getVector();//1d vector of uint
_brushVector = brush.bitmapData.getVector();//1d vector of uint
brushVectorIndex = 0;
for(yIndex = 0; yIndex < diameter; yIndex++)
{
for(xIndex = 0; xIndex < diameter; xIndex++)
{
yCor = yIndex + oldY;
xCor = xIndex + oldX;
if(_bitData.rect.contains(xCor,yCor))
{
bitVectorIndex_old = (yCor * _bitWidth) + xCor;
bitVectorIndex_new = ((Y+yIndex) * _bitWidth) + X+xIndex;
//Creating alpha map of brush and old mouse point's pixel
brushPixelAlpha = (_brushVector[brushVectorIndex] & _bitVector[bitVectorIndex_old] & 0xFF000000);
//Adding colors to the aplha map according to old mouse point's pixel
brushPixel = brushPixelAlpha | (_bitVector[bitVectorIndex_old] & 0x00FFFFFF);
//Create alpha map for new pixel
pixelAlpha = ((brushPixel | _bitVector[bitVectorIndex_new]) & 0xFF000000)
//Adding color to pixel alpha map using brush's stamp
pixel = pixelAlpha | (brushPixel & 0x00FFFFFF);
_bitVector[bitVectorIndex_new] = pixel;
}
brushVectorIndex++;
}
}
_bitData.setVector(_bitVector);
如果您能建议如何优化这段代码,那也会很有帮助,因为这段代码每帧 运行 10000 秒。
编辑:制定了一个有效的解决方案。上面的位运算是非常错误的。下面的代码没有优化,但可以工作。
private function smudgeIt(brush:uint,oldMouse:uint,newMouse:uint):uint
{
var pixel:uint;
var bA:uint = (brush>>24)&0xff;
var oA:uint = (oldMouse>>24)&0xff;
var oldAlpha:uint = oA<bA?oA:bA;
var rOld:uint,gOld:uint,bOld:uint;
var rNew:uint,gNew:uint,bNew:uint;
rOld = (oldMouse >>16) & 0xff;
gOld = (oldMouse >>8) & 0xff;
bOld = (oldMouse & 0xff);
rNew = (newMouse >>16) & 0xff;
gNew = (newMouse >>8) & 0xff;
bNew = (newMouse & 0xff);
var newAlpha:uint = ((newMouse>>24)&0xff)-oldAlpha;
newAlpha = newAlpha<0?0:newAlpha;
rNew = (rNew*newAlpha + rOld*oldAlpha)/255;
gNew = (gNew*newAlpha + gOld*oldAlpha)/255;
bNew = (bNew*newAlpha + bOld*oldAlpha)/255;
var finalAlpha:uint = ((newMouse >> 24) & 0xff)+oldAlpha;
finalAlpha = finalAlpha>255?255:finalAlpha;
pixel = finalAlpha<<24 | rNew << 16 | gNew << 8 | bNew;
return pixel;
}
Alpha 通道的含义有些混淆。
如果用旧的和刷子的混合物覆盖新位置的 RGB 通道,您显示的代码:
RGB_new = RGB_old | RGB_brush;
alpha_new = alpha_new | (alpha_old & alpha_brush);
这不是你想要的,你丢失了新位置的所有颜色信息(因此没有混合它),更糟糕的是,如果画笔真的有RGB信息,你会饱和所有通道直到你获得纯白.
让我们暂时忘掉 alpha 通道,让我们从普通的不透明 RGB 形式开始。
正如您所描述的那样,画笔作为位掩码运行:如果某个位设置为 1,则从旧位置获取像素,否则将像素从新位置保留。假设一个8位mask8 = mask1*16rFF
),应用于1个像素的1-8位通道:
R_new = (R_new & (256-mask8)) | (R_old & mask8);
现在假设一个 24 位掩码(8 位掩码重复 3 次,(mask8<<16)|(mask8<<8)|mask8
或 mask8*0x10100
或 mask1*16rFFFFFF
),这可以同时应用于 3 个通道:
RGB_new = (RGB_new & (~mask24)) | (R_old & mask24);
如果你想用 alpha 通道使事情复杂化(这是某种逐渐透明而不是全有或全无),那么你将不得不描述如何混合新旧位,但我认为然后画笔将成为 alpha 通道本身。
一种经典算法(alpha 混合)具有 R_new = R_new * (1-alpha) + R_old * alpha
,其中 alpha 是 0 到 1 之间的分数。它可以在 alpha 介于 0(透明)和 0xFF(不透明)之间的整数算法中执行:
R_new = (R_new * (255-alpha) + R_old*alpha) / 255;
通过一些小技巧,您可以在 R_B 通道和 A_G_ 通道上进行多路复用操作。您可以在此站点上找到其中一些 alpha 混合位技巧。我确实将其中一些应用于 Squeak VM http://bugs.squeak.org/view.php?id=7803, after all BitBlt operations where invented by Dan Ingalls in the Smalltalk context https://en.wikipedia.org/wiki/Bit_blit,所以我们必须回馈凯撒。
在这里,我们没有考虑新旧像素的固有透明度,我们可以定义更复杂的操作来考虑这些,但这意味着什么?如果它们是透明的,我们看到后面是什么?