【问题标题】:How could I optimize this pixel opacity calculation?如何优化此像素不透明度计算?
【发布时间】:2011-07-17 06:20:03
【问题描述】:

我有用于计算像素不透明度的 C# 代码,它用于 XNA,如何提高它的性能?

    public static uint GetPixelForOpacity(uint pixelBackground, uint pixelForeground, uint pixelCanvasAlpha)
    {
        byte surfaceR = (byte)((pixelForeground & 0x00FF0000) >> 16);
        byte surfaceG = (byte)((pixelForeground & 0x0000FF00) >> 8);
        byte surfaceB = (byte)((pixelForeground & 0x000000FF));

        byte sourceR = (byte)((pixelBackground & 0x00FF0000) >> 16);
        byte sourceG = (byte)((pixelBackground & 0x0000FF00) >> 8);
        byte sourceB = (byte)((pixelBackground & 0x000000FF));

        uint newR = sourceR * pixelCanvasAlpha / 256 + surfaceR * (255 - pixelCanvasAlpha) / 256;
        uint newG = sourceG * pixelCanvasAlpha / 256 + surfaceG * (255 - pixelCanvasAlpha) / 256;
        uint newB = sourceB * pixelCanvasAlpha / 256 + surfaceB * (255 - pixelCanvasAlpha) / 256;

        return (uint)255 << 24 | newR << 16 | newG << 8 | newB;
    }

【问题讨论】:

  • 根据背景和前景像素计算不透明度像素。
  • 我明白了。为什么不使用 XNA 中内置的 AlphaBlendEnable? msdn.microsoft.com/en-us/library/…
  • 我使用自定义的 BlendState() 来达到我的目的。现在只在前景图像上设置 Alpha。性能很棒。感谢 Jonas 提供非常好的建议。我是 XNA 的新手。

标签: c# .net performance optimization xna


【解决方案1】:
  1. 使用premultiplied alpha
  2. 显卡正是为了加速此类操作而设计的。将您的像素数据放入 Texture2D 并使用适当的混合模式将其绘制到屏幕上。这将快得多。或者,如果您不希望它立即出现在屏幕上,redirect your rendering 到另一个纹理。

【讨论】:

  • 1.我尝试过,但是当将 alpha 更改为 [0,1] 时,除法操作需要更长的时间 2。这已经在更改 Texture2D,但每个像素需要具有不同的不透明度。
  • 我没有说你应该使用浮点值——你可以使用带有整数值的预乘 alpha。关于 Texture2D - 你一定是图形编程的新手。当使用正确的格式创建时,纹理会为每个像素保留一个 alpha(不透明度)值。阅读alpha channels
  • 是的,我是图形编程的新手。我会考虑 alpha 通道,看起来它对我的目的很有用。
【解决方案2】:

pixelCanvasAlpha / 256 替换为pixelCanvasAlpha &gt;&gt; 8。不要用整数类型除以 2 的幂,移位总是更快。另外,unchecked 应该会有所帮助。

【讨论】:

  • 将 pixelCanvasAlpha / 256 替换为 pixelCanvasAlpha >> 8 并没有多大帮助,我认为编译器已经对此进行了改进。
  • 我希望编译器能够进行优化。刚刚验证它至少在 Windows x64 上这样做。
  • 该死,编译器现在很聪明:) unchecked 效果怎么样?
【解决方案3】:

我对此表示怀疑,但 bitwise not 可能比 255-n 更快

uint newR = (sourceR * pixelCanvasAlpha + surfaceR * (uint)(byte)~pixelCanvasAlpha) >> 8;

uint newR = (sourceR * pixelCanvasAlpha + surfaceR * ~pixelCanvasAlpha & 0x000000FF) >> 8;

了解的唯一方法是进行基准测试。

【讨论】:

  • 了解的唯一方法是测量。但如果铸造真的很慢,你可以~pixelCanvasAlpha &amp; 0x000000FF
  • 另请注意,我将&gt;&gt; 8 移到了末尾,因此只需执行一次。
  • 您提到的所有操作都是由编译器执行的。测试表明没有改善。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 1970-01-01
  • 2012-01-01
  • 2018-08-21
  • 2012-07-11
  • 1970-01-01
  • 2011-01-22
相关资源
最近更新 更多