B Info Shader Post Process Shaders and Effects (LENSFLARES, SSAO, DOF)

Users who are viewing this thread

La Grandmaster

Sergeant Knight at Arms
Warbands postfx system is rarely modded much which is a shame as it can really alter the overall feel/look of a mod. Recently in another thread (http://forums.taleworlds.com/index.php/topic,333534.0.html) I explained how you could add some simple postfx to mods but they were quite simple. In this thread I decided to do some more complicated post process effects and eventually release these as OSP, but I thought Id post them here for feedback first, as once released it is unlikely that I will updating these much. These are all done inside warband, and do not use an ENB system (which means they have very little performance impacts). Not one of these images has been touched up or altered in photoshop, they are taken straight from warband.

I have managed to get a depth of field effect working in warband along with very basic SSAO (Screen Space Ambient Occlusion). There are two types of DoF i plan to include in the pack, one which blurs things in the far distance. And another which blurs things depending on what the player is looking at.

The SSAO at the moment is quite buggy but hopefully I will be able to get it working.

Depth of Field (DoF)
Basically blurs the screen depending on what the camera is focusing on, Ive never seen this done in M&B before so im quite proud of it  :wink:

Focusing on something far away (notice up close things are blurred)
3GCz33U.jpg

Focusing on something up close (notice far away things are blurred)
hkPL3oq.jpg

Other pics
CPHxnYa.jpg

YeKuXu1.jpg

aS2qycL.jpg


Test SSAO shader (Screen Space Ambient Occlusion)
SSAO basically adds extra shadows, the shader still needs a lot of work, but on the plus side it is quite cheap at the moment.
In the images it shows - ssao off, ssao on, and then finally ssao on its own without coloring

asDKZB.gif

iEuCu3.gif

I think i need to blur it a bit (but unfortunately blurring makes this much more expensive). Yoshiboy has made an SSAO shader in the past but his code is quite different to mines. The effect he managed to produce was much better however his code made osp is not complete and cannot be implemented that easily.

These are all done inside warband, the images have not been touched in photoshop and no ENB system is used.

Basically I would like to know whether the blurring is too much, whether shadows are too strong, and if anyone knows (coding wise) how to get a better looking SSAO effect.
 

cmpxchg8b

Count
M&BWBWF&SNW
For SSAO you really want to remove any occlusion if the depth difference between two texels is too large.
For example:
XK1S5lF.jpg

there is no way that wooden pole ends up occluding a wall 2 meters behind it.
 
I had no idea you could access the depth value on warband post-shaders. I might have to look into making some of my own, I've got a few ideas...

I have no idea what language the code's written in though. Is it a warband "in-house" version of OpenGL like the module system is to python? If so is there any official documentation anywhere?

But as cmp said the SSAO is a bit aggressive. Have a look at the pitchfork in the first image. Given how much stuff sticks out like that in warband, and how little attached things protrude, it would be a good idea to reduce the depth threshold to something like half a metre to prevent nonsensical occlusion between, say, a shield and its owner. SSAO tends to look horrible and distracting otherwise.
 

La Grandmaster

Sergeant Knight at Arms
cmpxchg8b said:
For SSAO you really want to remove any occlusion if the depth difference between two texels is too large.
For example:
XK1S5lF.jpg

there is no way that wooden pole ends up occluding a wall 2 meters behind it.
That makes sense, my code at the moment is quite basic so ill have to give that a try. Like I said I wasnt really that happy with the results,  its too strong in some areas and has quite a few artifacts (like the banding/stripes/lines on the building on the far left of the second pic).
 

_Sebastian_

Punkbuster 2.0
Baron
NWWBVC
jacobhinds said:
I had no idea you could access the depth value on warband post-shaders. I might have to look into making some of my own, I've got a few ideas...
You can't by default, but it seems you can access all(I just tested depth) texture samplers by adding them to the postFX.fx file.
Texture samples incoming.
Code:
fx_ReflectionTextureSampler_RegisterS 			s0
fx_EnvTextureSampler_RegisterS				s1
fx_Diffuse2Sampler_RegisterS 				s2
fx_NormalTextureSampler_RegisterS			s3
fx_SpecularTextureSampler_RegisterS 			s4
fx_DepthTextureSampler_RegisterS 			s5
fx_CubicTextureSampler_RegisterS 			s6
fx_ShadowmapTextureSampler_RegisterS 			s7
fx_ScreenTextureSampler_RegisterS			s8
fx_MeshTextureSampler_RegisterS 			s9
fx_ClampedTextureSampler_RegisterS 			s10
fx_FontTextureSampler_RegisterS 			s11
fx_CharacterShadowTextureSampler_RegisterS		s12
fx_MeshTextureSamplerNoFilter_RegisterS 		s13
fx_DiffuseTextureSamplerNoWrap_RegisterS 		s14
fx_GrassTextureSampler_RegisterS 			s15

So if you want to have access to the depth sampler, you have to point to the postFX_sampler definitions and add the red marked line.

// use postFX_sampler4 for point sampling
#if defined(USE_FX_STATE_MANAGER) && !defined(USE_DEVICE_TEXTURE_ASSIGN) //else we can use direct device access with sampler indexes...
texture postFX_texture0, postFX_texture1, postFX_texture2, postFX_texture3, postFX_texture4;
//non-srgb samplers
sampler postFX_sampler0 : register(s0) = sampler_state {  Texture = postFX_texture0;  }; //linear clamp
sampler postFX_sampler1 : register(s1) = sampler_state {  Texture = postFX_texture1;  }; //linear clamp
sampler postFX_sampler2 : register(s2) = sampler_state {  Texture = postFX_texture2;  }; //linear clamp
sampler postFX_sampler3 : register(s3) = sampler_state {  Texture = postFX_texture3;  }; //linear clamp
sampler postFX_sampler4 : register(s4) = sampler_state {  Texture = postFX_texture4;  }; //linear clamp
sampler postFX_sampler5 : register(s5);// uses diffuse_texture //no need to add it to the else-statement as long as you don't change the definitions in fx_configuration
#else
#ifdef USE_REGISTERED_SAMPLERS
sampler postFX_sampler0 : register(s0); //linear clamp
sampler postFX_sampler1 : register(s1); //linear clamp
sampler postFX_sampler2 : register(s2); //linear clamp
sampler postFX_sampler3 : register(s3); //linear clamp
sampler postFX_sampler4 : register(s4); //linear clamp
#else
sampler postFX_sampler0 : register(s0) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR; }; //linear clamp
sampler postFX_sampler1 : register(s1) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR; }; //linear clamp
sampler postFX_sampler2 : register(s2) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR; }; //linear clamp
sampler postFX_sampler3 : register(s3) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR; }; //linear clamp
sampler postFX_sampler4 : register(s4) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR; }; //linear clamp
#endif
#endif


