Gaussian Blur PP Pixel Shader

Posted By: TSG_Torsten

Gaussian Blur PP Pixel Shader - 12/15/10 22:40

Hi all,

for some time I wasn't very active in the forums, so I hope some of you still know me laugh

I want to post a small piece of code I was working one since I think may some of you could use it.

GS includes a pp_gaussian.fx shader file, which is great, but I missed a way to set the strength of the gaussian blur filter.
So, I was working on it to make it possible to change the strength.

But, before any codes, of course everyone wants to see a picture laugh


As already mentioned, I used the essential GS-gaussian-filter file and just added the strength-option and changed the sample-algorithm.

pp_gaussian.fx File:
Code:
// Gaussian Blur PixelShader 2.0
// Template from GameStudio
// Changed by Torsten Simon - © 2010
// Accepts incomming skill1 - strength (0 ... 10)
// mat_name.skill1=floatv(0...10);


#include <define>

float4 vecSkill1;
// Min: 0, Max:10

Texture TargetMap;
sampler2D g_samSrcColor = sampler_state { texture = <TargetMap>; MipFilter = Linear;	};

float4 vecViewPort;

float4 postprocessing_gaussian(float2 Tex : TEXCOORD0) : COLOR0 
{   
	// If Strength>5 -> More samples needed
	bool hard=vecSkill1.x>5;
	
	
	// Real sample	
   float4 sampleM  = tex2D(g_samSrcColor, Tex.xy);
   
   // Moved samples
	float4 sampleB0 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw );
	float4 sampleF0 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw );
	float4 sampleB1 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*3. );
	float4 sampleF1 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*3. );
	float4 sampleB2 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*4. );
	float4 sampleF2 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*4. );
	
	float4 sampleB3 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*5. );
	float4 sampleF3 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*5. );
	float4 sampleB4 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*8. );
	float4 sampleF4 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*8. );
	
	float4 sampleB5;
	float4 sampleF5;
	float4 sampleB6;
	float4 sampleF6;
	if(hard)
	{
	// Additional samples for high strength
	sampleB5 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*11. );
	sampleF5 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*11. );
	sampleB6 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*14. );
	sampleF6 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*14. );
	}

	// Brightness calculation script
	float s=(10-vecSkill1.x)*0.0512;
	float r=vecSkill1.x/5;
	float facSub=0;
	float facHard;
	if(hard)
	{
	float temp=((vecSkill1.x-5)/5);
	facSub=temp*0.0050;
	facHard=temp*0.0261;
	}
	float fac=(0.0261-facSub)*r;	
	float4 ret; // return variable
	if(hard) ret=(s * sampleM + fac * (sampleB0 + sampleF0) + fac * (sampleB1 + sampleF1) + fac * (sampleB2 + sampleF2)+ fac * (sampleB3 + sampleF3)+ fac * (sampleB4 + sampleF4)+ facHard * (sampleB5 + sampleF5)+ facHard * (sampleB6 + sampleF6))*1.8;
	else ret=(s * sampleM + fac * (sampleB0 + sampleF0) + fac * (sampleB1 + sampleF1) + fac * (sampleB2 + sampleF2)+ fac * (sampleB3 + sampleF3)+ fac * (sampleB4 + sampleF4))*1.8;
	return ret;
}

technique PostProcess 
{
	pass p1 
	{
		AlphaBlendEnable = false;	
		VertexShader = null;
		PixelShader = compile ps_2_0 postprocessing_gaussian();
	}
}



Just create a file named "pp_gaussian.fx" in your project folder and paste the code.

You can implement it like this:
Code:
// Get the GS view import
#include <mtlView.c>
function main()
{
pp_set(camera,mtl_gaussian);
mtl_gaussian.skill1=floatv(7); // enter a value between 0 and 10
}



Please be aware that the look of the strength depends on the current window/screen resolution.

This is my first shader, so feel free to optimize or "correct" it. Have fun!

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/15/10 22:56

Your screens are a bit blurry
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/15/10 23:16

Sorry to write this, but, you know what a gaussian BLUR shader is? wink

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 01:17

Yeah was just in a laughing mood tongue. Nice work on it. Doesn't seem to work on draw_line functions though. But I'm sure that's an inability of 3dgs rather than your sample.
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/16/10 12:03

That's correct, anything within the gui like PANEL, TEXT or draw_line won't be blurred. Post-Processing shaders only apply to the given camera-view and everything that is visible in there.
To make blurry lines, try using draw_line3d.

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 14:31

