Welcome to Laser Pointer Forums - discuss green laser pointers, blue laser pointers, and all types of lasers

LPF Donation via Stripe | LPF Donation - Other Methods

Links below open in new window

ArcticMyst Security by Avery

HLSL Coding help

Joined
Feb 5, 2008
Messages
6,252
Points
83
Alright I know there are some advanced coders there,

I recently started getting aquainted with 3D graphics and all, wanna start a few learning projects (among which is a rudimentary 3D engine), and on the way picked up some shader coding.

Anyway, here's the problem.

I have a shader file that has 4 passes. Each pass relies on the result of the one before it.

I am using the shader in managed C# environment, in XNA game studio.

I am having trouble saving the result of each pass and forwarding it to the next. Info on using in-shader texture buffers between passes and general shader scripting is unbelivably scarce on the internet, as well as any simple shader examples.

My ideal solution is to run the shader only once, and within the shader do all the saving of results but I just cannot find any way to do it. If anybody knows, I'd appreciate that first.

Second, if not, I'd appreciate to know what I'm doing wrong with the shader calls in C# code.

Here is the end code of the shader. The actual shader I'm sure works, since I based it off Microsoft's Post process Glow example which uses like, 6 game classes and 3 seperate FX files. I made it into one shader file to be used with one class - simple as.

Code:
technique Bloom 
{
    pass Pass1
    {  
        PixelShader = compile ps_2_0 Extract();
    }
    pass Pass2
    
    {
        PixelShader = compile ps_2_0 BlurHorz();
    }
    pass Pass3 
    
    {
        PixelShader = compile ps_2_0 BlurVert();
    }
    pass Pass4 
    
    {
        PixelShader = compile ps_2_0 Combine();
    }
}

Here is the code to call each individual pass, store the result, and forward it to the next pass:

Code:
spriteBatch.Begin(0, BlendState.Opaque, null, null, null, bloom);

            graphicsDevice.SetRenderTarget(extract);
            bloom.Parameters["procScene"].SetValue(renderOutput);
            bloom.CurrentTechnique.Passes[0].Apply();
            spriteBatch.Draw(extract, Vector2.Zero, Color.White);

            graphicsDevice.SetRenderTarget(blur1);
            bloom.Parameters["blur"].SetValue(extract);
            bloom.CurrentTechnique.Passes[1].Apply();
            spriteBatch.Draw(blur1, Vector2.Zero, Color.White);

            graphicsDevice.SetRenderTarget(blur2);
            bloom.Parameters["blur"].SetValue(blur1);
            bloom.CurrentTechnique.Passes[2].Apply();
            spriteBatch.Draw(blur2, Vector2.Zero, Color.White);

            graphicsDevice.SetRenderTarget(finalRender);
            bloom.Parameters["blur"].SetValue(blur2);
            bloom.CurrentTechnique.Passes[3].Apply();
            spriteBatch.Draw(finalRender, Vector2.Zero, Color.White);

            graphicsDevice.SetRenderTarget(null);
            //spriteBatch.Draw(finalRender, Vector2.Zero, Color.White);
            spriteBatch.End();

As you can see, I am using rendering to texture method for the process rendering.

After this, I have made another Spritebatch.begin to draw 4 textures to 4 quarters of my screen.
Top left would be the rendered 3D geometry, before post process, and rest of three would be results of various passes.

The 3D geometry is rendered nicely, however all subsequent shader pass results are completely empty. Why?
What is the correct way to obtain shader pass result into a texture?

Here is the full shader source code in case I made a logical mistake porting it:
[C] Bloom shader - Pastebin.com

Help appreciated! Much! Lost sleep over this!
 





Joined
Oct 26, 2007
Messages
5,438
Points
83
There's a reason for not using in-code technique passes and that is because you'll probably want to tweak and reuse your effects without recompiling your code. The only time you should be using code-compiled technique systems is if you need some specialized data you need to process mid-step. Even then, you can usually fit that into your script as a call. You should think about just using the technique scripts so that you can concentrate on your game content, not the overhead of repeating what has already been made simple.

