// Screen Space Indirect Illumination
// Created and Implemented by Tomerk
// Optimized by Ethatron
// ---------------------------------------
// TWEAKABLE VARIABLES.
#undef TEST_MODE
// Toggle for test-mode. If enabled, you can see the raw ssgi
//"#define ..." is enabled, and "#undef ..." is disabled.
#define N_SAMPLES 9
// number of samples, currently do not change.
iface float giRadiusMultiplier
< string help = "Linearly multiplies the radius of the II/AO Sampling"; >
= 10;
iface float iiStrengthMultiplier
< string help = "Linearly multiplies the strength of the II"; >
= 3.0;
iface float aoStrengthMultiplier
< string help = "Linearly multiplies the strength of the AO"; >
= 1.0;
iface float giClamp
< string help = "The maximum strength of the AO, 0 is max strength, 1 is weakest"; >
= 0.0;
iface float ThicknessModel
< string help = "Units in space the AO assumes objects' thicknesses are"; >
= 100;
// END OF TWEAKABLE VARIABLES.
// ---------------------------------------
#include "includes/Random.hlsl"
#include "includes/Resolution.hlsl"
#include "includes/Depth.hlsl"
#include "includes/Fog.hlsl"
#include "includes/Position.hlsl"
texture2D obge_LastRendertarget0_EFFECTPASS;
texture2D obge_PrevRendertarget0_EFFECTPASS;
sampler2D FrmeSamplerL = sampler_state {
Texture = <obge_PrevRendertarget0_EFFECTPASS>;
AddressU = Mirror;
AddressV = Mirror;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
MIPFILTER = NONE;
};
sampler2D PassSamplerL = sampler_state {
texture = <obge_LastRendertarget0_EFFECTPASS>;
AddressU = CLAMP;
AddressV = CLAMP;
MINFILTER = LINEAR;
MAGFILTER = LINEAR;
};
struct VSOUT
{
float4 vertPos : POSITION;
float2 UVCoord : TEXCOORD0;
};
struct VSIN
{
float4 vertPos : POSITION0;
float2 UVCoord : TEXCOORD0;
};
VSOUT FrameVS(VSIN IN)
{
VSOUT OUT = (VSOUT)0.0f; // initialize to zero, avoid complaints.
OUT.vertPos = IN.vertPos;
OUT.UVCoord = IN.UVCoord;
return OUT;
}
static const float2 sample_offset[N_SAMPLES] =
{
//#if N_SAMPLES >= 9
float2(-0.1376476f, 0.2842022f ),
float2(-0.626618f , 0.4594115f ),
float2(-0.8903138f, -0.05865424f),
float2( 0.2871419f, 0.8511679f ),
float2(-0.1525251f, -0.3870117f ),
float2( 0.6978705f, -0.2176773f ),
float2( 0.7343006f, 0.3774331f ),
float2( 0.1408805f, -0.88915f ),
float2(-0.6642616f, -0.543601f )
//#endif
};
static const float sample_radius[N_SAMPLES] =
{
//#if N_SAMPLES >= 9
0.948832,
0.629516,
0.451554,
0.439389,
0.909372,
0.682344,
0.5642,
0.4353,
0.5130
//#endif
};
float4 Illumination(VSOUT IN) : COLOR0 {
float depth = LinearDepth(IN.UVCoord);
[branch]
if (depth >= 0.99)
return float4(0.0, 0.0, 0.0, 1.0);
float3 pos = EyePosition(IN.UVCoord, depth);
float3 dx = ddx(pos);
float3 dy = ddy(pos);
float3 norm = normalize(cross(dx, dy));
norm.y *= -1;
float sample_depth;
float4 gi = float4(0, 0, 0, 0);
float is = 0, as = 0;
float2 rand_vec = rand_2_10(IN.UVCoord);
float2 sample_vec_divisor = g_InvFocalLen * depth * rangeZ / (giRadiusMultiplier * 5000 * rcpres);
float2 sample_center = IN.UVCoord + norm.xy / sample_vec_divisor * float2(1, aspect);
float ii_sample_center_depth = depth * rangeZ + norm.z * giRadiusMultiplier * 20;
float ao_sample_center_depth = depth * rangeZ + norm.z * giRadiusMultiplier * 5;
[loop]
for (int i = 0; i < N_SAMPLES; i++) {
float2 sample_vec = reflect(sample_offset[i], rand_vec) / sample_vec_divisor;
float2 sample_coords = sample_center + sample_vec * float2(1, aspect);
float sample_depth = rangeZ * LinearDepth(sample_coords);
float ii_curr_sample_radius = sample_radius[i] * giRadiusMultiplier * 20;
float ao_curr_sample_radius = sample_radius[i] * giRadiusMultiplier * 5;
gi.a += clamp(0, ao_sample_center_depth + ao_curr_sample_radius - sample_depth , 2 * ao_curr_sample_radius);
gi.a -= clamp(0, ao_sample_center_depth + ao_curr_sample_radius - sample_depth - ThicknessModel, 2 * ao_curr_sample_radius);
if ((sample_depth < ii_sample_center_depth + ii_curr_sample_radius) &&
(sample_depth > ii_sample_center_depth - ii_curr_sample_radius)) {
float3 sample_pos = EyePosition(sample_coords, sample_depth);
float3 sample_dx = ddx(sample_pos);
float3 sample_dy = ddy(sample_pos);
float3 sample_norm = normalize(cross(sample_dx, sample_dy));
sample_norm.y *= -1;
float3 unit_vector = normalize(pos - sample_pos);
gi.rgb += tex2D(FrmeSamplerL, sample_coords).rgb;
//* saturate(dot(norm, unit_vector))
//* saturate(dot(sample_norm, unit_vector));
}
is += 1;
as += 2 * ao_curr_sample_radius;
}
gi.rgb /= is * 5;
gi.a /= as;
gi *= FogDecay(depth);
gi.rgb = 0.0 + gi.rgb * iiStrengthMultiplier;
gi.a = 1.0 - gi.a * aoStrengthMultiplier;
return gi;
}
float4 BlurNCombine(VSOUT IN) : COLOR0 {
float3 color = tex2D(FrmeSamplerL, IN.UVCoord).rgb;
float4 gi = tex2D(PassSamplerL, IN.UVCoord) * 4;
gi += tex2D(PassSamplerL, IN.UVCoord + float2( rcpres.x, 0)) * 2;
gi += tex2D(PassSamplerL, IN.UVCoord + float2(-rcpres.x, 0)) * 2;
gi += tex2D(PassSamplerL, IN.UVCoord + float2(0, rcpres.y)) * 2;
gi += tex2D(PassSamplerL, IN.UVCoord + float2(0, -rcpres.y)) * 2;
gi += tex2D(PassSamplerL, IN.UVCoord + rcpres );
gi += tex2D(PassSamplerL, IN.UVCoord - rcpres );
gi += tex2D(PassSamplerL, IN.UVCoord + rcpres * float2(1, -1));
gi += tex2D(PassSamplerL, IN.UVCoord - rcpres * float2(1, -1));
gi /= 16;
#ifdef TEST_MODE
return gi;
#endif
return float4((color + gi.rgb) * gi.a, 1);
}
technique main
<
int group = EFFECTGROUP_PRE;
int fxclass = EFFECTCLASS_LIGHT;
int conditions = EFFECTCOND_ZBUFFER | EFFECTCOND_ACHANNEL;
>
{
pass {
VertexShader = compile vs_3_0 FrameVS();
PixelShader = compile ps_3_0 Illumination();
}
pass {
VertexShader = compile vs_3_0 FrameVS();
PixelShader = compile ps_3_0 BlurNCombine();
}
}