Implementing a PostProcessing manager - xna

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?

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.

Is my webgl FBO color attachment being cleared?

I'm trying to render something to texture using a library called regl. I manage to render an effect using two render targets and i see the result in one.
Capturing the frame after i've done rendering to the target looks like this, and it represents a screen blit (full screen quad with this texture). This is how i would like this to work.
Once i pass this to some other regl commands, in some future frame, this texture attachment seems to get nuked. This is the same object that i'm trying to render with the same resource, but the data is gone. I have tried detaching the texture from the FBO, but it doesn't seem to be helping. What can i be looking for that would make this texture behave like this?
This ended up being a problem with Regl and WebViz. I was calling React.useState to set the whatever resource that regl uses for the texture. For some reason, this seems like it was invoked, which "resets" the texture to an empty 1x1.

Where to call SetRenderTarget?

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.

Three.js - What's the most effective way to render a WebGLRenderTarget texture?

Problem
I've gotten to a point in my project where I'm rendering to WebGLRenderTargets and using them as a textures in my main scene. It works, but it seems like I'm having it do a lot more work than it needs to. My generated textures only need to be 64x64, but because I'm using my main renderer (window width by window height) for both, it's unnecessarily rendering the WebGLRenderTargets at a much larger resolution.
I may be wrong, but I believe this increases both the processing required to draw to each RenderTarget and the processing required to then draw that large texture to the mesh.
I've tried using a second renderer, but I seem to get this error when trying to use a WebGLRenderTarget in renderer A after drawing to it from renderer B:
WebGL: INVALID_OPERATION: bindTexture: object not from this context
Example
For reference, you can see my abstracted page here (Warning: Due to the very issue I'm inquiring about, this page may lag for you). I'm running a simplex function on a plane in my secondary scene and chopping it up into sections using camera placement, then applying the segments to tile pieces via WebGLRenderTarget so that they're fluent but individual pieces.
Question
Am I correct in my assumption that using the same renderer size is much less efficient than rendering to a smaller renderer would be? And if so, what do you think the best solution for this would be? Is there currently a way to achieve this optimization?
The size parameters in renderer.setSize() are used by the renderer to set the viewport when rendering to the screen only.
When the renderer renders to an offscreen render target, the size of the texture rendered to is given by the parameters renderTarget.width and renderTarget.height.
So the answer to your question is that it is OK to use the same renderer for both; there is no inefficiency.

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.

Resources