Where to call SetRenderTarget? - xna

I'd like to change my RenderTargets between SpriteBatch.Begin and SpriteBatch.End. I already know this works:
GraphicsDevice.SetRenderTarget(target1);
SpriteBatch.Begin()
SpriteBatch.Draw(...)
SpriteBatch.End()
GraphicsDevice.SetRenderTarget(target2);
SpriteBatch.Begin()
Spritebatch.Draw(...)
SPriteBatch.End()
But I'd really like to make this work:
SpriteBatch.Begin()
GraphicsDevice.SetRenderTarget(target1);
SpriteBatch.Draw(...)
GraphicsDevice.SetRenderTarget(target2);
Spritebatch.Draw(...)
SpriteBatch.End()
I've ever seen anybody doing this, but I didn't find any reason why.
EDIT: a little more about why I want to do this:
In my project, I use SpriteSortMode.Immediate (to be able to change the BlendState when I want), and I simply iterate through a sorted list of sprites, and draw them all.
But now I want to apply mutli passes shader on some sprites, but not all! I'm quite new to shaders, but from what I understood, I have to draw my sprite on an intermediate one using first pass, and the draw the intermediate sprite on the final render target using the second pass. (I'm using a gaussian blur pixel shader).
That's why I'd like to draw on the target I want, using the desired shader, without having to make a new begin/end.

The question is: Why do you want to change the render target there?
You won't have any performance improvements, since the batch would have to be split anyways when the render target (or any other render state) changes.
SpriteBatch tries to group the sprites by common attributes, for example the texture when SpriteSortMode.Texture is used. That means sprites sharing a texture will be drawn in the same draw call (batch). Having less batches can improve performance. But you can't change the GPU state during a draw call. So when you change the render target you are bound to use two draw calls anyways.
Ergo, even if the second example would work, the number of batches would be the same.

Related

Fading a 3D object into the background, using D3D9, SH3 & HLSL

I have a simple program that renders a couple of 3D objects, using DirectX 3D 9 and HLSL. I'm just starting off with HLSL, I have no experience with 3D rendering.
I am able to change the texture & color of the models and fade between two textures without problems, however I was wondering what the best way to simply fade a 3D object (blend it with the background) would be. I would assume that it wouldn't be done as fading between two textures (using lerp), since I want the object faded to the entire background, so there would be many different textures behind it.
I'm using the LPD3DXEFFECT as my effect class, DrawIndexedPrimitive as the drawing function in each pass, and I only have a single pass. I'm also using Shader Model 3, as this is an older project.
The only way that I thought it possible would be to simply get the color of the pixel before you apply any changes, and then do calculations on it with the color of the texture of the model to attain a faded pixel. However, after looking over the internet, it does not appear that it's actually possible to get the color of a pixel before doing anything to it with HLSL.
Is it even possible to do something like this using HLSL? Am I missing something that could assist me here?
Any help is appreciated!
Forgive me if I'm misunderstanding, but it sounds like you're trying to simulate transparency instead of using built-in transparency.
If you're trying to get the color of the pixels behind the object and want to avoid using transparency, I'd start by trying to use the last rendered frame as a texture, then reference that texture in your current shader. There may be some way to do it within the same frame - to force all other rendering to go first, then handle the one object - but I don't know it.
After a long grind, I finally found a very good workaround for my problem, and I will try to explain my understanding of it for anyone else that has a smillar issue. Thanks to Alexander Stewart for suggesting that there may be an in-built way to do it.
Method Description
Instead of taking care of the background fade in the HLSL pixel shader, there is another way to do it, using a method called Frame Buffer Alpha Blending (full MS Docs documentation: https://learn.microsoft.com/en-us/windows/win32/direct3d9/frame-buffer-alpha).
The basic idea behind this method is to provide a simple way of blending a given pixel that is to be rendered, with the existing pixel on the screen. There is a formula that is followed: FinalColor = ObjectPixelColor * SourceBlendFactor + BackgroundPixelColor * DestinationBlendFactor, all of these "variables" being groups of 4 float values, in the format (R, G, B, A).
How I Implemented it
Before doing anything with the actual shaders, in my Visual Studio C++ file I have to pass a few flags to my render device (I used LPDIRECT3DDEVICE9 as my device class). I had to set render states for both D3DRS_SRCBLEND and D3DRS_DESTBLEND, which are reffering to ObjectPixelColor and DestinationBlendFactor respectivelly in the formula above. These will be my factors that will be multiplying each one of my object and background pixel colors. There are many possible values that can be assigned to D3DRS_SRCBLEND and D3DRS_DESTBLEND, full list is available in the MS Docs link above, but in order to achieve what I wanted to (simply a way to fade an object into the background with an alpha number going from 0 to 1), I figured out the flags should be like this: SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);.
After setting these flags, before passing through my shaders & rendering, I just needed to set one more flag: SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);. I was also able to alternate between TRUE and FALSE here without changing anything else with no rendering problems (although my project was very simple, it will probably cause issues on larger projects). You can then pass any arguments you want, such as the alpha number, to the HLSL shader as a global variable (I did it using SetValue()).
Going back to my HLSL shader, after these changes, passing a color float4 variable taken from the tex2D() function from my pixel shader with an alpha value between 0 and 1 yielded the correct alpha, provided there aren't other issues (another issue that I had but hadn't realized at the time was the fact that my transparent object was actually rendering before the background, so I can only reccomend to check the rendering order when working on rendering projects).
I'm sure there could have probably been a better way of implementing this with the latest DirectX, but my compiler only supports Shader Model 3 and lower.

