Applying shader to particular scene

Hi,

I have a little bit of a conundrum. Essentially I want to apply a shader to only a few particular sprites, but I need to apply it to all of them at once, not just individually. The way to do this is normally render targets but in this instance it seems impossible to use them. Here is the code and a more in depth run down below:

currentMap.DrawBackground(spriteBatch, currentRoom, camera);
currentMap.DrawMiddleground(spriteBatch, currentRoom, camera);

// Shader applied to this bit :

foreach (Character character in entities)
{
      character.Draw(spriteBatch, camera);
}

currentMap.DrawForeground(spriteBatch, currentRoom, camera);
        
//------------------------------------------

base.Draw(spriteBatch);

Using render targets seems impossible as I would need to switch render targets which will wipe the stuff drawn before getting here, which I don’t want. I could stop it from wiping, but that is slow and I want to try to avoid that. I don’t really want to flush what I have already drawn to the screen as I apply some post processing shaders to the entire game. It seems like an impossible puzzle.

Am I missing something?

Thanks

Which render target are you worrying about wiping?

Can you
Draw all characters to a character render target (with no shader)
Draw that character render target to the main render with the shader applied

I don’t think you need to use a render target, but you do need to use a different sprite batch block.

spriteBatch.Begin(...);
// Draw stuff that doesn't need shader
spriteBatch.End();

spriteBatch.Begin(..., someShader, ...);
// Draw stuff that does need shader
spriteBatch.End();

In your case, it looks like you’d need three blocks…

  • Block to draw map background and middle.
  • Block to draw characters.
  • Block to map draw foreground.

Another option might be to introduce a flag to your shader where, if the flag is true, perform the shader operation, otherwise return the input colour. Ensure the flag is set for your character draws but clear it for everything else.

There might well be other ways, but that’s all I know to suggest for you :slight_smile:

*Edit: You can still use a render target if you like. It’d be the same approach as the blocks…

  • Draw map background and middle to render target 1
  • Draw characters with shader to render target 2
  • Draw map foreground to render target 3.
    … then …
  • Draw render target 1 to screen.
  • Draw render target 2 to screen.
  • Draw render target 3 to screen.

It’s up to you, but no real need to use a rendertarget unless you have something else you want to do (ie, full screen scaling or post processing).

Unfortunately, That is not a valid option with this, as the shader needs to be applied to the result of both of them being drawn. If i just used another sprite batch block, it will apply the shader to each of the sprites, but I want it ot be applied to all of them together.

Oh I see, sorry. Then yes I believe you’d need to use a render target. Use your shader when you draw the render target to the screen. You can draw to the render target before you do any screen rendering at all in a pre draw step…

  1. Set render target.
  2. In batch block (no shader), draw character sprites.
  3. Clear render target
  4. In batch block (no shader), draw map background and middle.
  5. In batch block (with shader), draw render target to screen.
  6. In batch block (no shader), draw map foreground.

Hopefully I’ve understood you correctly now :slight_smile:

1 Like

Thank you very much! I forgot that I could draw to the render target before drawing the other layers to avoid having to switch half way through. Thanks again

1 Like