Hey there!
I got here a very nice DOF (actually way better than TV's integrated) shader which I want to implement into my TV-Project.
Let me say, I read the FAQ ^^
here's the shader code:
/************************************************************************/
/* Post Processing for DepthOfField */
/************************************************************************/
//3x3 Gauss-Blur
float blurSampleWeights[3] = {.274069,.451863,.274069 };
//Used as buffer for downsc. and blurring, AND as Low-Res Version in Final Pass
samplerRECT bufferSamplerDEBUG = sampler_state {
MinFilter = Linear;
MagFilter = Linear;
WrapS = ClampToEdge;
WrapT = ClampToEdge;
};
samplerRECT bufferSampler = sampler_state {
MinFilter = Linear;
MagFilter = Linear;
WrapS = ClampToEdge;
WrapT = ClampToEdge;
};
samplerRECT gbufferSampler = sampler_state {
MinFilter = Nearest;
MagFilter = Nearest;
WrapS = ClampToEdge;
WrapT = ClampToEdge;
};
//Hi-Res Original Image w. Destination Alpha
samplerRECT bufferSamplerHiRes = sampler_state {
MinFilter = Linear;
MagFilter = Linear;
WrapS = ClampToEdge;
WrapT = ClampToEdge;
};
//VARS For Final DOF - PASS
//On Gef7 8, 4 other hardware
#ifdef HQDFILTER
#define NUM_TAPS 8
#else
#define NUM_TAPS 4
#endif
//NOTE: 4 Taps best Performance / Quality setting
// 6 Taps better Quality / OK Performance
// 8 Taps best Quality / better have a GeForce 7
// poisson-distributed positions
float2 poisson[8] = {
float2( 0.0, 0.0),
float2( 0.527837,-0.085868),
float2(-0.040088, 0.536087),
float2(-0.670445,-0.179949),
float2(-0.419418,-0.616039),
float2( 0.440453,-0.639399),
float2(-0.757088, 0.349334),
float2( 0.574619, 0.685879)
};
//NOTE: Dont think we need pixel-size, as we use nv-rects...
float2 maxCoC = float2(5.0, 10.0);
//float2 maxCoC = float2(.42, .84);
float radiusScale = .4; //Used on lower res. image
//DEBUG
float fudgeLow;
float fudgeLowScale;
/*** Downsampling and appyling 4x4 Box-Filter ***/
struct downsampleVsOutput
{
float4 HPosition : POSITION;
float2 UV[4] : TEXCOORD0;
};
downsampleVsOutput DownsampleVS(float4 Position : POSITION, float2 TexCoord : TEXCOORD0) {
downsampleVsOutput OUT;
//Preparing Coords for downsampling by 4 with 4x4 box filter...
float2 s = TexCoord;// + float2(-1.0, -1.0);
OUT.HPosition = Position;
OUT.UV[0] = s;
OUT.UV[1] = s + float2(2,0);
OUT.UV[2] = s + float2(2,2);
OUT.UV[3] = s + float2(0,2);
return OUT;
}
struct simplestVsOutput
{
float4 HPosition : POSITION;
float2 UV : TEXCOORD0;
//float2 UVscaled : TEXCOORD1;
};
struct simplestVsOutputPlusScaled
{
float4 HPosition : POSITION;
float2 UV : TEXCOORD0;
float2 UV_scaled : TEXCOORD1;
};
/*** Very simple Vertex - Shader for PostProcessing ***/
simplestVsOutput PostVS(float4 Position : POSITION, float2 TexCoord : TEXCOORD0) {
simplestVsOutput OUT;
OUT.HPosition = Position;
OUT.UV = TexCoord;// + float2(fudgeLow, fudgeLow);
//note *.25 + fudge of .00178
//OUT.UVscaled = (TexCoord+1)*(0.25178);
return OUT;
}
simplestVsOutputPlusScaled simplestVP_scaled(float4 Position : POSITION, float2 TexCoord : TEXCOORD0) {
simplestVsOutputPlusScaled OUT;
OUT.HPosition = Position;
OUT.UV = TexCoord;
OUT.UV_scaled = TexCoord * 0.25;
return OUT;
}
float4 DownsamplePS(downsampleVsOutput IN, uniform samplerRECT tex) : COLOR {
half3 result;
result = h3texRECT(tex, IN.UV[0])* .25;
result += h3texRECT(tex, IN.UV[1])*.25;
result += h3texRECT(tex, IN.UV[2])*.25;
result += h3texRECT(tex, IN.UV[3])*.25;
return float4(result, 1.0f);
}
//watch out with changing the big arrays...
float4 BlurPSHoriz( simplestVsOutput IN ) : COLOR0
{
//accumulated color
half4 vAccum = half4( 0.0f, 0.0f, 0.0f, 0.0f );
//vAccum = texRECT( bufferSampler, IN.UV );// * blurSampleWeights[i+1];
for( int i = -1; i < 2; i++ )
{
float2 texCoord = IN.UV + float2(i,0);
vAccum += h4texRECT( bufferSampler, texCoord ) * (half) blurSampleWeights[i+1];
}
return vAccum;
}
float4 BlurPSVert( simplestVsOutput IN ) : COLOR0
{
//accumulated color
half4 vAccum = half4( 0.0f, 0.0f, 0.0f, 0.0f );
//vAccum = texRECT( bufferSampler, IN.UV );// * blurSampleWeights[i+1];
for( int i = -1; i < 2; i++ )
{
float2 texCoord = IN.UV + float2(0,i);
vAccum += h4texRECT( bufferSampler, texCoord ) * (half) blurSampleWeights[i+1];
}
return vAccum;
}
/*** Poisson Distributed DOF - Filter ***/
float4 PoissonDOFFilter(simplestVsOutputPlusScaled IN) : COLOR {
half4 cOut;
half discRadius;
half discRadiusLow;
half centerDepth;
//cOut = texRECT(bufferSamplerHiRes, IN.UV);
//Dirty Copy?
//half2 texCoord = IN.UV;
//half2 texCoordScaled = IN.UVscaled;
cOut = h4texRECT(bufferSamplerHiRes, IN.UV); // fetch center tap
centerDepth = cOut.a; // retrieve its depth
// convert depth into blur radius in pixels
discRadius = abs(cOut.a * maxCoC.y - maxCoC.x);
// compute disc radius on low-res image
discRadiusLow = discRadius * radiusScale;
// reuse cOut as an accumulator
cOut = 0;
for(int t = 0; t < NUM_TAPS; t++)
{
// fetch low-res tap * half2(1.01, 1.01
//watch out, lower coord are aso rect-coords, so scale down as we get 0..1024
half2 coordLow = IN.UV_scaled + ((half2) poisson[t] * discRadiusLow);
half4 tapLow = h4texRECT(bufferSampler, IN.UV_scaled);
//tapLow.x = 1.0;
// fetch high-res tap
half2 coordHigh = IN.UV.xy + ((half2) poisson[t] * discRadius);
half4 tapHigh = h4texRECT(bufferSamplerHiRes, coordHigh);
//tapHigh.z = 1.0;
// put tap blurriness into [0, 1] range
half tapBlur = abs(tapHigh.a * 2.0 - 1.0);
// mix low- and hi-res taps based on tap blurriness
half4 tap;
/*if (centerDepth > 0.0035 && centerDepth < 0.005)
tap = (tapHigh + tapLow) / 2;
else*/
tap = lerp(tapHigh, tapLow, tapBlur);
// apply leaking reduction: lower weight for taps that are
// closer than the center tap and in focus
tap.a = (tap.a >= centerDepth) ? 1.0 : abs(tap.a * 2.0 - 1.0);
// accumulate
cOut.rgb += tap.rgb * tap.a;
cOut.a += tap.a;
}
// normalize and return result
cOut = (cOut / cOut.a);
return float4(cOut);
}
/*** SIMPLE TEX OUTPUT OF BUFFER ***/
float4 ShowBufferPS(simplestVsOutput IN) : COLOR {
float4 result;
result = texRECT(bufferSamplerDEBUG, IN.UV);
result.xyz = result.aaa;
return result;
}
technique DepthOfField {
pass Downsample{
CullfaceEnable = false;
DepthTestEnable = false;
VertexProgram = compile vp40 DownsampleVS();
FragmentProgram = compile fp40 DownsamplePS(bufferSampler);
}
pass BlurHoriz{
CullfaceEnable = false;
DepthTestEnable = false;
VertexProgram = compile vp40 PostVS();
FragmentProgram = compile fp40 BlurPSHoriz();
}
pass BlurVert{
CullfaceEnable = false;
DepthTestEnable = false;
VertexProgram = compile vp40 PostVS();
FragmentProgram = compile fp40 BlurPSVert();
}
pass ApplyDof{
CullfaceEnable = false;
DepthTestEnable = false;
VertexProgram = compile vp40 simplestVP_scaled();
FragmentProgram = compile fp40 PoissonDOFFilter();
}
pass ShowBuffer {
/*DepthTestEnable = false;*/
VertexProgram = compile vp40 PostVS();
FragmentProgram = compile fp40 ShowBufferPS();
}
}
Let me also say it's not mine so I only want to use it for testing purposes.
So, here are my questions:
1) Are there any limitations in TV regarding shader files? Like f.e. special structures, that can't be used, etc.
2) How would I go about including the shader to post-process my scene? I don#t have any clue on which object I should apply it.
I hope someone can help me.
Cya,
Philipp