首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >AS3像素完美绘图?

AS3像素完美绘图?
EN

Stack Overflow用户
提问于 2012-07-27 07:25:57
回答 3查看 3K关注 0票数 4

当我在使用时:

代码语言:javascript
运行
复制
var shape:Shape = new new Shape();
shape.graphics.lineStyle(2,0);
shape.graphics.lineTo(10,10);
addChild(shape);

我得到了我想要的黑线,但我也得到了在它们旁边漂浮的灰色像素。有没有一种方法可以关闭添加模糊像素的平滑/反走样?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-06-13 03:35:29

是的,即使启用了抗锯齿功能,也可以绘制像素完美的形状。像素提示是必须的。等式的另一半是实际发出具有整个像素坐标的绘制命令。

例如,您可以使用以下代码绘制一个具有4px半径曲线的像素完全对称的圆角矩形。请仔细注意代码正在执行的操作,特别是偏移量与边框厚度之间的关系。

首先,请记住,当您绘制填充形状时,光栅化发生到,但不包括轮廓的右/下边缘。因此,要绘制一个4x4像素填充的正方形,只需调用drawRect(0,0,4,4)即可。这覆盖了像素0,1,2,3,4 (5个像素),但由于它不会栅格化右边和下边缘,所以它最终是4个像素。另一方面,如果您只绘制轮廓(不填充它),则需要调用drawRect(0,0,3,3),它将覆盖像素0,1,2,3,即4像素。因此,您实际上需要稍微不同的尺寸填充和轮廓,以获得像素完美的大小。

假设你想画一个50px宽,20px高的按钮,它的圆角边半径是4px,厚度是2px。为了确保恰好覆盖50x20像素,并且2px粗线的外边缘与边缘像素对接而不溢出,您必须像这样发出绘图命令。您必须使用像素提示,并且必须在所有边将矩形向内偏移1px (不是半个像素,而是恰好是1)。这条线的中心恰好位于像素0和1之间,因此它最终绘制了通过像素0和1的2px宽的线。

以下是您可以使用的示例方法:

代码语言:javascript
运行
复制
public class GraphicsUtils
{
    public static function drawFilledRoundRect( g:Graphics, x:Number, y:Number, width:Number, height:Number, ellipseWidth:Number = 0, ellipseHeight:Number = 0, fillcolor:Number = 0xFFFFFF, fillalpha:Number = 1, thickness:Number = 0, color:Number = 0, alpha:Number = 1, pixelHinting:Boolean = false, scaleMode:String = "normal", caps:String = null, joints:String = null, miterLimit:Number = 3 )
    {
        if (!isNaN( fillcolor))
        {
            g.beginFill( fillcolor, fillalpha );
            g.drawRoundRect( x, y, width, height, ellipseWidth, ellipseHeight );
            g.endFill();
        }
        if (!isNaN(color))
        {
            g.lineStyle( thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit );
            g.drawRoundRect( x, y, width, height, ellipseWidth, ellipseHeight );
        }
    }
}

你可以这样叫它:

代码语言:javascript
运行
复制
var x:Number = 0;
var y:Number = 0;
var width:Number = 50;
var height:Number = 20;
var pixelHinting:Boolean = true;
var cornerRadius:Number = 4;
var fillColor:Number = 0xffffff; //white
var fillAlpha:Number = 1;
var borderColor:Number = 0x000000; //black
var borderAlpha:Number = 1;
var borderThickness:Number = 2;
GraphicsUtils.drawFilledRoundRect( graphics, x + (borderThickness / 2), y + (borderThickness / 2), width - borderThickness, height - borderThickness, cornerRadius * 2, cornerRadius * 2, fillColor, fillAlpha, borderThickness, borderColor, borderAlpha, pixelHinting );

这将产生一个像素完全对称的2px厚填充圆角矩形,正好覆盖50x20像素区域。

非常重要的是要注意,使用borderThickness为0有点无意义,而且会导致矩形放大1个像素,因为它仍然绘制一条1像素的宽线,但它无法减去宽度(因为它是0),因此你将得到一个超大的矩形。

总之,使用上面的算法,在x和y坐标上加上一半的边框厚度,然后从宽度和高度中减去整个边框厚度,并且始终使用最小厚度1。这将始终导致矩形的边框占据并且不会溢出与给定的宽度和高度相等的像素区域。

如果你想看到它的实际效果,只需将以下代码块复制并粘贴到主时间线上的一个新的AS3 Flash项目中,然后按原样运行它,因为它包含了运行所需的一切:

代码语言:javascript
运行
复制
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.events.Event;
import flash.utils.getTimer;
import flash.display.Sprite;
import flash.display.Graphics;

stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
stage.align = flash.display.StageAlign.TOP_LEFT;
stage.frameRate = 60;
draw();

