What I am trying to do is use a spritesheet to create a blended terrain, save that as a texture, and then pass it into a shader for additional effects. However, I am having some issues with the render target:
RenderTarget2D someNewTexture = new RenderTarget2D(GraphicsDevice, 256, 256);
GraphicsDevice.SetRenderTarget(someNewTexture);
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
{
// draw some stuff
}
spriteBatch.End();
GraphicsDevice.SetRenderTarget(null);
Obviously, this creates a black background with my texture on top of it. However, when I actually draw that texture onto my main scene, I don't want the background, only the texture (if I don't use clear, I get the default purple color instead). How do I fix this?
Use a transparent clear color:
GraphicsDevice.Clear(Color.TransparentBlack);
If you handle blending correctly, it will result in transparent pixels not to be drawn.
Related
This may be a strange question, but I'm trying to find a way to render sprites only inside a specific allowed area rather then the entire buffer/texture.
Like so:
Basically allowing me to draw to the buffer or texture2D as I normally would, but with actual drawing happening only inside this specified area and remaining pixels outside of it remaining untouched.
Why this is needed - I'm building my own UI system and I would like to avoid using intermediary buffers as it is quite slow when there are many UI components on the screen (and each has to draw to their own buffer to prevent child elements being drawn outside of parent bounds).
And just to clarify - this is all for simple 2D rendering, not 3D.
If your UI is actually drawn with SpriteBatch you can use ScissorRectangle
GraphicsDevice.RasterizerState.ScissorTestEnable = true;
spriteBatch.GraphicsDevice.ScissorRectangle = ...
In 3D, you can render to a texture and draw just a portion of it - or with a shader (you could actually just send in the dimensions as parameter and set it to black in PixelShader if the Pixel is outside that Rectangle (or whatever you want to accomplish)
You can use:
spriteBatch.Draw(yourTexture,
//where and the size of what you want to draw on screen
//for example, new Rectangle(100, 100, 50, 50)//position and width, height
destinationRectangle,
//the area you want to draw from the original texture
//for example, new Rectangle(0, 0, 50, 50)//position and width, height
sourceRectangle,
Color.White);
Then it will only draw the area that you chose before. Hope this helps!
What I would like to do is to be able to draw a specific set of sprites within a spriteBatch with additive blending. The problem is that the draw order that they're drawn in needs to be preserved and I can't draw everything else in the SpriteBatch with additive blending, so I can't just do this:
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
//Draw some stuff here
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.Additive);
//Draw stuff with additive blending here
spriteBatch.End();
So my solution would be to write a shader to do what I need and just do this:
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
//Draw some stuff here
foreach(EffectPass pass in AdditiveShader.CurrentTechnique.Passes)
{
pass.Apply()
//Draw stuff with additive shader applied here
}
spriteBatch.End()
But pass.Apply() is literally doing nothing. Even if I try just using a BasicEffect and have it rotate a few degrees, it's doing nothing. The only way I can get it to do anything is to call it like this:
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend,
null, null, null, AdditiveShader);
Then it actually does something to sprites, but that doesn't really help me because I want to only apply it to specific sprites and still retain the draw order.
What am I doing wrong when using pass.Apply()? Is there a way to draw a set of sprites with additive blending and another set with alpha blending and still keep the draw order? Any help would be greatly appreciated. Thanks.
EDIT: For clarification, I'm working in 2D.
OK, so what I found (Thanks to Shawn Hargreaves - http://blogs.msdn.com/b/shawnhar/archive/2010/04/05/spritebatch-and-custom-renderstates-in-xna-game-studio-4-0.aspx) is that I can use GraphicsDevice.BlendState = BlendState.Additive to change the BlendState on the fly.
So what I did was this:
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Alpha);
//Draw with alpha blending here
GraphicsDevice.BlendState = BlendState.Additive;
//Draw specific sprites with additive blending here
GraphicsDevice.BlendState = BlendState.Alpha; //Revert the blendstate to Alpha
//Draw more stuff here with alpha blending
spriteBatch.End();
The problem is that the SpriteSortMode for the spriteBatch has to be set to Immediate or GraphicsDevice.BlendState = BlendState.Additive will do nothing.
So I suppose I'll have to use a custom DepthStencilState to replicate the functionality of SpriteSortMode.FrontToBack.
I'm stuck for several days now. What I'm trying to achieve shouldn't be that hard, but I cannot figure it out.
I want to blend two sprites together and only get the overlapping part as a result (the blue part in the image). The limitation that I have is it must be under the Reach-profile (limited blending options and no shaders). Because of that I cannot figure out how to blend both sprites to get the result.
I do have stencilmasks for both sprites and the white in the image is transparent (and should also be transparent in the resulting image).
This is the code I have so far:
//Set the render target
spriteBatch.GraphicsDevice.SetRenderTarget(rtFinal);
//Clear the renderTarget
spriteBatch.GraphicsDevice.Clear(Color.Transparent); //I need transparent result
//Clear the stencil's buffer
spriteBatch.GraphicsDevice.Clear(ClearOptions.Stencil, Color.White, 0, 0);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive); //Adding the two sprites together
spriteBatch.Draw((rtCutOut as Texture2D), Vector2.Zero, Color.White); //Unsure about this color
spriteBatch.Draw(ent.StencilTex, Vector2.Zero, Color.Blue); //Using the other stencil
spriteBatch.End();
This code results in (not what I want):
I do understand why I get this result (because it's just an additive render), but I don't know how to get it right (cutting of the non-overlapping parts).
I can also get the following result:
But that's with one of the stencils using a white background instead of a transparent one.
Please help, before I lose my sanity...
I'm working on a project. All 2D using spriteBatch.
I'm having things like explosions use custom effects that do not apply to the rest of the image. So here is my flow so far:
1)Clear the Background
2)Draw all the explosion sprites
3)Capture that image and implement my effects into a separate RenderTarget2D
4)Draw my Background
5)Draw the RenderTarget2D created in step 3
6) Draw everything else
The problem I'm running into is the RenderTarget2D created is not transparent in the areas not drawn on. As a result, the background drawn in step 4 is not shown.
I have tried GraphicsDevice.Clear(Color.Transparent) following any calls to SetRenderTarget(null). However, I am still getting that purple background.
Any ideas?
I'd post code, but there's too much for you all to have to parse through.
if you follow this flow it should work;
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.Clear(Color.Transparent);
// Draw stuff to texture
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(BackgroundColor); // Important to clear here
// Draw background
// Draw texture
// Draw stuff
I'm attempting to change RenderTargets at runtime, so I can draw some elements at runtime, manipulate them and then finally draw the texture to the screen. Problem is, the screen turns purple if I change the RenderTarget at runtime. Here's the code I've got in Draw:
RenderTarget2D tempTarget = new RenderTarget2D(GraphicsDevice, 128, 128, 1,
GraphicsDevice.DisplayMode.Format, GraphicsDevice.PresentationParameters.MultiSampleType,
GraphicsDevice.PresentationParameters.MultiSampleQuality, RenderTargetUsage.PreserveContents);
GraphicsDevice.SetRenderTarget(0, tempTarget);
GraphicsDevice.Clear(ClearOptions.Target, Color.SpringGreen, 0, 0);
GraphicsDevice.SetRenderTarget(0, null);
It doesn't seem to matter how I create the RenderTarget, if I do it at runtime (and I do need to create in-memory textures at runtime and draw on them with SpriteBatch) it results in an entirely purple screen. What can I do to fix this?
It looks like the best option is to create the RenderTarget somewhere other than Draw, draw to it during Update, save the resulting texture (and manipulate as necessary) then draw that texture during Draw.
I know this is late, but the solution is to write to the RenderTarget BEFORE you clear the screen and beginning drawing your other items.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.SetRenderTarget(_renderTarget);
//...
//Perform Rendering to the specified target
//...
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.CornflowerBlue);
//...
//Code that draws to the users screen goes here
//...
}
This should prevent you from rendering in the Update method as suggested by others, which is counter-intuitive in many aspects.
When spritebatch.End() is called objects are written to the backbuffer or in your case to tempTarget. To make the texture,
change the target
call begin
call all of the draws
end the spritebatch
set target back to null
then use the render2d