将着色器滤镜应用于BitmapData对象会忽略传递的矩形 - 如何正确应用着色器滤镜?

Ves*_*per 6 shader actionscript-3

我有以下代码,仅用于测试,因为这是我想要指出的一种错误:

        _shader = new Shader(new TheShader() as ByteArray);
        _shader.data.width.value = [64.0];
        _shader.data.height.value = [64.0];
        _shaderFilter = new ShaderFilter(_shader);
        _sequence = new Vector.<BitmapData>();
        var smallBD:BitmapData;
        var i:int;
        _delta = new Point();
        var megabase:BitmapData = new TheBitmap().bitmapData;
        var _rect:Rectangle = new Rectangle(0, 0, 64, 64);
        for (i = 0; i < 64; i++) {
            smallBD = new BitmapData(64, 64, true, 0x00808080);
            //_rect.x = i;
            _rect.y = i;
            smallBD.applyFilter(megabase, _rect, _delta, _shaderFilter);
            _sequence.push(smallBD);
        }
Run Code Online (Sandbox Code Playgroud)

然后我循环通过_sequence以查看更改矩形是否实际上做了什么.如果_shaderFilter实际上是着色器过滤器,它什么都不做.使用任何内置Flash过滤器进行测试都可以正常工作,但是使用ShaderFilter时,它有时就像提供的矩形明显是sourceBitmapData.rect一样,无论源位图是什么,有时它的行为就像没有传递数据一样,边界是位于奇怪的位置 - 大小为512x384的位图,传递到着色器的区域边缘显然位于(256,192)或位图的中心.到目前为止,我只能实现一个解决方法,即首先copyPixels()所需的区域,然后applyFilter()到位.有人可以证明这是一个错误而不是我做错了吗?

PS:我使用FlashDevelop,项目目标是Flash Player 10.3,我不知道FP11是否修复了这个问题.

Dav*_*ave 1

好吧,遗憾的是我无法告诉你如何解决这个问题,但我可以确认这不是你的错!

问题似乎是 FlashsourceRect在使用自定义着色器时完全忽略了这一点。起初我认为它可能会将这些值传递给着色器中未记录的参数,但后来我注意到输出位图的每个像素都会发生变化,即使 更sourceRect小或destPoint非零。而且似乎没有inCoord()匹配的函数outCoord(),因此看起来这不是开发人员预期的用途!

我可以提供一个建议;不要将 ROI 复制到新BitmapData对象,而是float2 offset向着色器添加一个参数,并按该值移动所有像素查找。它将节省一些处理。

这是我用来确认行为的简化测试用例:

着色器测试.as:

package {
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Shader;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.filters.ShaderFilter;

    final public class ShaderTest extends Sprite {
        [Embed(source="test.pbj",mimeType="application/octet-stream")]
        private static const sCopy : Class;

        final private function R( x, y, w, h ) : Rectangle {
            return new Rectangle( x, y, w, h );
        }
        final public function ShaderTest( ) {
            super( );
            var
            s  : Shader = new Shader( new sCopy( ) ),
            f  : ShaderFilter = new ShaderFilter( s ),
            d1 : BitmapData = new BitmapData( 256, 256, false, 0 ),
            d2 : BitmapData = new BitmapData( 128, 128, false ),
            b1 : Bitmap = new Bitmap( d1 ),
            b2 : Bitmap = new Bitmap( d2 ),
            w  : Rectangle = R( 16, 16, 64, 64 );
            b2.x = 274;
            addChild( b1 );
            addChild( b2 );

            for( var i : int = 0; i < 8; ++ i ) {
                for( var j : int = 0; j < 8; ++ j ) {
                    d1.fillRect( R( i * 32 + 1, j * 32 + 1, 30, 30 ), (((i + j) & 1) * 0x00FF00) | (i << 21) | (j << 5) );
                }
            }
            d2.applyFilter( d1, w, new Point( 10, 10 ), f );
            d1.fillRect( R( w.x, w.y, 1, w.height ), 0xFF0000 );
            d1.fillRect( R( w.x, w.y, w.width, 1 ), 0xFF0000 );
            d1.fillRect( R( w.x, w.y + w.height - 1, w.width, 1 ), 0xFF0000 );
            d1.fillRect( R( w.x + w.width - 1, w.y, 1, w.height ), 0xFF0000 );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

测试.pbk:

<languageVersion:1.0;>

kernel bugtest <namespace:"Me";vendor:"Me";version:1;>{
    input image4 src;
    output pixel4 dst;
    void evaluatePixel(){
        dst = sampleNearest(src,outCoord());
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

输出截图

(右侧的小方块使用着色器从大方块复制。红色框显示sourceRectdestPoint是 (10,10)。尽管有这两个设置,但它实际上渲染了整个位图)