function draw():void
{
    var x:Number = 10;
    var y:Number = 10;
    var width:Number = 50;
    var height:Number = 20;
    var pixelHinting:Boolean = true;
    var cornerRadius:Number = 4;
    var fillColor:Number = 0xffffff; //white
    var fillAlpha:Number = 1;
    var borderColor:Number = 0x000000; //black
    var borderAlpha:Number = 1;
    var borderThickness:Number = 2;

    var base:Number = 1.6;
    var squares:int = 10;
    var rows = 4;
    var thicknessSteps:Number = 16;
    var thicknessFactor:Number = 4;

    var offset:Number;
    var maxBlockSize:Number = int(Math.pow( base, squares ));
    var globalOffset:Number = maxBlockSize; //leave room on left for animation
    var totalSize:Number = powerFactorial( base, squares );
    var colors:Array = new Array();
    for (i = 1; i <= squares; i++)
        colors.push( Math.random() * Math.pow( 2, 24 ) );

    for (var j:int = 0; j < thicknessSteps; j++)
    {
        var cycle:Number = int(j / rows);
        var subCycle:Number = j % rows;
        offset = cycle * totalSize;
        y = subCycle * maxBlockSize;
        borderThickness = (j + 1) * thicknessFactor;
        for (var i:int = 0; i < squares; i++)
        {
            cornerRadius = Math.max( 8, borderThickness );
            borderColor = colors[i];
            x = globalOffset + offset + powerFactorial( base, i ); //int(Math.pow( base, i - 1 ));
            width = int(Math.pow( base, i + 1 ));
            height = width;
            if (borderThickness * 2 > width) //don't draw if border is larger than area
                continue;
            drawFilledRoundRect( graphics, x + (borderThickness / 2), y + (borderThickness / 2), width - borderThickness, height - borderThickness, cornerRadius * 2, cornerRadius * 2, fillColor, fillAlpha, borderThickness, borderColor, borderAlpha, pixelHinting );
        }
    }

    var start:uint = flash.utils.getTimer();
    var duration:uint = 5000;
    var sprite:Sprite = new Sprite();
    addChild( sprite );
    var gs:Graphics = sprite.graphics;
    addEventListener( flash.events.Event.ENTER_FRAME,
    function ( e:Event ):void
    {
        var t:uint = (getTimer() - start) % duration;
        if (t > (duration / 2))
            borderThickness = ((duration-t) / (duration/2))  * thicknessSteps * thicknessFactor;
        else
            borderThickness = (t / (duration/2)) * thicknessSteps * thicknessFactor;
        //borderThickness = int(borderThickness);
        cornerRadius = Math.max( 8, borderThickness );
        borderColor = colors[squares - 1];
        x = 0;
        y = 0;
        width = int(Math.pow( base, squares ));
        height = width;
        if (borderThickness * 2 > width) //don't draw if border is larger than area
            return;
        gs.clear();
        drawFilledRoundRect( gs, x + (borderThickness / 2), y + (borderThickness / 2), width - borderThickness, height - borderThickness, cornerRadius * 2, cornerRadius * 2, fillColor, fillAlpha, borderThickness, borderColor, borderAlpha, pixelHinting );
    }, false, 0, true );
}

function powerFactorial( base:Number, i:int ):Number
{
    var result:Number = 0;
    for (var c:int = 0; c < i; c++)
    {
        result += int(Math.pow( base, c + 1 ));
    }
    return result;
}

function drawFilledRoundRect( g:Graphics, x:Number, y:Number, width:Number, height:Number, ellipseWidth:Number = 0, ellipseHeight:Number = 0, fillcolor:Number = 0xFFFFFF, fillalpha:Number = 1, thickness:Number = 0, color:Number = 0, alpha:Number = 1, pixelHinting:Boolean = false, scaleMode:String = "normal", caps:String = null, joints:String = null, miterLimit:Number = 3 )
{
    if (!isNaN( fillcolor))
    {
        g.beginFill( fillcolor, fillalpha );
        g.drawRoundRect( x, y, width, height, ellipseWidth, ellipseHeight );
        g.endFill();
    }
    if (!isNaN(color))
    {
        g.lineStyle( thickness, color, alpha, pixelHinting, scaleMode, caps, joints, miterLimit );
        g.drawRoundRect( x, y, width, height, ellipseWidth, ellipseHeight );
    }
}
票数 3
EN

Stack Overflow用户

发布于 2012-07-27 07:29:59

尝试打开pixelHinting:

shape.graphics.lineStyle(2, 0, 1, true);

更多关于pixelHinting here的信息。

票数 0
EN

Stack Overflow用户

发布于 2012-07-27 07:47:48

您不能完全关闭抗锯齿。如果你想要一条清晰的、像素化的线条,那么不幸的是,你必须使用位图和setPixel()逐个像素地绘制。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11679477

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档