2

我正在尝试完成一些我认为在 Windows 上的 MonoGame GL 中应该非常简单的事情。那就是从 PNG 文件加载纹理并将其作为精灵渲染到屏幕上。到目前为止,我在这方面遇到了很多麻烦。我正在使用以下代码(F#)将 PNG 加载到 Texture2D:

    use file = System.IO.File.OpenRead("testTexture.png")
    this.texture <- Texture2D.FromStream(this.GraphicsDevice, file)

然后渲染:

    this.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
    this.spriteBatch.Draw(this.texture, Vector2.Zero, Color.White)
    this.spriteBatch.End()

问题是 alpha 通道出现了某种奇怪的效果,好像通道没有被 alpha 预乘之类的东西,但我无法确定到底发生了什么。值得注意的是,使用官方 XNA 库可以完美呈现完全相同的代码。问题仅在 MonoGame 中,我使用 3.0 和 3.2 版本进行了测试,两者都有相同的问题。

下面是在 MonoGame 中渲染一个测试 PNG 来说明问题:

http://i.imgur.com/Dny26gI.png

每张图片的背景是矢车菊蓝色,然后分别是纯红色、绿色和蓝色。请注意,在具有红色背景的图像中,您可以在纹理中的红线周围看到深色轮廓。这个轮廓不应该在那里,因为线条和背景都是纯红色的。请注意,在具有蓝色背景的图像中的蓝线周围会发生同样的事情,但在具有绿色背景的图像中则不会。在该图像中,绿线应与绿色背景融为一体。

下面是使用官方 XNA 库渲染完全相同的文件的方式。

http://i.imgur.com/2Rtqhuk.png

注意当背景颜色相同时,蓝色、绿色和红色线条如何融入背景。这是正确的行为。

鉴于相同的代码在 XNA 和 MonoGame 中的行为不同,我相信框架中一定存在错误。任何人都可以很好地猜测错误可能在哪里以及性质是什么?如果这是一个简单的修复,那么最好的解决方案可能是自己修复该错误。

除此之外,虽然我真的只是想学习一种方法,我可以简单地加载 PNG 并将其正确渲染到 MonoGame 的屏幕上。我敢肯定我不能成为第一个想要这样做的人。如果可能的话,我想避免使用内容管道,只是为了简单起见。

更新

我做了一些更多的挖掘,试图找出这个问题的本质。我更改了 testTexture.png 文件,以更能揭示 alpha 混合问题。在使用这个新的纹理文件后,我截取了错误的 MonoGame 渲染并在其单独的颜色通道中查看它。正在发生的事情让我很困惑。我最初虽然这可能是一个BlendState.NonPremultiplied被忽略的简单案例,但我所看到的看起来更复杂。除其他外,绿色通道似乎与蓝色和红色通道混合不同。这是一个相当大的PNG图像,它是我在说什么的截图和解释的汇编:

i.imgur.com/CEUQqm0.png

显然,MonoGame for Windows GL 中存在某种错误,可能还有其他我没有尝试过的版本(尽管我有兴趣看到已验证)。如果有人认为他们知道这里可能会发生什么,请告诉我。

最后,这是重现我遇到的问题的项目文件:

mega.co.nz/#!llFxBbrb!OrpPIn4Tu2UaHHuoSPL03nqOtAJFK59cfxI5TDzLyYI

4

1 回答 1

6

此问题已得到解决。框架中的错误在 MonoGame.Framework/Graphics/ImageEx.cs以下方法中找到:

internal static void RGBToBGR(this Image bmp)
{
    System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
    System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(rgbtobgr);

    ia.SetColorMatrix(cm);
    using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
    {
        g.DrawImage(bmp, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, System.Drawing.GraphicsUnit.Pixel, ia);
    }
}

将其更改为此可以解决问题:

internal static void RGBToBGR(this Image bmp)
{
    using (Bitmap bmpCopy = (Bitmap)bmp.Clone())
    {
        System.Drawing.Imaging.ImageAttributes ia = new System.Drawing.Imaging.ImageAttributes();
        System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(rgbtobgr);

        ia.SetColorMatrix(cm);
        using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bmp))
        {
            g.Clear(Color.Transparent);
            g.DrawImage(bmpCopy, new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, System.Drawing.GraphicsUnit.Pixel, ia);
        }
    }
}

发生的情况是,当执行 RGBToBGR 转换时,它会将转换后的图像版本绘制在要转换的图像对象之上。这就是造成奇怪效果的原因。据我所知,唯一要做的就是在再次绘制之前清除图像对象,这当然意味着必须复制要转换的位图,这样您就可以在覆盖原始版本的同时从复制的版本中读取刚刚被清除。

感谢 dellis1972 为我指明了正确的方向:https ://github.com/mono/MonoGame/issues/1946

于 2013-08-20T22:57:28.377 回答