【问题标题】:How to load transparent PNG using Texture2D.FromStream如何使用 Texture2D.FromStream 加载透明 PNG
【发布时间】:2017-03-04 19:19:24
【问题描述】:

我想问如何在保持图像透明度的同时从文件加载 Texture2D 图像(我不想使用 XNA 的内容管道),因为我想在我的游戏中进行蒙皮。

我的代码:

使用_cursor.Texture = _helper.LoadPicture("skin\\cursor.png");初始化纹理

使用spriteBatch.Draw(Texture, rectangle, Color.BlanchedAlmond);绘制纹理

public Texture2D LoadPicture(string filename) {
    FileStream setStream = File.Open(filename, FileMode.Open);
    StreamReader reader = new StreamReader(setStream);
    Texture2D NewTexture = Texture2D.FromStream(_graphicsDevice, setStream);
    setStream.Dispose();
    return NewTexture;
 }

屏幕截图 1(结果):http://prntscr.com/cxjzwu

屏幕截图 2(预期):http://prntscr.com/cxk065

【问题讨论】:

  • 你使用spriteBatch.Begin()方法传递了哪些参数?
  • 你应该使用类似:spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend); (stackoverflow.com/questions/6632723/…)
  • 还是同样的问题。
  • 当我使用 Content.Load("cursor"); -- XNA Content Pipeline 然后它可以正常工作,但我不想使用它,因为我需要用户皮肤。
  • 根据这个问题“stackoverflow.com/questions/7997750/…”应该支持透明图片。

标签: c# xna


【解决方案1】:

您也可以从加载中处理它,因此您可以将 BlendState 保持为 AlphaBlend。

这是我用来从文件加载纹理的函数:

private Texture2D PremultiplyTexture(String FilePath, GraphicsDevice device)
{
    Texture2D texture;

    FileStream titleStream = File.OpenRead(FilePath);
    texture = Texture2D.FromStream(device, titleStream);
    titleStream.Close();
    Color[] buffer = new Color[texture.Width * texture.Height];
    texture.GetData(buffer);
    for (int i = 0; i < buffer.Length; i++)
        buffer[i] = Color.FromNonPremultiplied(buffer[i].R, buffer[i].G, buffer[i].B, buffer[i].A);
    texture.SetData(buffer);

    return texture;
}

【讨论】:

  • 谢谢,太好了!让我不必切换 BlendStates。
【解决方案2】:

我已尝试重现您的问题,但对我来说效果很好:

我的幕后代码:

    #region Usings

using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

#endregion

namespace OpacityTest
{
    /// <summary>
    ///     This is the main type for your game
    /// </summary>
    public class Game1 : Game
    {
        private static Texture2D Tested;
        private GraphicsDeviceManager graphics;
        private SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        ///     Allows the game to perform any initialization it needs to before starting to run.
        ///     This is where it can query for any required services and load any non-graphic
        ///     related content.  Calling base.Initialize will enumerate through any components
        ///     and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        ///     LoadContent will be called once per game and is the place to load
        ///     all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            using (var fileStream = new FileStream("test.png", FileMode.Open))
            {
                Tested = Texture2D.FromStream(GraphicsDevice, fileStream);
            }
        }

        /// <summary>
        ///     UnloadContent will be called once per game and is the place to unload
        ///     all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // Important!!!
            Tested.Dispose();
        }

        /// <summary>
        ///     Allows the game to run logic such as updating the world,
        ///     checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                Exit();

            base.Update(gameTime);
        }

        /// <summary>
        ///     This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
            spriteBatch.Draw(Tested, Vector2.Zero, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

我正在使用这种纹理:

并将其放入我的构建文件夹中。


[编辑]

现在我知道您的问题出在哪里 - 颜色的 alpha 值设置为最大值。我已经尝试了一些事情并得出结论,您必须替换此行:

        spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);

用那一行:

        spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);

之后我得到了你的 Content.Load 结果:

如果您想了解更多关于“预乘 alpha”的信息,请点击me! :)

这是我用于光标的第二个纹理:

【讨论】:

  • 非常感谢 :) 为我工作,你是真正的 MVP。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 2022-01-25
  • 2016-06-03
  • 1970-01-01
  • 2011-10-08
  • 2012-02-15
  • 1970-01-01
相关资源
最近更新 更多