Of coure you can change postFX_sampler5 to a more understandable variable name, but this way it fits to the others :wink:

jacobhinds said:
I have no idea what language the code's written in though. Is it a warband "in-house" version of OpenGL like the module system is to python? If so is there any official documentation anywhere?
It's plain HLSL.
 

Airbar

Squire
M&BWBNWVCWF&S
This might be relevant as well, though don't ask me questions about it, snatched it from here

Code:
float3 normal_from_depth(float depth, float2 texcoords) {
  
  const float2 offset1 = float2(0.0,0.001);
  const float2 offset2 = float2(0.001,0.0);
  
  float depth1 = tex2D(DepthTextureSampler, texcoords + offset1).r;
  float depth2 = tex2D(DepthTextureSampler, texcoords + offset2).r;
  
  float3 p1 = float3(offset1, depth1 - depth);
  float3 p2 = float3(offset2, depth2 - depth);
  
  float3 normal = cross(p1, p2);
  normal.z = -normal.z;
  
  return normalize(normal);
}

PS_OUTPUT ps_ssao(VS_OUT_SSAO In)
{ 
  PS_OUTPUT Output;
  
  const float total_strength = 1.0;
  const float base = 0.2;
  
  const float area = 0.0075;
  const float falloff = 0.000001;
  
  const float radius = 0.0002;
  
  const int samples = 16;
  float3 sample_sphere[samples] = {
      float3( 0.5381, 0.1856,-0.4319), float3( 0.1379, 0.2486, 0.4430),
      float3( 0.3371, 0.5679,-0.0057), float3(-0.6999,-0.0451,-0.0019),
      float3( 0.0689,-0.1598,-0.8547), float3( 0.0560, 0.0069,-0.1843),
      float3(-0.0146, 0.1402, 0.0762), float3( 0.0100,-0.1924,-0.0344),
      float3(-0.3577,-0.5301,-0.4358), float3(-0.3169, 0.1063, 0.0158),
      float3( 0.0103,-0.5869, 0.0046), float3(-0.0897,-0.4940, 0.3287),
      float3( 0.7119,-0.0154,-0.0918), float3(-0.0533, 0.0596,-0.5411),
      float3( 0.0352,-0.0631, 0.5460), float3(-0.4776, 0.2847,-0.0271)
  };
  
  float3 random = normalize( tex2D(RandomTextureSampler, In.Tex0 * 4.0).rgb );
  
  float depth = tex2D(DepthTextureSampler, In.Tex0).r;
 
  float3 position = float3(In.Tex0, depth);
  float3 normal = normal_from_depth(depth, In.Tex0);
  
  float radius_depth = radius/depth;
  float occlusion = 0.0;
  for(int i=0; i < samples; i++) {
  
    float3 ray = radius_depth * reflect(sample_sphere[i], random);
    float3 hemi_ray = position + sign(dot(ray,normal)) * ray;
    
    float occ_depth = tex2D(DepthTextureSampler, saturate(hemi_ray.xy)).r;
    float difference = depth - occ_depth;
    
    occlusion += step(falloff, difference) * (1.0-smoothstep(falloff, area, difference));
  }
  
  float ao = 1.0 - total_strength * occlusion * (1.0 / samples);
  Output.RGBColor = saturate(ao + base);
  
  return Output;
}
 