Drawing instances with WebGL2 - vertexAttribDivisor

I'm learning webgl2 from https://webgl2fundamentals.org. I'm learning about instancing right now. I can get the demo to work, where it draws many crosses, and I can get it to work with 500 instances.
But I cannot add anything else to the scene. I have a simple triangle that renders fine without the instancing, but with the crosses added the triangle disappears. I believe it has to do with gl.vertexAttribDivisor. I'm not sure when I need to call it, or if I need to undo it somehow.
If I omit calls to vertexAttribDivisor, the crosses don't render correctly, but the triangle is fine. If I replace the call to vertexAttribDivisor, the triangle disappears.
When do I call gl.vertexAttribDivisor? Do I have to undo the call to resume normal, non-instanced rendering? What does it really do?
The vertex attribute functions change a single global state. vertexAttribDivisor sets the divisor for a specified generic vertex attribute (one of the globally available ones), for every draw* call you want to setup the attributes using vertexAttribPointer and vertexAttribDivisor, if you changed the divisor for an attribute for one draw call but don't want to use the same divisor for your following draw call you need to reset it.

HLSL: Handle lack of TexCoords?

I'm in the process of writing my first few shaders, usually writing a shader to accomplish features as I realize that the main XNA library doesn't support them.
The trouble I'm running into is that not all of my models in a particular scene have texture data in them, and I can't figure out how to handle that. The main XNA libraries seem to handle it by using a wrapper class for BasicEffect, loading it through the content manager and selectively enabling or disabling texture processing accordingly.
How difficult is it to accomplish this for a custom shader? What I'm writing is an generic "hue shift" effect, that is, I want whatever gets drawn with this technique to have its texture colors (if any) and its vertex color hue shifted by a certain degree. Do I need to write separate shaders, one with textures and one without? If so, when I'm looping through my MeshParts, is there any way to detect if a given part has texture coordinates so that I can apply the correct effect?
Yes, you will need separate shaders, or rather different "techniques" - it can still be the same effect and use much of the same code. You can see how BasicEffect (at least the pre-XNA 4.0 version) does it by reading the source code.
To detect whether or not a model mesh part has texture coordinates, try this:
// Note: this allocates an array, so do it at load-time
var elements = meshPart.VertexBuffer.VertexDeclaration.GetVertexElements();
bool result = elements.Any(e =>
e.VertexElementUsage == VertexElementUsage.TextureCoordinate);
The way the content pipeline sets up its BasicEffect is via BasicMaterialContent. The BasicEffect.TextureEnabled property is simply turned on if Texture is set.

XNA beginner question about draw method

I understand that I have to draw everything in draw(), and it's looping continuously.
But I don't want to draw texture again and again, for example I want to create a texture, draw something to texture (not spritebatch). than I will only draw that texture in draw().
Is it possible?
What can I use?
You have to draw again and again, as in short, if you dont it wont show. A wise man once wrote in a windows development book
Ask not why the text on your windows has to be constantly drawn, ask why it never used to be in DOS/Unix command line.
If something is placed over the area you're drawing too, and you dont redraw it, it just simply wont be there. You need to keep drawing it for it to be sustained on screen. Its done very quickly and wont hurt anything (especially if you're thinking in terms of background)
Not drawing it again is a performance optimisation. You should only do that if you really need to.
If you do need to do this, create a render target, draw your scene to the render target, and then draw your render target to the screen each frame (using SpriteBatch makes this easy) instead of your scene.
Take a look at this question about caching drawing using render targets.

Implementing a PostProcessing manager

I have been thinking about how to implement a PostProcessing manager into my engine (Vanquish).
I am struggling to get my head around how a Post Processing technique works. I have read and viewed the Post Processing sample on the creators.xna.com webiste, but this seems to re-render the model applying the Post Processing effect.
I can add this functionality for static models, but when it comes to redrawing the Skinned Models, I then get confused as they already have their own techniques to their effects.
Can someone help me straighten my thoughts by pointing me in the right direction?
Generally post-processing works over the entire screen. This is pretty simple, really.
What you do is set a render target on the device (I assume you can figure out how to create a render target from the sample):
GraphicsDevice.SetRenderTarget(renderTarget);
From this point onward everything you render will be rendered to that render target. When you're done you can set the device back to drawing to the back buffer:
GraphicsDevice.SetRenderTarget(null);
And finally you can draw using your render target as if it were a texture (this is new in XNA 4.0, in XNA 3.1 you had to call GetTexture on it).
So to making a post-processing effect:
Render your scene to a render target
Switch back to the back buffer
Render your render target full screen (using SpriteBatch will do) with a pixel shader that will apply your post-processing effect.
You sound like you want to do this per model? Which seems kind of strange but certianly possible. Simply ensure your render target has a transparent alpha channel to begin with, and then draw it with alpha blending.
Or do you not mean post-processing at all? Do you actually wish to change the pixel shader the model is drawn with, while keeping the skinned model vertex shader?

Resources