Pretty awesome, it works laugh. You are blurring in one direction though, that's quite well visible on draw_line3d. Isn't gaussian a non-directional blur?

Edit:
For fun, when I move the blur is applied.

Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/16/10 15:39

Nice to hear that you can use it wink

Well, you're right, actually gaussian should be a non-directional blur filter. But the template already was designed to move the samples directional. Unfortunaley, I still didn't find a way to render the samples non-directional. If I have some time, I will try to change the code.

Do you have any significant performance issues using the shader? Or is everything fast enough? wink

Regards
TSGames
Posted By: Hummel

Re: Gaussian Blur PP Pixel Shader - 12/16/10 15:41

Doesnt look like you are using real gaussian weights, so it´s actually not a gaussian-blur. Also Joozey is right, the blur should be non-directional.
Another thing: using something like '#define HARD' instead of 'if(hard)' is smarter and faster.
Posted By: Pappenheimer

Re: Gaussian Blur PP Pixel Shader - 12/16/10 18:01

You made me curious about the "#define" versus "if()". And, I asked myself how you write a define with several lines.
In case someone cares, I found this about those defines:
http://www.coker.com.au/russell/ccode/macros.html
Posted By: Hummel

Re: Gaussian Blur PP Pixel Shader - 12/16/10 18:32

Code:
#ifdef HARD	
	// Additional samples for high strength
	sampleB5 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*11. );
	sampleF5 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*11. );
	sampleB6 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*14. );
	sampleF6 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*14. );
	#endif


instead of
Code:
if(hard)
	{
	// Additional samples for high strength
	sampleB5 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*11. );
	sampleF5 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*11. );
	sampleB6 = tex2D( g_samSrcColor, Tex.xy - vecViewPort.zw*14. );
	sampleF6 = tex2D( g_samSrcColor, Tex.xy + vecViewPort.zw*14. );
	}


was what I meant.

Using 'if' the shader checks whether you want to use the 'hard' version every frame for every screen pixel. Thats slow.
Posted By: Pappenheimer

Re: Gaussian Blur PP Pixel Shader - 12/16/10 18:49

Thanks. Any hints, why "#ifdef" is faster than "if()"?
(Sorry, TSG_Torsten for hijacking your thread.)

EDIT: Thanks, Joozey. I missed the "every pixel" in Hummel's explanation.
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 19:06

Because the compiler evaluates the #ifdef only once, whereas the if() gets executed for every pixel every frame as Hummel says. So the #ifdef is here faster by definition laugh.

TSG_Torsen:
No, no performance issues. My laptop is really crappy at processing stuff like shaders, but this goes fine. Must be said that it isn't exactly a large area of pp shading here tongue. My game is 352x512 pixels grin.
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/16/10 19:30

Thanks for the hint with ifdef, haven't thought about it before, and this is quite a good idea!

Anyway, I've re-written the whole shader... So, now it is really direction-independent... voila:


You can set a lot more options now in the shader-file.
By default, PS 3.0 is needed, but take a look into the file if you need a PS 2.0:
Code:
// Gaussian Blur PixelShader 3.0
// By Torsten Simon - © 2010

// Accepts incomming:
// skill1 - strength (0 ... 10)
// mat_name.skill1=floatv(0...10);

#define USE_STATIC_VALUES true
// Remove/Comment this line to use material.Skill2...Skill5 for the values below
#define WIDTH 8
// WIDTH in Pixels to distribute the blur, lower values -> faster rendering
#define WIDTH_SKIP 2
// "Jump" Pixels when blurring, higher values -> faster rendering
#define RADIUS 7
// Radius when blurring, higher values -> faster rendering
#define GLOW 0
// Min: 0, Max: 100, Applying a glowing blur effect


// Please Read:
// This shader uses PS_3_0, but if you use the fast, simple blur-parameters
// you can also use PS_2_0. Therefore, change line 123 to
//	PixelShader = compile ps_2_0 postprocessing_gaussian(); 

/* Some Examples to try

// Default (Small, Smooth)
#define WIDTH 8
#define WIDTH_SKIP 2
#define RADIUS 7

// Fast, Simple Blur (Works with PS_2_0 as well!)
#define WIDTH 8
#define WIDTH_SKIP 4
#define RADIUS 45

// Wide Range
#define WIDTH 30
#define WIDTH_SKIP 8
#define RADIUS 10

// Medium Range
#define WIDTH 20
#define WIDTH_SKIP 8
#define RADIUS 15

*/