La Grandmaster

Sergeant Knight at Arms
That code was what initially got me interested in SSAO, its far from complete though, I cant remember if I could even get it working when I initially tried it. Yoshiboy (the author) did however get it to produce a much much better effect than I have ever been able to reproduce in M&B.

full article here - http://theorangeduck.com/page/pure-depth-ssao
 

ElPadrino

Sergeant Knight at Arms
You don't like ENB ?  :mrgreen:

Very nice ! Yeah maybe you msut add blur because we see too much the "movment" at the background, like a glass.
But I really like the render ! The forground looks more sharp :smile: (Can you try with antialiasing or not ?)
 

_Sebastian_

Punkbuster 2.0
Baron
NWWBVC
La Grandmaster said:
That code was what initially got me interested in SSAO, its far from complete though, I cant remember if I could even get it working when I initially tried it. Yoshiboy (the author) did however get it to produce a much much better effect than I have ever been able to reproduce in M&B.

full article here - http://theorangeduck.com/page/pure-depth-ssao
The mentioned code is quite heavy.
You can achieve the same or better quality with less depth lookups and cheaper operations.
Rendering and blurring the SSAO in half resolution would make it 4 times faster and since you blur it anyway, you hardly could see any difference.

So I gave it a shot myself and the result is quite good.
tgUB5i.gif


The SSAO shader uses 8 depth lookups (+1 for base depth) per pixel and effects everything within a radius of 4 meters.
The result is blurred by a 15x15 bilateral filter based on depth difference and as I mentioned above everything is done in half resolution, so it's super fast.
It also provides countermeasures to avoid haloing...

The shader is actually a PostFX shader, but applied to a PostFX sampler that is passed to the shaders file.
So you can use it on every pixel shader you like, or not...
This way you're able to avoid occlusion artifacts on surfaces with manipulated vertices or materials that are not affected by the depth buffer, eg. particles, water, fog etc.
 

La Grandmaster

Sergeant Knight at Arms
@Sebastian, looks fantastic, exactly the kind of effect I was aiming to achive.

