关于c#:渲染到纹理会在XNA中用颜色填充纹理

Rendering to texture fills texture with color in XNA

我正在XNA中工作,但遇到了以下问题:我的目标是将许多不同的纹理绘制到纹理上,然后使用给定的alpha值将最终纹理绘制到屏幕上。

问题是我绘制到的纹理是全屏的,并且填充了颜色而不是透明度,因此它遮挡了其后面的所有内容。

一切都是2d,这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void Draw(SpriteBatch sb)
            {
            if (opacity > 0)
                {
                gd.SetRenderTarget(formTexture);
                gd.Clear(Color.Transparent);
                for (int i=0; i<formItems.Count; i++)
                    {
                    ((FormItem)formItems[i]).draw(sb);
                    }
                sb.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                    for (int i=0; i<formItems.Count; i++)
                        {
                        FormItem fi = (formItems[i] as FormItem);
                        if (fi.glow != null)
                            {
                            sb.Draw(fi.glow, new Rectangle((int) fi.location.X + fi.width/2 - fi.glow.Width/2, (int) fi.location.Y + fi.height/2 - fi.glow.Height/2, fi.glow.Width, fi.glow.Height), Color.White);
                            }
                        }
                sb.End();
                gd.SetRenderTarget(null);
                sb.Begin();
                sb.Draw(formTexture, new Rectangle(0, 0, gd.Viewport.Width, gd.Viewport.Height), Color.White*opacity);
                sb.End();
                }
            }

formTexture是RenderTarget2D对象,gd是图形设备。这是formTexture初始化的方式:

1
formTexture = new RenderTarget2D(this.gd, this.windowWidth, this.windowHeight);

您遇到的问题是,设置渲染目标-并将后缓冲区计为渲染目标-将清除该渲染目标。

至少设置了RenderTargetUsage.DiscardContents(MSDN)。这是默认设置,因为它是唯一在Xbox 360上运行良好的产品,在Xbox 360上,保存内容需要昂贵的副本。 (这是Windows上的默认设置,只是为了保持行为相同的跨平台)。

您的后缓冲将在此行上清除为"哇,这是新鲜的缓冲"颜色(通常是紫色):

1
gd.SetRenderTarget(null);

有两种方法可以解决此问题:

首选方法是对所有渲染进行排序,以便在帧的开头设置渲染目标,然后将场景绘制到后缓冲区。切勿多次触摸渲染目标。

另一种方法是将事件附加到GraphicsDeviceManager.PreparingDeviceSettings,该事件将后缓冲设置为使用RenderTargetUsage.PreserveContents

1
2
3
4
5
6
7
8
9
void SetBackbufferPreserveContents(object sender,
                                   PreparingDeviceSettingsEventArgs e)
{
    e.GraphicsDeviceInformation.PresentationParameters.RenderTargetUsage
            = RenderTargetUsage.PreserveContents;
}

// in your game constructor:
graphics.PreparingDeviceSettings += SetBackbufferPreserveContents;

仅当您的游戏专门针对Windows时,才应使用第二种方法。