AS3 - проблема альфа-прозрачности края bitmapData - PullRequest
3 голосов
/ 06 марта 2011

Я создаю приложение для рисования в as3, и у меня проблемы с закрашенными или размытыми краями на кисти.Я использую bitmapData.draw () для рисования кисти, но я вижу более темные цветные области по краям при медленном рисовании.

Я пробовал многочисленные варианты, включая установку для всех отображаемых объектов cacheAsBitmap = true, использование copyPixels вместо рисования, фильтра размытия и градиентной заливки ... все безрезультатно.

Следующий класс иллюстрирует мою проблему.Я включил метод solid (), который работает правильно, но без закрашенных краев, метод градиента () и метод filter (), которые оба показывают ту же проблему, а также onMove2 использует copyPixels () и снова имеет ту же проблему.

Что я могу сделать, чтобы это исправить ?!Я действительно не хочу использовать пиксельные шейдеры для чего-то такого простого ...

package test {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;

    public class Sucks extends Sprite {

        private var brush:Sprite;
        private var brushMap:BitmapData;
        private var bmd:BitmapData;
        private var radius:Number = 50;
        private var color:uint = 0x990000;


        public function Sucks() {
            brush = new Sprite();
            brushMap = new BitmapData(radius*2, radius*2, true, 0x00ffffff);
            bmd = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x0);
            var bmp:Bitmap = new Bitmap(bmd, PixelSnapping.ALWAYS, true);
            addChild(bmp);

            //solid();         
            gradient();
            //filter();
            brushMap.draw(brush, new Matrix(1, 0, 0, 1, radius, radius));

            stage.addEventListener(Event.ENTER_FRAME, onMove);
        }

        private function solid():void {
            brush.graphics.beginFill(color, 1);
            brush.graphics.drawCircle(0, 0, radius);
            brush.graphics.endFill();
        }

        private function gradient():void {
            var m:Matrix = new Matrix();
            m.createGradientBox(radius*2, radius*2, 0, -radius, -radius);
            brush.graphics.beginGradientFill(GradientType.RADIAL, [color, color], [1, 0], [0, 250], m);
            brush.graphics.drawCircle(0, 0, radius);
            brush.graphics.endFill();
        }

        private function filter():void {
            solid();
            brush.filters = [new BlurFilter(8, 8, 3)];
        }

        private function onMove(e:Event):void {
            var mp:Matrix = new Matrix();
            mp.tx = mouseX;
            mp.ty = mouseY;
            bmd.draw(brush, mp);
            //bmd.applyFilter(bmd, new Rectangle(0, 0, stage.stageWidth, stage.stageHeight), new Point(), new BlurFilter(2, 2, 3));
        }

        private function onMove2(e:Event):void {
            bmd.copyPixels(brushMap, new Rectangle(0, 0, radius*2, radius*2), new Point(mouseX-radius, mouseY-radius), null, null, true);
        }

    }

}

Ответы [ 6 ]

2 голосов
/ 25 июня 2012

Ваша проблема вызвана тем, что Flash использует предварительно умноженную альфа.Обычно это не большая проблема, но она становится очень очевидной, если у вас есть пиксельные значения с очень низкими альфа-значениями, которые, к сожалению, очень распространены, когда вы используете размытую кисть с мягкими перьями.

Предварительное умножение приводит к потере информации в пикселях - и когда у вас низкие альфа-значения, значения цвета эффективно округляются, что при медленном рисовании в приложении и вытягивании одних и тех же пикселейСнова и снова друг с другом область будет становиться все темнее и темнее.

Для получения более подробной информации о проблеме предварительного умножения проверьте мой старый пост: http://www.quasimondo.com/archives/000665.php

Там нет ничегоВы можете делать это, за исключением случаев, когда вы обрабатываете альфа-канал и канал rgb отдельно.Но тогда вам также придется выполнять все композиции самостоятельно, что не является тривиальной задачей и может слишком сильно замедлить работу вашего приложения.

1 голос
/ 06 марта 2011

Я удивлен, что BlurFilter не сработал.Мне повезло с этим в прошлом.Возможно, стоит поиграться с Flex Filter Explorer , чтобы посмотреть, нужно ли настроить параметры.

Еще одна вещь, которую вы можете попробовать, это нарисовать несколько концентрических кругов с прозрачностью и уменьшением радиуса, чтобы имитировать размытые края..

0 голосов
/ 31 мая 2012

Изменить свойство кисти cacheAsBitmap на true.

brush.cacheAsBitmap = true;

спрайт будет храниться в памяти как растровое изображение, а не как вектор, поэтому при рисовании он будет точнее отображать пиксели.

0 голосов
/ 08 марта 2011

Не знаю, связано ли это с этим, но вы устанавливаете прозрачность, но ваши BitmapData не прозрачны.

brushMap = new BitmapData(radius*2, radius*2, true, 0x00ffffff);

К

brushMap = new BitmapData(radius*2, radius*2, true, 0);

Также попробуйте изменить значение PixelSnapping. ВСЕГДА значение на PixelSnapping. НИКОГДА , но, думаю, вы уже это попробовали.

0 голосов
/ 07 марта 2011

Я считаю, что это больше проблема с enterframe, чем с вашей логикой.Я заметил, что если вы измените обработчик enter_frame на обработчик mouse_move, он будет работать намного лучше.Проблема с использованием enter_frame заключается в том, что вы рисуете один и тот же элемент снова и снова - который, естественно, имеет свои собственные артефакты - поэтому после 600 или около того, он начнет показывать эти артефакты.Я думаю, что было бы лучше использовать mouse_move.

Если вам нужно использовать enter_frame, я бы предложил перечислить как enter_frame и mouse_move, так и значительно уменьшить непрозрачность при рисовании для enter_frames.

Это хорошо сработало для меня:

stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
0 голосов
/ 07 марта 2011

Если цвет кисти сплошной, вы также можете попробовать использовать фильтр Glow, с точными настройками этого можно достичь

...