I have been playing around with lens flares and managed to get the working, not perfect but the base code is in place.
jUm6Ru.gif


o740oq.gif


Again this a postfx effect, which can be dropped into any mod without any work - the beauty of working with post process effects  :smile:
 

_Sebastian_

Punkbuster 2.0
Baron
NWWBVC
Heyho.
Since La Grandmaster and some other guys asked me how I achieved the SSAO effect, it would be a shame to not share it's basic code...
But since all of my shaders and the structure itself is rewritten from scratch, it's not that easy to apply the effect to your mod.
Due to that your HLSL experience is key to get it working and not to mess everything up.

So let's get started.
I actually use the postFX_sampler1(used for HDR) which is rendered in half-(low hdr) or quarter-(high hdr) resolution anyway and bake the SSAO to it's alpha channel.
After that I blur the sampler based on depth difference by using the ps_main_blur(X/Y) and then pass it to the shaders file, but you also can apply it to the final PostFX pass ofc.

The code is not well documented(I'm lazy ikr) and the SSAO only works in combination with HDR(I recommend low hdr cause of the half res sampler) and enabled Depth Effects.

Make sure you can access the depth buffer.
Code:
#if defined(USE_FX_STATE_MANAGER) && !defined(USE_DEVICE_TEXTURE_ASSIGN)	//else we can use direct device access with sampler indexes...
	texture postFX_texture0, postFX_texture1, postFX_texture2, postFX_texture3, postFX_texture4;
	//non-srgb samplers
	sampler postFX_sampler0 : register(s0) = sampler_state	{  Texture = postFX_texture0;  };  // scene
	sampler postFX_sampler1 : register(s1) = sampler_state	{  Texture = postFX_texture1;  };  // hdr-low = 1/2res high = 1/4res
	sampler postFX_sampler2 : register(s2) = sampler_state	{  Texture = postFX_texture2;  };  // brightness .. AVG and MAX
	sampler postFX_sampler3 : register(s3) = sampler_state	{  Texture = postFX_texture3;  };  // black
	sampler postFX_sampler4 : register(s4) = sampler_state	{  Texture = postFX_texture4;  };  // == sampler 2 + WithLuminance???
	sampler postFX_sampler5 : register(s5);// depth
	// sampler postFX_sampler6 : register(s6);// cubic  ...black screen
	// sampler postFX_sampler7 : register(s7);// shadowmap ...white screen
	// sampler postFX_sampler8 : register(s8);// screen ...half resolution screen
	// sampler postFX_sampler9 : register(s9);// mesh ...shows random texture
	// sampler postFX_sampler10 : register(s10);// clamped ...black screen
	// sampler postFX_sampler11 : register(s11);// font ...shows font texture
	// sampler postFX_sampler12 : register(s12);// char shadow ...black screen
	// sampler postFX_sampler13 : register(s13);// mesh no filter ...shows random texture without filter
	// sampler postFX_sampler14 : register(s14);// diffuse no wrap ...black screen
	// sampler postFX_sampler15 : register(s15);// grass ...black screen
	
	// sampler postFX_sampler16 : register(s0);//reflection ...shows blurry screen
	// sampler postFX_sampler17 : register(s1);//env ...shows env texture
	// sampler postFX_sampler18 : register(s2);//diffuse ...shows random diffuse texture
	// sampler postFX_sampler19 : register(s3);//normal ...shows random normal texture
#else 
	#ifdef USE_REGISTERED_SAMPLERS
		sampler postFX_sampler0 : register(s0);	//linear clamp
		sampler postFX_sampler1 : register(s1);	//linear clamp
		sampler postFX_sampler2 : register(s2);	//linear clamp
		sampler postFX_sampler3 : register(s3);	//linear clamp
		sampler postFX_sampler4 : register(s4);	//linear clamp
	#else
		sampler postFX_sampler0 : register(s0) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	 };	//linear clamp
		sampler postFX_sampler1 : register(s1) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	 };	//linear clamp
		sampler postFX_sampler2 : register(s2) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	 };	//linear clamp
		sampler postFX_sampler3 : register(s3) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	 };	//linear clamp
		sampler postFX_sampler4 : register(s4) = sampler_state{ AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	 };	//linear clamp
	#endif
