StarlingGraphics / Starling-Extension-Graphics

flash.display.Graphics style extension for the Starling Flash GPU rendering framework
https://github.com/StarlingGraphics/Starling-Extension-Graphics/wiki
MIT License
282 stars 89 forks source link

Stroke with antialiasing has black edges #131

Closed alexeevilya closed 9 years ago

alexeevilya commented 9 years ago

Hi, Ion! Firstly, thanx for extension - it's very nice!

  1. I have some problem when create line, based on Stroke with 0-1-0 alpha texture for aa. Here is a code:

    public class PathTest extends Sprite {
    [Embed( source = "/assets/strokeTexture.png" )] private var WhiteBMP :Class; private var stroke :Stroke; private var whiteBMP :Bitmap; private var whiteTexture :Texture;

    public function PathTest() 
    {
       addEventListener(Event.ADDED_TO_STAGE, onAdded);
    }
    
    private function onAdded ( e:Event ):void
    {
       stroke = new Stroke();
       addChild(stroke);
       stroke.x = 20;
       stroke.y = 20;
    
       whiteBMP = new WhiteBMP();
       whiteTexture = Texture.fromBitmap( whiteBMP, false );
    
       runExample();
    }
    
    private function runExample():void
    {
       stroke.material = new TextureMaterial(whiteTexture, 0xFFF440);
    
       var l_x:Number = 0;
       var l_y:Number = 0;
       for (var i:int = 0; i < 100; i++) 
       {
           l_x += Math.random() * 10;
           l_y += Math.random() * 10;
           stroke.lineTo(l_x, l_y, 16);
       }
    }

    }

The problem is that there are black edges around the line. Is it possible to make its transparent or may be set the color of that (same as the background color)?

Look what i mean:

img

here is a texture:

stroketexture

and project src: https://www.dropbox.com/s/om7v84i2iibpp53/pathTest.zip?dl=0

.. and another small question. May be it's possible to update stroke thickness without clear and redraw it by lineTo method? I need to animate at each frame long polyline thickness (by zoom-in/out a route in my geo-map application). Now a use that:

public function update():void
    {
        clear();
        for (var i:int = 0; i < _basePoints.length; i+=3)
        {
            lineTo(_basePoints[i], _basePoints[i+1], _thickness);
        }
    }

Is there fastest way to do that job?

Thanks!

jonathanrpace commented 9 years ago

Looks like a problem related to pre-multiplied alpha to me http://www.quasimondo.com/archives/000665.php

If you stored your alpha in a seperate bitmap, then used a bit of BitmapData.copyChannel, you should be able to construct an un pre-multiplied version of your bitmap.

Or if you only needed greyscale, you could save yourself another bitmap and just pack the alpha into the green channel.

IonSwitz commented 9 years ago

I will answer the second issue first:

If you use ShapeEx instead of Shape, the shapeEx.graphics - API opens up the ability to post process Line properties, like Thickness. However, it isn't a whole lot faster, since the underlying geometry has to be recreated anyway.

If you look at the "postProcess" method on GraphicsEx, you can supply a startIndex and an endIndex, and a GraphicsExThicknessData variable that holds the thickness you wish to apply along the line.

This allows you to say that the line should be 10 thick in the beginning, 20 thick in the middle, etc.

But the performance gains will be slight, unfortunately. It does give you the ability to make more fun lines, however. You can check Example 08 in the Extension, the NaturalSplineExample , it will show you how to use the postProcess method.

For the first question, unfortunately I dont know how to solve that. I think it has something to do with premultiplied alpha and the shaders that the Graphics extension use by default, but I dont know what exactly. It should be possible to fix, but I have so very little time on my hands.

I will look into it as well, but please have a look yourself too, if you want, in the StandardMaterial, the StandardVertexShader and the TextureVertexColorFragmentShader classes

IonSwitz commented 9 years ago

Yes, it is the StandardVertexShader and the TextureVertexColorFragmentShader classes that handles premultiplied alpha wrong.

I believe fixing this would require quite a change to the StandardVertexShader and the FragmentShaders that are used in the extension. An excellent project for someone with time ;)

sigh I'm sorry that I can't fix it, @IlyaFlasher

This is easily verified by taking the same texture with alpha, and applying it both to an Image and a Stroke of similar dimensions. The Image gets blended correctly, the Stroke isnt.

https://dl.dropboxusercontent.com/u/107200878/BadPremultipliedAlpha.jpg

alexeevilya commented 9 years ago

Ion, Thank you so much for your answer! Thank you for try to help solve the problem quickly! But "shader"... ohhmg! It's so difficult for me... %( Do you have any advice for me, that what I need to look specifically? "Premultiplied Alpha", it's a magic words ) Well, thanks anyway, I understand that the solution to this problem requires a lot of time from you. No problem, thanks!

jonathanrpace commented 9 years ago

Fixed by d59dad98088b5709b1ff63eec4a4a6744953e482.

This fix doesn't touch the shaders (un-premultiplying in shaders would cause precision artifacts) - Starling already supports correctly rendering shader output with premultiplied alphas via hardware blend modes - so I've just exposed the flag for that from the materials.

IMaterial's have a new 'premultipliedAlpha' field that's set to 'true' by default on TextureMaterial. This assumes most people will be supplying image data via Flash's BitmapData class (which premultiplies) - users supplying texture data via their own loading mechanisms (which don't premultiply) will need to set premultiplyAlpha=false on their material to get correct blending.

IonSwitz commented 9 years ago

This is most excellent, and very very good news. Great fix, @jonathanrpace

alexeevilya commented 9 years ago

@jonathanrpace, Thank you so much!!!! Your help is invaluable!!!!