Can't really explain what's causing that.
Anyway, here's an updated code of the shader script. Please keep in mind that it's still a WIP, and there may be bugs in it. It also needs cleaning up, but I've added some comments to help navigating easier.
Code:
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Grain filter technique /////////////////////////////////////////////////////////////////////////
//Last Updated: Wednesday September 16, 2009, 4:41PM
//Grain sampler for grain filter.
sampler2D grainNoiseSampler = sampler_state
{
Texture = textures/defaults/vector_noise.dds;
MinFilter = POINT;
MagFilter = POINT;
MipFilter = POINT;
AddressU = Wrap;
AddressV = Wrap;
};
sampler2D GIsum : register (s0)
{
Texture = $ZTarget;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};
sampler2D GInormal : register (s2)
{
Texture = $BackBuffer;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};
sampler2D GIcolor : register (s3)
{
Texture = $BackBuffer;
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = Clamp;
AddressV = Clamp;
};
////////////////// structures /////////////////////
struct vtxOutGrainFilter
{
float4 HPosition : POSITION;
float4 ScreenTC : TEXCOORD0;
};
///////////////// vertex shader //////////////////
// based off BaseVS
vtxOutGrainFilter GrainFilterVS(vtxIn IN)
{
vtxOutGrainFilter OUT = (vtxOutGrainFilter)0;
float4 vPos = IN.Position;
OUT.HPosition = mul(vpMatrix, vPos);
OUT.ScreenTC.xy = IN.baseTC.xy;
OUT.ScreenTC.zw = IN.baseTC.xy*g_VS_ScreenSize.xy/4;
return OUT;
}
//noise producing function to eliminate banding.
float GIrand(float2 co)
{
return 0.5+(frac(sin(dot(co.xy, float2(12.9898,78.233))) * 43758.5453))*0.5;
}
pixout GrainFilterPS(vtxOutGrainFilter IN)
{
pixout OUT;
///////////////// grain filter //////////////////
/*
half4 acc = 0;
float2 vNoiseTC = (IN.ScreenTC.xy ) * (PS_ScreenSize.xy/64.0) + (psParams[0].xy/PS_ScreenSize.xy);
float2 vNoise = tex2D(grainNoiseSampler, vNoiseTC)+ dot(IN.ScreenTC.xy, 1) * 65535;
vNoise = frac( vNoise );
vNoise = vNoise*2-1;
//vNoise *= 0.05;
half4 cScreen = tex2D(screenMapSampler, IN.ScreenTC);
*/
///////////////// arkano22 SSGI //////////////////
//Calculate sampling rates.
float ratex = (1.0f/3840.0);
float ratey = (1.0f/2160.0);
//Initialize occlusion sum and gi color.
//float sum = 0.0;
float3 fcolor = float3(0,0,0);
//Far and near clip planes.
float zFar = 80.0;
float zNear = 0.5;
//Get depth at current pixel.
float prof = tex2D(GIsum, IN.ScreenTC.xy).x;
//Scale sample number with depth.
//int samples = round(8/(0.5+prof));
int depthsamples = round(8/(0.5+prof));
prof = zFar * zNear / (prof * (zFar - zNear) - zFar); //linearize z sample
//Obtain normal and color at current pixel.
float3 norm = normalize(float3(tex2D(GInormal,IN.ScreenTC.xy).xyz)*2.0-float(1.0));
float3 dcolor1 = tex2D(GIcolor, IN.ScreenTC.xy);
// Number of samples for SSGI. Leave at 2.
float samples = 2;
//Calculate kernel steps.
float incx = ratex*30*psParams[0].w;//gi radius
float incy = ratey*30*psParams[0].w;
//float incx2 = ratex*8;//ao radius
//float incy2 = ratey*8;
//Do the actual calculations.
for(float i=0; i < samples; i++)
{
for(float j=0; j < samples; j++)
{
if (i != 0 || j!= 0)
{
float2 coords = float2(i*incx,j*incy)/prof;
//float2 coords2 = float2(i*incx2,j*incy2)/prof;
float prof2 = tex2D(GIsum,IN.ScreenTC.xy+coords*GIrand(IN.ScreenTC)).x;
//prof2 = zFar * zNear / (prof * (zFar - zNear) - zFar); //linearize z sample
prof2 = zFar * zNear / (prof2 * (zFar - zNear) - zFar); //linearize z sample
//float prof2g = tex2D(GIsum,IN.ScreenTC.xy+coords2*GIrand(IN.ScreenTC)).x;
//prof2g = zFar * zNear / (prof * (zFar - zNear) - zFar); //linearize z sample
//float3 norm2g = normalize(float3(tex2D(GInormal,IN.ScreenTC.xy+coords2*GIrand(IN.ScreenTC)).xyz)*2.0-float3(1.0,1.0,1.0));
float3 dcolor2 = tex2D(GIcolor, IN.ScreenTC.xy+coords*GIrand(IN.ScreenTC));
//OCCLUSION:
/*
//Calculate approximate pixel distance.
float3 dist2 = float3(coords2,prof-prof2g);
//Calculate normal and sampling direction coherence.
float coherence2 = dot(normalize(-coords2),normalize(float2(norm2g.xy)));
//If there is coherence, calculate occlusion.
if (coherence2 > 0)
{
float pformfactor2 = 0.5*((1.0-dot(norm,norm2g)))/(3.1416*pow(abs(length(dist2*2)),2.0)+0.5);//el 4: depthscale
sum += clamp(pformfactor2*0.2,0.0,1.0);//ao intensity;
}*/
//COLOR BLEEDING:
if (length(dcolor2)>0.3)
{
//Color threshold
float3 norm2 = normalize(float3(tex2D(GInormal,IN.ScreenTC.xy+coords*GIrand(IN.ScreenTC)).xyz)*2.0-float(1.0));
//Calculate approximate pixel distance.
float3 dist = float3(coords,abs(prof-prof2));
//Calculate normal and sampling direction coherence:
float coherence = dot(normalize(-coords),normalize(float2(norm2.xy)));
//If there is coherence, calculate bleeding.
if (coherence > 0)
{
float pformfactor = ((1.0-dot(norm,norm2)))/(3.1416*pow(abs(length(dist*2)),2.0)+0.5); //el 4: depthscale
//Here is the clamp. Increase the *25 to increase strength of bleeding, or increase the lower and maximum values, 2 and 4 are default.
fcolor += dcolor2*(clamp(pformfactor*25,2.0,4.0));
}
}
}
}
}
float3 bleeding = (fcolor/depthsamples)*0.5;
// float occlusion = 1.0-(sum/depthsamples);
// had to remove occlusion because of 2 reasons:
// 1. Crysis already has SSAO
// 2. Crysis doesn't have a screen normal sampler, only depth/scene/backbuffer samplers.
// Didn't remove code just in case.
float occlusion = 1.0;
//Output SSGI
OUT.Color = float4(1,1,1,1);
OUT.Color = float4(float3(dcolor1*occlusion+bleeding*0.5),1.0);
// Testing depth
//OUT.Color = prof;
// Grainfilter test output
// OUT.Color = cScreen + dot(vNoise.xy, 0.5)*psParams[0].w;
return OUT;
}
////////////////// technique /////////////////////
technique GrainFilter
{
pass p0
{
VertexShader = compile vs_Auto GrainFilterVS();
PixelShader = compile ps_Auto GrainFilterPS();
ZEnable = false;
ZWriteEnable = false;
CullMode = None;
}
}
Here are the instructions on how to use it:
1. Extra PostEffects.cfx from the Shaders.pak if you haven't already done so (Don't delete the one in the shaders.pak, unless you back it up).
2. If you're running a mod from a mod folder, editing shader files will have effect in real-time in the editor if you're in DX9. Otherwise you'll have to re-launch the editor everytime you make a change.
3. Open the PostEffects.cfx and replace the grain filter technique, with the code above (You'll know where to start and where to end.)
4. Start up sandbox, open your map.
5. Add a comment or other entity that allows you to create a flowgraph. Place a startup node and an image:filtergrain node into the flowgraph, and connect them.
6. Set the "Amount" to the multiplier for the radius. 1 is standard radius, while > 1 increases the radius and < 1 lowers the radius. The lowest value that can be entered is 0.1, and the highest depends on how you feel about the way it looks.
That's it. The new code takes into account even the lighter colors, so the entire level might get a little too bright or grainy, but that's a side effect of the fact that it's still a WIP.
I'd suggest you don't edit the shader apart from the color clamps near the bottom for intensity, or if you can fix the shaders problems.

Have fun and post your screenshots here so I can see what you've done with it

Note: If you want the bleeding to push upwards rather than in an SSAO style, replace these lines:
Code:
prof = zFar * zNear / (prof * (zFar - zNear) - zFar); //linearize z sample
float2 coords = float2(i*incx,j*incy)/prof;
prof2 = zFar * zNear / (prof2 * (zFar - zNear) - zFar); //linearize z sample
With these lines:
Code:
prof = zFar * zNear / (prof * (zFar - zNear) * zFar); //linearize z sample
float2 coords = float2(i*incx,j*incy)*prof;
prof2 = zFar * zNear / (prof2 * (zFar - zNear) * zFar); //linearize z sample
This will increase the radius and will probably produce weird results as I've adapted it to work the other way. You may have to play with the shader to get this working.