#endif

Set up the static constants.
Code:
static const int clip_distance = 1250;// is 1250 by default you can change it in module.ini ...=> far_plane_distance = 1250 #clip distance
static const int num_iterations = 8;
static const float BlurPixelWeight[num_iterations] = {1.000, 0.875, 0.750, 0.625, 0.500, 0.375, 0.250, 0.125};

Render the SSAO and bake it to the sampler's alpha channel.
Code:
float4 ps_main_brightPass(float2 texCoord: TEXCOORD0 ) : COLOR0 
{
	float3 color = tex2D(postFX_sampler0, texCoord);
	color *= 255.0f; //make it real values.. more accuracy
	color = pow(color, 2.0f);
	
	//SSAO
	float occlusion = 0.0f;
 	float base_depth = tex2D(postFX_sampler5, texCoord).r;
	if (base_depth < 1.0f)//1 = clip_distance
	{
		base_depth *= clip_distance;
		
		float2 normal;//now generate pseudo random values
		normal.x = frac(sin((texCoord.x + 0.5) * (texCoord.y + 0.5) * 1000.0f) * 1000.0f);
		normal.y = frac(cos((texCoord.x + 0.5) * (texCoord.y + 0.5) * 1000.0f) * 1000.0f);
		normal *= 2.0f;
		normal -= 1.0f;
		float2 offset = g_HalfPixel_ViewportSizeInv.zw * normal * 250.0f / base_depth;
		
		float2 cur_offset;
		float difference_1, difference_2, check_dist;
		for(int i = 1; i <= 4; i++)
		{
			check_dist = i;
			cur_offset = offset * i;
			difference_1 = base_depth - tex2D(postFX_sampler5, texCoord + cur_offset).r * clip_distance;
			difference_2 = base_depth - tex2D(postFX_sampler5, texCoord - cur_offset).r * clip_distance;
			// if one sample distance is invalid then use its twins inverse ... almost completely removes haloing
			if (difference_1 > check_dist && difference_2 < check_dist)
				difference_1 = -difference_2;
			else if (difference_2 > check_dist && difference_1 < check_dist)
				difference_2 = -difference_1;
			difference_1 = saturate(difference_1 / check_dist);
			difference_2 = saturate(difference_2 / check_dist);
			occlusion += saturate((difference_1 * (1.0f - difference_1) + difference_2 * (1.0f - difference_2)) - 0.25);
		}
		occlusion *= 2.0f;
	}
	return float4(color, saturate(occlusion));
}

Blur the sampler.
Code:
float4 ps_main_blurX(float2 inTex: TEXCOORD0) : COLOR0 
{
	float4 total_color = tex2D(postFX_sampler0, inTex) * BlurPixelWeight[0];
	float4 cur_color;
	float2 offset = float2(g_HalfPixel_ViewportSizeInv.z, 0);
	float2 cur_offset;
	float base_depth = tex2D(postFX_sampler5, inTex).r * clip_distance * 10.0f;
	float cur_amount;
	float2 blur_amount = 1.0f;
	for(int i = 1; i < num_iterations; i++)
	{
		for(int j = 0; j < 2; j++)
		{
			if(j == 0)
				cur_offset = inTex + offset * i;
			else
				cur_offset = inTex - offset * i;
			cur_color = tex2D(postFX_sampler0, cur_offset) * BlurPixelWeight[i];
			cur_amount = max(1.0f / i, 1.0f - abs(base_depth - tex2D(postFX_sampler5, cur_offset).r * clip_distance * 10.0f));//based on difference
			total_color.a += cur_color.a * cur_amount;
			total_color.rgb += cur_color.rgb;
			blur_amount.x += BlurPixelWeight[i];
			blur_amount.y += BlurPixelWeight[i] * cur_amount;
		}
	}
	total_color.rgb /= blur_amount.x;
	total_color.a /= blur_amount.y;
	return total_color;
}
float4 ps_main_blurY(float2 inTex: TEXCOORD0) : COLOR0 
{
	float4 total_color = tex2D(postFX_sampler0, inTex) * BlurPixelWeight[0];
	float4 cur_color;
	float2 offset = float2(0, g_HalfPixel_ViewportSizeInv.w);
	float2 cur_offset;
	float base_depth = tex2D(postFX_sampler5, inTex).r * clip_distance * 10.0f;
	float cur_amount;
	float2 blur_amount = 1.0f;
	for(int i = 1; i < num_iterations; i++)
	{
		for(int j = 0; j < 2; j++)
		{
			if(j == 0)
				cur_offset = inTex + offset * i;
			else
				cur_offset = inTex - offset * i;
			cur_color = tex2D(postFX_sampler0, cur_offset) * BlurPixelWeight[i];
			cur_amount = max(1.0f / i, 1.0f - abs(base_depth - tex2D(postFX_sampler5, cur_offset).r * clip_distance * 10.0f));//based on difference
			total_color.a += cur_color.a * cur_amount;
			total_color.rgb += cur_color.rgb;
			blur_amount.x += BlurPixelWeight[i];
			blur_amount.y += BlurPixelWeight[i] * cur_amount;
		}
	}
	total_color.rgb /= blur_amount.x;
	total_color.a /= blur_amount.y;
	return total_color;
}