#include <define>

float4 vecSkill1;
// Min: 0, Max:10

float4 vecSkill5;

Texture TargetMap;
sampler2D g_samSrcColor = sampler_state { texture = <TargetMap>; MipFilter = Linear;	};

float4 vecViewPort;

#define RENDER vecSkill1.x>0

float4 postprocessing_gaussian(float2 Tex : TEXCOORD0) : COLOR0 
{   
	float4 ret=tex2D(g_samSrcColor, Tex.xy);
	#ifdef RENDER
	
	int width,width_skip,radius,glow;
	
	#ifdef USE_STATIC_VALUES
	width=WIDTH;
	width_skip=WIDTH_SKIP;
	radius=RADIUS;
	glow=GLOW;
	#else
	width=vecSkill1.y;
	width_skip=max(vecSkill1.z,1);
	if(width<width_skip) width=width_skip;
	else width+=width%width_skip;
	radius=max(vecSkill1.w,1);
	glow=vecSkill5.x;
	#endif
	
	// Real sample	
   float4 sampleM  = tex2D(g_samSrcColor, Tex.xy);
   
	// Brightness calculation script
	float fac=(vecSkill1.x)*float(float(((float)width_skip/(float)width)/float(360/radius))/10)*((glow+50)/50.f);
	
	float s=(10-vecSkill1.x)*.1+fac;

	ret=s*sampleM; // return variable
	int i=0;
	int dist=width_skip;

	while(dist<=width)
	{
	float4 pos1;
	float round=radians(i);
	pos1.x=Tex.x+sin(round)*vecViewPort.z*dist;
	pos1.y=Tex.y+cos(round)*vecViewPort.w*dist;
	pos1.z=0;
	pos1.w=0;
	float4 S1=tex2Dlod(g_samSrcColor,pos1);
	ret+=fac*(S1);
	i+=radius;
	if(i>=360) {
		dist+=width_skip;
		i=0;
	}
	}
	#endif
	return ret;
}

technique PostProcess 
{
	pass p1 
	{
		AlphaBlendEnable = false;	
		VertexShader = null;
		PixelShader = compile ps_3_0 postprocessing_gaussian();
	}
}



As always, C & C are welcome laugh

[Edit:] And I'm again curious if you run into any performance issue... no problems for me so far @ATI HD 5870 laugh

Have fun!

Regards
TSGames
Posted By: Joey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 19:50

Isn't that incredibly slow? I suggest you blur in x and then in y-direction and exploit the linear interpolation feature of texture sampling.

edit:
http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/16/10 19:59

I'm new to shaders, so if there are ways to design it better (and, for sure, there are wink ), feel free to do and re-post it wink

I'm checking the activity of my GPU, and I've got less than 10% @1980x1080 and 30 FPS, so there are no performance problems for me so far...

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 19:59

Can you make the width, glow and radius also in vecSkill variables? I'd like to change those by events in the game. I tried, but I keep getting errors at the WIDTH in the while loop. Converted the vecskill2 to an integer, but same problem.

I do get a performance issue now. Framerate drops considerably when I use your wide range sample.

EDIT: I say vecSkill2, but that one is still part of the float4 of skill1. skill5 is better tongue.
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/16/10 20:19

I also tried to use vecSkill's to change - but I ran into the same problems. I still didn't find a way to make it possible to change this vars by the engine.

Try using a higher radius (for example 20) or a higher width_skip (for example 14), may it should be faster than.

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 20:25

I briefly tried the shader in joey's link, but that thing doesn't do a very good job. On high range it becomes a cross rather than a complete blur. It requires a vertical blur for each horizontal sample I think. So that's 9*9=81 samples anyway. not 9+9.

Ill ponder a bit more with the vecskills, really want it to work tongue. And yeah I can have a nice setting that gives me a good FPS, luckily.
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 20:59

the tex2d in your loop causes the gradient error to be triggered. If you use tex2dlod, and fill in float4(pos1.x,pos1.y,0,0) for the texture argument, it will work laugh. Found the solution here, also the only thread about it on the whole internet. In English at least. Shaders are SO completely undocumented.

http://www.gamedev.net/community/forums/topic.asp?topic_id=466629

the [loop] keyword as suggested there didnt work for me.
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/16/10 21:43

Thank you for this great tip! But i really don't understand why it doesn't work for the other function... Confusing laugh

