2
\$\begingroup\$

I'm not sure if everything's working as it should be or whether I'm just not doing something properly, but I couldn't find anything that discussed this so I thought I'd ask here.

I'm using Monogame 3.2 for Windows.

In my game I'm drawing sprites to the back buffer, then I set a render target and draw to that, then I switch back to the back with SetRenderTarget(null) so I can draw my render target but I find that all the drawing I did before I set the render target the first time has been cleared. Is this just how it works or have I done something wrong?

EDIT: The pink rectangle is the render target.

Here is example code:

        // Render some stuff first
        spriteBatch.Begin();
        spriteBatch.Draw(mPixel, new Rectangle(10, 10, 500, 50), Color.Red);
        spriteBatch.End();

        // Render to target
        GraphicsDevice.SetRenderTarget(renderTarget);
        GraphicsDevice.Clear(Color.Pink);
        spriteBatch.Begin();
        spriteBatch.Draw(mPixel, new Rectangle(10, 10, 500, 50), Color.Blue);
        spriteBatch.End();

        // Render back to backbuffer
        GraphicsDevice.SetRenderTarget(null);
        spriteBatch.Begin();
        spriteBatch.Draw(renderTarget, Vector2.Zero, Color.White);
        spriteBatch.End();

Here is the result, I expected the first red rectangle to remain behind the render target: enter image description here

\$\endgroup\$
  • \$\begingroup\$ Haven't used XNA but DX, but shouldn't you set the rendertarget back to backbuffer and not null? This is what you do in DX at least or otherwise all the rendering is ignored \$\endgroup\$ – JarkkoL Sep 23 '14 at 0:25
  • \$\begingroup\$ in XNA setting the render target to null sets it to the back buffer. It's more for setting it to custom render targets \$\endgroup\$ – Joseph Little Sep 23 '14 at 17:27
  • \$\begingroup\$ It looks like it's not being cleared, but you're drawing over what you had previously draw when you draw the render target. \$\endgroup\$ – fastinvsqrt Sep 24 '14 at 20:30
  • \$\begingroup\$ The pink rectangle is the render target, so since it doesn't physically cover the first rectangle I drew I thought it wouldn't affect anything. Or is this not the case? \$\endgroup\$ – Joseph Little Sep 25 '14 at 16:06
4
\$\begingroup\$

Having the exactly same issue here - the following code snipped works perfectly fine:

private void DoRenderSkybox (GameTime Time) {
  this.Device.SetRenderTarget(this.GridTexture);
  this.Device.SetRenderTarget(null);


  // compute a temporary transformation matrix containing
  // the combined world and projection transfromation
  Matrix WorldViewProjection = this.Camera.View * this.Camera.Projection;

  // set the render target to the back buffer in any case
  this.Device.SetRenderTarget(null);

  // assign the vertex - declaration and the vertex- and the index - buffer
  this.Device.SetVertexBuffer(this.SkyboxVertices);
  this.Device.Indices = this.SkyboxIndices;

  // choose the appropriate technique for the current render pass
  this.SceneEffect.CurrentTechnique = SceneEffect.Techniques["Skybox"];
  this.SceneEffect.CurrentTechnique.Passes[0].Apply();
  this.SceneEffect.Parameters["WorldViewProjection"].SetValue(WorldViewProjection);

  // finally render the sykbox with disabled depth stencil buffering
  this.Device.DepthStencilState = DepthStencilState.None;
  this.Device.DrawIndexedPrimitives( PrimitiveType.TriangleList, 0, 0, 36, 0, 12);
  this.Device.DepthStencilState = DepthStencilState.Default;


  //this.Device.SetRenderTarget(this.GridTexture);
  //this.Device.SetRenderTarget(null);
}

However, if I assign (and right away unassign) the render target at the end of the function like so:

    private void DoRenderSkybox (GameTime Time) {
  //this.Device.SetRenderTarget(this.GridTexture);
  //this.Device.SetRenderTarget(null);


  // compute a temporary transformation matrix containing
  // the combined world and projection transfromation
  Matrix WorldViewProjection = this.Camera.View * this.Camera.Projection;

  // set the render target to the back buffer in any case
  this.Device.SetRenderTarget(null);
  this.Device.Clear(Color.Black);

  // assign the vertex - declaration and the vertex- and the index - buffer
  this.Device.SetVertexBuffer(this.SkyboxVertices);
  this.Device.Indices = this.SkyboxIndices;

  // choose the appropriate technique for the current render pass
  this.SceneEffect.CurrentTechnique = SceneEffect.Techniques["Skybox"];
  this.SceneEffect.CurrentTechnique.Passes[0].Apply();
  this.SceneEffect.Parameters["WorldViewProjection"].SetValue(WorldViewProjection);

  // finally render the sykbox with disabled depth stencil buffering
  this.Device.DepthStencilState = DepthStencilState.None;
  this.Device.DrawIndexedPrimitives( PrimitiveType.TriangleList, 0, 0, 36, 0, 12);
  this.Device.DepthStencilState = DepthStencilState.Default;


  this.Device.SetRenderTarget(this.GridTexture);
  this.Device.SetRenderTarget(null);
}

nothing is being rendered - I got a purple screen! Does that make any sense to you!

P.S. I know the sample doesn't make much sense (like assigning and right away unassigning a render target). The real scenario here is much more complicated but I was able to narrow down the essence of the problem to this strange behaviour, which I can demonstrate in this very simple example!

EDIT: Just found the solution by further examining the API: Adding Params.RenderTargetUsage = RenderTargetUsage.PreserveContents; into the PresentationParameter structure solves the problem.

It looks to me that the content of the backbuffer is - like with render targets being destroyed whenever you switch to another render target.

\$\endgroup\$
  • \$\begingroup\$ Thanks! I've been using a work around for this for a long time now but I appreciate your answer :) \$\endgroup\$ – Joseph Little Jan 28 '15 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.