Now you either can apply the SSAO to the final pass FinalScenePassPS and use it as pure PostFX effect...
Code:
	// return 1.0f - tex2D(postFX_sampler1, texCoord).a;//SSAO only
	return lerp(color, 0.0f, tex2D(postFX_sampler1, texCoord).a);

...or pass it to the shaders file and apply the SSAO to any shader in order to avoid some issues;
_Sebastian_ said:
The shader is actually a PostFX shader, but applied to a PostFX sampler that is passed to the shaders file.
So you can use it on every pixel shader you like, or not...
This way you're able to avoid occlusion artifacts on surfaces with manipulated vertices or materials that are not affected by the depth buffer, eg. particles, water, fog etc.

And here starts the tricky part...
You have to replace the ENV sampler with the specific PostFX sampler, cause all 16 samplers are already used.
So you wont be able to use fake reflections by using env textures anymore... but I dont mind since I use screen space reflections instead.
Code:
// Texture&Samplers
texture postFX_texture1;

#if defined(USE_SHARED_DIFFUSE_MAP) || !defined(USE_DEVICE_TEXTURE_ASSIGN)
	texture diffuse_texture;
#endif

#ifndef USE_DEVICE_TEXTURE_ASSIGN
	texture diffuse_texture_2;
	texture specular_texture;
	texture normal_texture;
	texture env_texture;
	texture shadowmap_texture;

	texture cubic_texture;

	texture depth_texture;
	texture screen_texture;

	#ifdef USE_REGISTERED_SAMPLERS
	sampler ReflectionTextureSampler 	: register(fx_ReflectionTextureSampler_RegisterS 		) = sampler_state	{  Texture = env_texture;		};
	sampler PostFXTextureSampler			: register(fx_EnvTextureSampler_RegisterS				) = sampler_state	{  Texture = postFX_texture1;		};
	sampler Diffuse2Sampler 			: register(fx_Diffuse2Sampler_RegisterS 				) = sampler_state	{  Texture = diffuse_texture_2;	};
	sampler NormalTextureSampler		: register(fx_NormalTextureSampler_RegisterS			) = sampler_state	{  Texture = normal_texture;	};
	sampler SpecularTextureSampler 		: register(fx_SpecularTextureSampler_RegisterS 			) = sampler_state	{  Texture = specular_texture;	};
	sampler DepthTextureSampler 		: register(fx_DepthTextureSampler_RegisterS 			) = sampler_state	{  Texture = depth_texture;	    };
	sampler CubicTextureSampler 		: register(fx_CubicTextureSampler_RegisterS 			) = sampler_state	{  Texture = cubic_texture;	    };
	sampler ShadowmapTextureSampler 	: register(fx_ShadowmapTextureSampler_RegisterS 		) = sampler_state	{  Texture = shadowmap_texture;	};
	sampler ScreenTextureSampler 		: register(fx_ScreenTextureSampler_RegisterS			) = sampler_state	{  Texture = screen_texture;	};
	sampler MeshTextureSampler 			: register(fx_MeshTextureSampler_RegisterS 				) = sampler_state	{  Texture = diffuse_texture;	};
	sampler ClampedTextureSampler 		: register(fx_ClampedTextureSampler_RegisterS 			) = sampler_state	{  Texture = diffuse_texture;	};
	sampler FontTextureSampler 			: register(fx_FontTextureSampler_RegisterS 				) = sampler_state	{  Texture = diffuse_texture;	};
	sampler CharacterShadowTextureSampler:register(fx_CharacterShadowTextureSampler_RegisterS	) = sampler_state	{  Texture = diffuse_texture;	};
	sampler MeshTextureSamplerNoFilter 	: register(fx_MeshTextureSamplerNoFilter_RegisterS 		) = sampler_state	{  Texture = diffuse_texture;	};
	sampler DiffuseTextureSamplerNoWrap : register(fx_DiffuseTextureSamplerNoWrap_RegisterS 	) = sampler_state	{  Texture = diffuse_texture;	};
	sampler GrassTextureSampler 		: register(fx_GrassTextureSampler_RegisterS 			) = sampler_state	{  Texture = diffuse_texture;	};
	#else


	sampler ReflectionTextureSampler 	= sampler_state	{  Texture = env_texture;		AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler PostFXTextureSampler			= sampler_state	{  Texture = postFX_texture1;		AddressU = WRAP;  AddressV = WRAP;  MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler Diffuse2Sampler 			= sampler_state	{  Texture = diffuse_texture_2;	AddressU = WRAP; AddressV = WRAP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler NormalTextureSampler		= sampler_state	{  Texture = normal_texture;	AddressU = WRAP; AddressV = WRAP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler SpecularTextureSampler 		= sampler_state	{  Texture = specular_texture;	AddressU = WRAP; AddressV = WRAP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler DepthTextureSampler 		= sampler_state	{  Texture = depth_texture;		AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;    };
	sampler CubicTextureSampler 		= sampler_state	{  Texture = cubic_texture;	 	AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;   };
	sampler ShadowmapTextureSampler 	= sampler_state	{  Texture = shadowmap_texture;	AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler ScreenTextureSampler 		= sampler_state	{  Texture = screen_texture;	AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler MeshTextureSampler 			= sampler_state	{  Texture = diffuse_texture;	AddressU = WRAP; AddressV = WRAP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler ClampedTextureSampler 		= sampler_state	{  Texture = diffuse_texture;	AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler FontTextureSampler 			= sampler_state	{  Texture = diffuse_texture;	AddressU = WRAP; AddressV = WRAP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler CharacterShadowTextureSampler= sampler_state	{  Texture = diffuse_texture;	AddressU = BORDER; AddressV = BORDER; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler MeshTextureSamplerNoFilter 	= sampler_state	{  Texture = diffuse_texture;	AddressU = WRAP; AddressV = WRAP; MinFilter = NONE; MagFilter = NONE;	};
	sampler DiffuseTextureSamplerNoWrap = sampler_state	{  Texture = diffuse_texture;	AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	};
	sampler GrassTextureSampler 		= sampler_state	{  Texture = diffuse_texture;	AddressU = CLAMP; AddressV = CLAMP; MinFilter = LINEAR; MagFilter = LINEAR;	};

	#endif

#else
	sampler ReflectionTextureSampler 	: register(fx_ReflectionTextureSampler_RegisterS 		);
	sampler PostFXTextureSampler			: register(fx_EnvTextureSampler_RegisterS				);
	sampler Diffuse2Sampler 			: register(fx_Diffuse2Sampler_RegisterS 				);
	sampler NormalTextureSampler		: register(fx_NormalTextureSampler_RegisterS			);
	sampler SpecularTextureSampler 		: register(fx_SpecularTextureSampler_RegisterS 			);
	sampler DepthTextureSampler 		: register(fx_DepthTextureSampler_RegisterS 			);
	sampler CubicTextureSampler 		: register(fx_CubicTextureSampler_RegisterS 			);
	sampler ShadowmapTextureSampler 	: register(fx_ShadowmapTextureSampler_RegisterS 		);
	sampler ScreenTextureSampler 		: register(fx_ScreenTextureSampler_RegisterS			);

	#ifdef USE_SHARED_DIFFUSE_MAP
		sampler MeshTextureSampler 			: register(fx_MeshTextureSampler_RegisterS 				) = sampler_state	{  Texture = diffuse_texture;	};
		sampler ClampedTextureSampler 		: register(fx_ClampedTextureSampler_RegisterS 			) = sampler_state	{  Texture = diffuse_texture;	};
		sampler FontTextureSampler 			: register(fx_FontTextureSampler_RegisterS 				) = sampler_state	{  Texture = diffuse_texture;	};
		sampler CharacterShadowTextureSampler:register(fx_CharacterShadowTextureSampler_RegisterS	) = sampler_state	{  Texture = diffuse_texture;	};
		sampler MeshTextureSamplerNoFilter 	: register(fx_MeshTextureSamplerNoFilter_RegisterS 		) = sampler_state	{  Texture = diffuse_texture;	};
		sampler DiffuseTextureSamplerNoWrap : register(fx_DiffuseTextureSamplerNoWrap_RegisterS 	) = sampler_state	{  Texture = diffuse_texture;	};
		sampler GrassTextureSampler 		: register(fx_GrassTextureSampler_RegisterS 			) = sampler_state	{  Texture = diffuse_texture;	};
	#else
		sampler MeshTextureSampler 			: register(fx_MeshTextureSampler_RegisterS 				);
		sampler ClampedTextureSampler 		: register(fx_ClampedTextureSampler_RegisterS 			);
		sampler FontTextureSampler 			: register(fx_FontTextureSampler_RegisterS 				);
		sampler CharacterShadowTextureSampler:register(fx_CharacterShadowTextureSampler_RegisterS	);
		sampler MeshTextureSamplerNoFilter 	: register(fx_MeshTextureSamplerNoFilter_RegisterS 		);
		sampler DiffuseTextureSamplerNoWrap : register(fx_DiffuseTextureSamplerNoWrap_RegisterS 	);
		sampler GrassTextureSampler 		: register(fx_GrassTextureSampler_RegisterS 			);
	#endif
#endif

In order to apply the SSAO to a specific shader you first need to get the screen space position within the vertex shader.
Code:
	if(use_depth_effects)
	{
		Out.projCoord.xy = (float2(Out.Pos.x, -Out.Pos.y)+Out.Pos.w)/2.0f;
		Out.projCoord.xy += (vDepthRT_HalfPixel_ViewportSizeInv.xy * Out.Pos.w);
		Out.projCoord.zw = Out.Pos.zw;
	}

And then apply the SSAO to the ambient term of the pixel shader.
Code:
	if(use_depth_effects)
	{
		float4 ssao = tex2Dproj(PostFXTextureSampler, In.projCoord);
		if ((ssao.r + ssao.g + ssao.b) > 0.0f)//check if HDR is enabled
			ambient_term *= 1.0f - ssao.a;
	}

You can use this code to create your own SSAO effect, but dont forget to give me credit.  :wink:
 

Parrot

Knight
WBWF&SNWVC
That's insanely awesome _Sebastion_. Thanks for sharing!

Edit: I quickly gave it a spin in Blood and Iron, and the results were very nice.
ksJCmzp.gif
 

Swyter

Grandmaster Knight
M&BWBWF&S
Neat, just saw this. There's some cutting edge tech right here.

SSAO without halo'ing, screen-space reflections, Gaussian depth of field. You guys sure know your stuff.
Games like the latest Far Cry and MGS V: TFP still have pretty evident halos in their implementations.

Good to see that technical artists are keen on sharing their techniques and tricks, it's a pretty open field.
 
Top Bottom