Also, what you pasted up there is a technique, not a shader. The shader code itself is a C-like language that gets compiled and executed on the hardware. The technique combines multiple shader applications into passes which take inputs and combine outputs for the final effect. For example, in the Gaussian blur above, it must execute two (or three) shader passes for the final result: one going horizontally, and the other vertically + combine.

For that particular blur shader if you want to cut down on the number of temporary buffers, I think you can pass the result of the first Gaussian blur pass onto the second pass as an input and it'll work just fine, skipping the combine step. You can't get around the use of buffers in a Gaussian blur because it reduces the computational complexity of the calculation. The combine step above might also be including the extra bloom effect -- combining it with the input.

What you might want to check on your technique is what your inputs are, and what is required for your Bloom effect. There are many Bloom effects, and they require multiple input buffers to determine what is bright and bloomy, what is background image, etc. The technique script may already have these defined elsewhere, but your compiled code may need to explicitly define where this data is coming from.
 
Last edited:
Joined
Feb 5, 2008
Messages
6,252
Points
83
Thanks for all the optimization tips, but that's one step above what I need now : finally getting it to render.

Even if un-optimized, as long as I can get a result I can see, I'll happily dwelve into optimizations.

BTW, it's not Gaussian blur, not a true Gaussian generated curve. I have used a break-point to determine precisely what data is forwarded into the buffers for blurring, and I came up with a very simple algorithms that generate almost exact same values, only in like, 1/10 time or so, and currently I'm looking into porting the data generation itself on GPU to save on CPU time which is overtaxed anyway with abstracted and managed DirectX code used through C# language.

Anyway, you spoke of scripts. I can see scripts being set and used in example projects I download with FX Composer, however, it appears that an amazingly small amount of googling results all point out to string script constants being used exclusively by FX Composer environment to simulate the pass handling code you'd normally write in the program calling the shader itself.

I have decided for now, to split the shader code into individual passes so that I can at least, through breakpoints, monitor the values passed between them.

Once I figure out the correct way to use this shader and finally render a bloom effect, I will work on porting entire process to the GPU to save on CPU time, but like I said. First things first, and that being said,

Is there a way to direct a Pass within a shader to a variable inside the shader code itself, so I can simply call all passes in sequence and get final output out? If not, what is the correct way of chanelling the output data for these passes so I can get some result?

It appears that, no matter what I do, I cannot get even the result of the very first pass, Extract. The texture stays blank, as if no data was being output to it at all.

How to correctly set guddam render target? And why is info on these things so surprisingly rare? Googling anything regarding to my problems will reveal official MS instructions for outdated XNA 3.1 studio, maybe one tutorial site that shares similarities to my problem, and a dozen unanswered forum messages. It's frustrating.
 
Joined
Feb 5, 2008
Messages
6,252
Points
83
I have solved it by implementing a quad to draw as user indexed primitive, adding a vertex shader and upgrading shader structs.

If anybody is remotely interested, I'll post source code.
 
Joined
Oct 26, 2007
Messages
5,438
Points
83
Good that you were able to figure out what was wrong. You might want to check out Ogre3D, or mOgre if you're using C#. It's well documented and has a great message board full of helpful people. It's also not far different than the XNA stuff you're attempting, and also more generic since you can use it on other platforms as well.

Look at the compositor example if you want to see how to directly deal with pass infrastructure and/or apply extra special effects that may be hard to accomplish in shaders.
 
Last edited:
Joined
Feb 5, 2008
Messages
6,252
Points
83
Thanks, I'm kinda partial towards Unity since of all the hype, I also heard about Ogre and all,

But my interest is not skip to the part of creating the game with finished engine.

I want to try and write my own 3D engine, see how far I get. The best part is, the farther I get, the more I understand how professional games work and how impossibly impressive everything is :D

So far I got 3D camera controls, Skybox mapping and post process effects. Now I am starting work on Level, so I have something to move through, Player and related hierarchy objects (weapons, targets, etc), and OMFGWTF of them all, RK4 integrator for collision detection... should be fun! :D

Anyway I'm most glad I got the shaders down and all. It should come in very handy.
 




Top