写入RenderTarget后,如何有效地克隆输出? [英] After Writing to a RenderTarget, How to Efficiently Clone the Output?

查看:61
本文介绍了写入RenderTarget后,如何有效地克隆输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

XNA新手在这里,每天学习.我刚刚弄清楚了如何使用RenderTarget2D将多个纹理合成为一个.但是,尽管我可以将RenderTarget2D用作大多数用途的Texture2D,但有一个关键的区别:调整后缓冲区的大小时,这些渲染的纹理会丢失(毫无疑问,在其他情况下,例如图形设备的内存不足).

目前,我只是将完成的RenderTarget2D复制到新的非易失性Texture2D对象中.但是,我这样做的代码非常难看.有没有更优雅的方法可以做到这一点?也许我只是累了,但无法在Google或SO上找到答案.

略有简化:

 公共静态Texture2D MergeTextures(int宽度,int高度,IEnumerable< Tuple< Texture2D,Color>>纹理){RenderTarget2D缓冲区=新的RenderTarget2D(_device,width,height);_device.SetRenderTarget(buffer);_device.Clear(Color.Transparent);SpriteBatch spriteBatch =新的SpriteBatch(_device);spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.NonPremultiplied);//用合适的颜色在之前的每个纹理上绘画矩形矩形=新矩形(0,0,宽度,高度);foreach(纹理中的Tuple< Texture2D,Color>纹理)spriteBatch.Draw(texture.Item1,矩形,texture.Item2);spriteBatch.End();_device.SetRenderTarget((RenderTarget2D)null);//将合并的纹理写入Texture2D,因此在调整后缓冲区大小时不会丢失它//这是强大的丑陋代码,可能非常慢Texture2D mergedTexture = new Texture2D(_device,width,height);Color [] content = new Color [width * height];buffer.GetData< Color>(内容);mergedTexture.SetData< Color>(内容);返回mergedTexture;} 

我想我应该检查IsContentLost并根据需要重新渲染,但这发生在我的主绘制循环中间,当然您不能嵌套SpriteBatches.我可以维护一个渲染待办事项"列表,在主SpriteBatch结束后处理这些列表,然后将它们用于下一帧.那是首选策略吗?

此代码仅被调用几次,因此性能不是问题,但我想学习如何正确地做事.

解决方案

实际上,如果您在通常加载内容(游戏开始,关卡更改,房间变更等).您正在CPU和GPU之间传输纹理,就像加载普通的纹理一样.很简单而且有效!

如果您越来越频繁地生成纹理,并且它开始变成每帧成本,而不是加载时间成本,那么您将要担心其性能,并可能将其保留为渲染目标./p>

您不应在图形中间看到 ContentLost ,因此您可以放心地响应该事件并重新创建渲染目标.或者,您可以检查它们中的每个 IsContentLost ,最好在渲染任何其他内容之前在帧的开头.无论哪种方式,都应在 SpriteBatch 开始之前检查所有内容.

(通常,在使用渲染目标时,无论如何都要在每个帧上重新生成它们,因此在这种情况下无需检查它们.)

XNA noob here, learning every day. I just worked out how to composite multiple textures into one using a RenderTarget2D. However, while I can use the RenderTarget2D as a Texture2D for most purposes, there's a critical difference: these rendered textures are lost when the backbuffer is resized (and no doubt under other circumstances, like the graphics device running low on memory).

For the moment, I'm just copying the finished RenderTarget2D into a new non-volatile Texture2D object. My code to do so is pretty fugly, though. Is there a more graceful way to do this? Maybe I'm just tired but I can't find the answer on Google or SO.

Slightly simplified:

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;
    }

I suppose I should check for IsContentLost and re-render as needed, but this happens in the middle of my main drawing loop, and of course you can't nest SpriteBatches. I could maintain a "render TODO" list, handle those after the main SpriteBatch ends, and then they'd be available for the next frame. Is that the preferred strategy?

This code is only called a few times, so performance isn't a concern, but I'd like to learn how to do things right.

解决方案

Actually your code is not so bad if you're generating textures in a once-off process when you'd normally load content (game start, level change, room change, etc). You're transferring textures between CPU and GPU, same thing you'd be doing loading plain ol' textures. It's simple and it works!

If you're generating your textures more frequently, and it starts to become a per-frame cost, rather than a load-time cost, then you will want to worry about its performance and perhaps keeping them as render targets.

You shouldn't get ContentLost in the middle of drawing, so you can safely just respond to that event and recreate the render targets then. Or you can check for IsContentLost on each of them, ideally at the start of your frame before you render anything else. Either way everything should be checked before your SpriteBatch begins.

(Normally when using render targets you're regenerating them each frame anyway, so you don't need to check them in that case.)

这篇关于写入RenderTarget后,如何有效地克隆输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