每天都在这里学习。我刚刚想出了如何使用RenderTarget2D将多个纹理组合成一个。然而,虽然我可以在大多数情况下使用RenderTarget2D作为Texture2D,但有一个关键的区别:当调整缓冲区的大小时,这些呈现的纹理会丢失(毫无疑问,在其他情况下,比如内存不足的图形设备)。
目前,我只是将完成的RenderTarget2D复制到一个新的非易失性Texture2D对象中。不过,我这么做的代码是相当糟糕的。有什么更优雅的方法吗?也许我只是累了,但是我在Google上找不到答案。
略为简化:
public static Texture2D MergeTextures(int width, int height, IEnumerable<Tuple<Texture2D, Color>> textures)
{
RenderTarget2D buffer = new RenderTarget2D(_device, width, height);
_device.SetRenderTarget(buffer);
_device.Clear(Color.Transparent);
SpriteBatch spriteBatch = new SpriteBatch(_device);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
// Paint each texture over the one before, in the appropriate color
Rectangle rectangle = new Rectangle(0, 0, width, height);
foreach (Tuple<Texture2D, Color> texture in textures)
spriteBatch.Draw(texture.Item1, rectangle, texture.Item2);
spriteBatch.End();
_device.SetRenderTarget((RenderTarget2D)null);
// Write the merged texture to a Texture2D, so we don't lose it when resizing the back buffer
// This is POWERFUL ugly code, and probably terribly, terribly slow
Texture2D mergedTexture = new Texture2D(_device, width, height);
Color[] content = new Color[width * height];
buffer.GetData<Color>(content);
mergedTexture.SetData<Color>(content);
return mergedTexture;
}我想我应该根据需要检查IsContentLost和重新呈现,但是这发生在我的主绘图循环的中间,当然您不能嵌套SpriteBatches。我可以维护一个“呈现TODO”列表,在主SpriteBatch结束之后处理这些列表,然后它们就可以用于下一个帧了。这是首选的策略吗?
这段代码只被调用了几次,所以性能不是问题,但是我想学习如何正确地处理事情。
发布于 2011-04-01 05:50:03
实际上,如果您在一次性过程中生成纹理,而通常加载内容(游戏开始、级别更改、空间更改等),代码就不会那么糟糕。你在CPU和GPU之间传输纹理,这和加载普通的纹理是一样的。这很简单,而且很有效!
如果您正在更频繁地生成纹理,并且它开始成为每帧成本,而不是负载时间成本,那么您将需要担心它的性能,并可能将它们保留为渲染目标。
您不应该在绘图过程中获得ContentLost,因此您可以安全地响应该事件并重新创建呈现目标。或者,您可以在它们上检查IsContentLost,最好是在呈现任何其他内容之前先在框架的开始处进行检查。无论哪种方式,都应该在SpriteBatch开始之前检查所有内容。
(通常在使用呈现目标时,您会重新生成每个帧,因此在这种情况下不需要检查它们。)
发布于 2011-05-01 07:36:49
替换
Texture2D mergedTexture = new Texture2D(_device, width, height);
Color[] content = new Color[width * height];
buffer.GetData<Color>(content);
mergedTexture.SetData<Color>(content);
return mergedTexture;使用
return buffer;因为RenderTarget2D扩展了Texture2D,所以您将只返回Texture2D类数据。另外,如果您感兴趣,这里有一个类,用于用多个纹理构建GUI库的小部件。以防你经常做这种事。
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
namespace Voodo.Utils {
/// <summary>
///
/// </summary>
public class TextureBaker {
private readonly SpriteBatch _batch;
private readonly RenderTarget2D _renderTarget;
private readonly GraphicsDevice _graphicsDevice;
/// <summary>
///
/// </summary>
public Rectangle Bounds {
get { return _renderTarget.Bounds; }
}
/// <summary>
///
/// </summary>
/// <param name="graphicsDevice"></param>
/// <param name="size"></param>
public TextureBaker(GraphicsDevice graphicsDevice, Vector2 size) {
_graphicsDevice = graphicsDevice;
_batch = new SpriteBatch(_graphicsDevice);
_renderTarget = new RenderTarget2D(
_graphicsDevice,
(int)size.X,
(int)size.Y);
_graphicsDevice.SetRenderTarget(_renderTarget);
_graphicsDevice.Clear(Color.Transparent);
_batch.Begin(
SpriteSortMode.Immediate,
BlendState.AlphaBlend,
SamplerState.LinearClamp,
DepthStencilState.Default,
RasterizerState.CullNone);
}
#region Texture2D baking
/// <summary>
///
/// </summary>
/// <param name="texture"></param>
public void BakeTexture(Texture2D texture) {
_batch.Draw(
texture,
new Rectangle(0, 0, Bounds.Width, Bounds.Height),
Color.White);
}
/// <summary>
///
/// </summary>
/// <param name="texture"></param>
/// <param name="destination"></param>
public void BakeTexture(Texture2D texture, Rectangle destination) {
_batch.Draw(
texture,
destination,
Color.White);
}
/// <summary>
///
/// </summary>
/// <param name="texture"></param>
/// <param name="destination"></param>
/// <param name="source"></param>
public void BakeTexture(Texture2D texture, Rectangle destination, Rectangle source) {
_batch.Draw(
texture,
destination,
source,
Color.White);
}
/// <summary>
///
/// </summary>
/// <param name="texture"></param>
/// <param name="sourceModification"></param>
/// <param name="destination"></param>
public void BakeTexture(Texture2D texture, System.Drawing.RotateFlipType sourceModification, Rectangle destination) {
Stream sourceBuffer = new MemoryStream();
texture.SaveAsPng(sourceBuffer, texture.Width, texture.Height);
System.Drawing.Image sourceImage = System.Drawing.Image.FromStream(sourceBuffer);
sourceBuffer = new MemoryStream();
sourceImage.RotateFlip(sourceModification);
sourceImage.Save(sourceBuffer, System.Drawing.Imaging.ImageFormat.Png);
_batch.Draw(
Texture2D.FromStream(_graphicsDevice, sourceBuffer),
destination,
Color.White);
}
/// <summary>
///
/// </summary>
/// <param name="texture"></param>
/// <param name="sourceModification"></param>
/// <param name="destination"></param>
/// <param name="source"></param>
public void BakeTexture(Texture2D texture, System.Drawing.RotateFlipType sourceModification, Rectangle destination, Rectangle source) {
Stream sourceBuffer = new MemoryStream();
texture.SaveAsPng(sourceBuffer, texture.Width, texture.Height);
System.Drawing.Image sourceImage = System.Drawing.Image.FromStream(sourceBuffer);
sourceBuffer = new MemoryStream();
sourceImage.RotateFlip(sourceModification);
sourceImage.Save(sourceBuffer, System.Drawing.Imaging.ImageFormat.Png);
_batch.Draw(
Texture2D.FromStream(_graphicsDevice, sourceBuffer),
destination,
source,
Color.White);
}
#endregion
#region SpriteFont baking
/// <summary>
///
/// </summary>
/// <param name="font"></param>
/// <param name="text"></param>
/// <param name="location"></param>
/// <param name="textColor"></param>
public void BakeText(SpriteFont font, string text, Vector2 location, Color textColor) {
_batch.DrawString(font, text, location, textColor);
}
/// <summary>
///
/// </summary>
/// <param name="font"></param>
/// <param name="text"></param>
/// <param name="location"></param>
public void BakeTextCentered(SpriteFont font, string text, Vector2 location, Color textColor) {
var shifted = new Vector2 {
X = location.X - font.MeasureString(text).X / 2,
Y = location.Y - font.MeasureString(text).Y / 2
};
_batch.DrawString(font, text, shifted, textColor);
}
#endregion
/// <summary>
///
/// </summary>
/// <returns></returns>
public Texture2D GetTexture() {
_batch.End();
_graphicsDevice.SetRenderTarget(null);
return _renderTarget;
}
}
}发布于 2011-04-01 11:02:53
如果在将呈现目标绘制到其他地方时出现了动态调整其大小的问题,则只需设置一个屏幕外呈现对象,您就可以复制完成的RT如下所示:
Rendertarget2D offscreenRT = new RenderTarget2D(_device, width, height);
_device.SetRenderTarget(offscreenRT);
_device.Clear(Color.Transparent);
SpriteBatch spriteBatch = new SpriteBatch(_device);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
spriteBatch.Draw(buffer, Vector2.Zero, Color.White);
spriteBatch.End();
_device.SetRenderTarget(null);https://stackoverflow.com/questions/5509265
复制相似问题