Graphics 在Monogame中从PNG加载纹理的透明度问题

Graphics 在Monogame中从PNG加载纹理的透明度问题,graphics,rendering,sprite,monogame,Graphics,Rendering,Sprite,Monogame,我正在努力完成一些我认为在Windows上的MonoGame GL中应该非常简单的事情。。即从PNG文件加载纹理,并将其作为精灵渲染到屏幕上。到目前为止,我在这方面遇到了很多麻烦。我正在使用以下代码(F#)将PNG加载到纹理2D中: 问题是alpha通道产生了某种奇怪的效果,好像有什么通道没有被alpha预乘或者什么的,但是我不能确定到底发生了什么。但值得注意的是,完全相同的代码使用官方XNA库呈现得非常完美。这个问题只存在于MonoGame中,我用版本3.0和3.2测试了它,这两个版本都有相同

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

问题是alpha通道产生了某种奇怪的效果,好像有什么通道没有被alpha预乘或者什么的,但是我不能确定到底发生了什么。但值得注意的是,完全相同的代码使用官方XNA库呈现得非常完美。这个问题只存在于MonoGame中,我用版本3.0和3.2测试了它,这两个版本都有相同的问题

下面是在MonoGame中呈现测试PNG以说明问题:

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

下面是如何使用官方XNA库呈现完全相同的文件

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

考虑到相同的代码在XNA和MonoGame中的行为不同,我相信框架中一定存在缺陷。有人能很好地猜出这个bug可能在哪里,是什么性质的吗?如果这是一个简单的修复,那么最好的解决方案可能就是自己修复这个bug

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

更新 为了弄清这个问题的本质,我做了更多的挖掘工作。我已经更改了testTexture.png文件,以便更清楚地了解alpha混合问题。在使用了这个新的纹理文件后,我截取了不正确的MonoGame渲染的屏幕截图,并在单独的颜色通道中查看了它。所发生的事情让我很困惑。我起初认为这可能是一个简单的情况,即
混合状态。非乘性
被忽略,但我看到的情况看起来更复杂。除此之外,绿色通道似乎与蓝色和红色通道的混合方式不同。这是一张相当大的PNG图片,它是关于我所说内容的截图和解释的汇编:

i、 imgur.com/CEUQqm0.png

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

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


mega.co.nz/#!llFxBbrb!orppin4tuhuahuospL03nqotaJFK59cfxi5tdzlyyi

此问题已解决。在以下位置发现框架中的错误:
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为我指明了正确的方向:

我的第一个猜测是在SpriteBatch.Begin调用中使用BlendState.nonpremultipled,但我看到您已经在这样做了。尝试切换到SpriteSortMode。延迟,看看会发生什么。无论如何,我同意这可能是MonoGame中的一个bug。@craftworkgames尝试过,但没有什么不同:(.不过谢谢。
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);
        }
    }
}