I've updated the code above and you can remove the USE_STATIC_VALUES define if you want to use dynamic ones... (if you didn't already have rewritten the shader wink )

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/16/10 21:53

Although mine wasn't yet working good, for some reason your version is very laggy for me. Whatever setting I use I barely get over 10fps, and the game lags a whole lot even for 10fps. This is weird.
Posted By: Slin

Re: Gaussian Blur PP Pixel Shader - 12/16/10 22:22

Blurring in different directions in several passes will always be faster with better result.
The if statements in shaders are also something one has to be very carefull with, as they will always be executed, when using a shader model below 3.0. 3.0 and above uses dynamic branching, which means that the shader kinda compiles to several mutuations, which are than choosen at runtime. While dynamic branching can be a great thing when used wisely, it can cause the shader compiling to take endlessly long and the execution can be very slow, especially if used much.
Another thing which can be very bad are loops. It most cases it is faster to unroll them, which can basicly done by the compiler, but can offer some more freedom when doing it yourself.
When using shaders, there are instruction limits as well as some other limits. I don´t see a way to check a shader for being within those limits, when using loops with a varying counter. Especially, as this has to happen at compile time.
The reason for all these restriction I guess, is basicly that they are meant to run extremely parallel for the best performance possible.
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/17/10 19:56

Originally Posted By: Joozey
Although mine wasn't yet working good, for some reason your version is very laggy for me. Whatever setting I use I barely get over 10fps, and the game lags a whole lot even for 10fps. This is weird.


Does it also lag if you use the STATIC_VALUES var? Or just when using dynamic settings?

@Slin:
The dynamic branching since PS 3.0 sounds interesting, didn't hear about it before. Are there any basic things a shader developer has to do to use it "wisely" as you said?

Regards
TSGames
Posted By: Hummel

Re: Gaussian Blur PP Pixel Shader - 12/17/10 21:48

A short passage from an ATI paper:
Quote:

Dynamic branching
The ATI Radeon HD 2000 hardware has excellent dynamic branching performance for all three shader
stages. Using dynamic branching you can reduce the workload in e.g. a pixel shader by skipping past
instructions that don’t need to be executed. In a lighting situation, if the pixel is in shadow you don’t
need to compute the whole lighting equation but may return zero or the ambient value immediately.
Same thing if the pixel is beyond the light radius. It can be beneficial to rearrange your code so that you
can do some large scale culling early in the shader. For instance attenuation is usually cheap to compute,
so it makes sense to do that first in the shader. Depending on how your shader looks you may sometimes
see better performance if you stick to a small set of branches instead of several branches shortly after
each other. Thus it may be faster to multiply the attenuation with the shadow factor and check that value
against zero, rather than checking attenuation first and then shadow in a separate branch. This varies a
lot with the situation, so it’s recommended that you try both approaches and see which one comes out
faster in your application.
One thing to keep in mind though is that branches need to be coherent to achieve top performance. If
pixels within the same thread take different branches the hardware will have to execute both sides of the
branch and just select the results for each pixel. So for branches that generally are not coherent you will
probably see a performance loss compared to code without branching. For the ATI Radeon HD 2000 you need a coherency of at least 64 pixels or vertices. Anything that varies in smaller units than that in
general should not use dynamic branching. For example you may have the following code:

Code:
float diffuse = dot(lightVec, normal);
if (diffuse > 0.0)
{
// Compute lighting ...
}



If the normal is an interpolated normal across the surface this branch is fine. But if the normal comes out
of a high-frequency normal map this code may result in a performance loss. This is because normals
from a high-requency normal map can typically vary a lot from pixel to pixel. As a result, in most cases
the hardware will not be able to skip past the code within the if-statement, so there is no performance
gain to be had, but you incur a small performance hit from doing the actual branch test and possible
additional register pressure.


Better you google for more information. If you find something interesting let us know. We are as willing to learn as you. wink
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/20/10 21:34

Yes it still lags. Do you still have the previous version? I can't make it not lagging anymore.

EDIT: nevermind, without the ifdef's it seems to work lag-less.
Posted By: TSG_Torsten

Re: Gaussian Blur PP Pixel Shader - 12/22/10 22:58

Strange thing, for me it works... But anyway, you got it work, so everything seems okay now?! wink

Regards
TSGames
Posted By: Joozey

Re: Gaussian Blur PP Pixel Shader - 12/22/10 23:42

Well only with defines, not with skills tongue
© 2024 lite-C Forums