更有效的混合像素的方法(半透明)?

问题描述 投票:3回答:1

我正在为一个小型二维游戏在其他图像上绘制半透明的图像。为了当前混合图像,我使用这里的公式。https:/en.wikipedia.orgwikiAlpha_compositing#Alpha_blending#。

我的实现方法如下。

private static int blend(int source, int dest, int trans)
{
    double alpha = ((double) trans / 255.0);
    int sourceRed = (source >> 16 & 0xff);
    int sourceGreen = (source >> 8 & 0xff);
    int sourceBlue = (source & 0xff);
    int destRed = (dest >> 16 & 0xff);
    int destGreen = (dest >> 8 & 0xff);
    int destBlue = (dest & 0xff);

    int blendedRed = (int) (alpha * sourceRed + (1.0 - alpha) * destRed);
    int blendedGreen = (int) (alpha * sourceGreen + (1.0 - alpha) * destGreen);
    int blendedBlue = (int) (alpha * sourceBlue + (1.0 - alpha) * destBlue);

    return (blendedRed << 16) + (blendedGreen << 8) + blendedBlue;
}

现在,它工作得很好,但它有一个相当高的开销,因为它被调用的每一个像素每一帧。与单纯渲染图像而不进行混合相比,我的性能下降了30%左右的FPS。

我只是想知道是否有人能想到更好的方法来优化这段代码,因为我可能做了太多的位运算。

java graphics rendering java-2d blending
1个回答
1
投票

不是一个java编码员(所以带着偏见来阅读),但你做的一些事情真的是错的(从我C++和低级gfx的角度来看)。

  1. 整数与浮点混合

    这需要转换,有时真的很昂贵... ... 在范围内使用整数权重(alpha)要好得多。<0..255> 然后再除以255或位移8,这样可能会快很多。

  2. 位移屏蔽来获取字节。

    是的,但有更简单快捷的方法,只需使用

    enum{
        _b=0,   // db
        _g=1,
        _r=2,
        _a=3,
        };
    
    union color
        {
        DWORD dd;    // 1x32 bit unsigned int
        BYTE db[4];  // 4x8 bit unsigned int
        };
    
    color col;
    col.dd=some_rgba_color;
    r = col.dd[_r]; // get red channel
    col.dd[_b]=5;   // set blue channel
    

    像样的编译器可以在内部将代码的某些部分优化成这样,但我怀疑它是否能做到面面俱到......

    你也可以用指针代替 union 同样

  3. 功能开销

    你得到的功能混合单像素。这意味着它将会被调用很多。通常每次调用混合区域(矩形)要比调用每个像素的东西快得多。因为你用这种方式来糟蹋堆栈。为了限制这种情况,你可以试试这些(对于大规模调用的函数)。

    重新编码您的应用程序,使您可以混合区域而不是像素,从而减少函数调用。

    通过降低操作数、返回值和被调用函数的内部变量来降低堆栈垃圾化,以限制每次调用所分配的RAM量freedoverwrittencopied。例如通过使用静态或全局变量,Alpha很可能不会有太大变化。或者你可以直接在颜色中使用alpha编码,而不是使用 alpha 作为操作数。

    使用 inline 或宏,如 #define 将源代码直接放到代码中,而不是函数调用。

首先,我会尝试将你的函数体重新编码成这样。

enum{
    _b=0,   // db
    _g=1,
    _r=2,
    _a=3,
    };

union color
    {
    unsigned int dd;    // 1x32 bit unsigned int
    unsigned char db[4];  // 4x8 bit unsigned int
    };

private static unsigned int blend(unsigned int src, unsigned int dst, unsigned int alpha)
    {
    unsigned int i,a,_alpha=255-alpha;
    color s,d;
    s.dd=src;
    d.dd=dst;
    for (i=0;i<3;i++)
        { 
        a=(((unsigned int)(s.db[i]))*alpha) + (((unsigned int)(d.db[i]))*_alpha);
        a>>=8;
        d.db[i]=a;
        }
    return d.dd;
    }

然而,如果你想要真正的速度,请使用GPU(OpenGL Blending)。

© www.soinside.com 2019 - 2024. All rights reserved.