| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259 |
- /******************************************************************************/
- #include "!Header.h"
- /******************************************************************************
- TODO: add slow but high quality circular bokeh DoF
- -create small / quarter res (or maybe even smaller) RT containing info about biggest blur radius
- -in the blur function iterate "radius x radius" using BRANCH/LOOP and the small RT image (perhaps need to use 'SamplerPoint')
- -sample intensity should be based on Length2(sample_distance)<=Sqr(sample_range) (making bool true/false)
- -probably should divide this by sample area "intensity / Sqr(sample_range)" (samples covering more areas are stretched and their intensity spreaded?)
- /******************************************************************************/
- #define SHOW_BLUR 0
- #define SHOW_SMOOTH_BLUR 0
- #define SHOW_BLURRED 0
- #define FRONT_EXTEND 0 // 0 or 1, method for extending the front, default=0
- #define DEPTH_TOLERANCE (FRONT_EXTEND ? 1.5f : 1.0f) // 1..2 are reasonable
- #define FINAL_MODE 1 // 1(default)=maximize smooth blur only if it's closer, 0=always maximize smooth blur
- #define FINAL_SCALE 4.0f // final blur scale, increases transition between sharp and blurred in 0..1/FINAL_SCALE step, instead of 0..1
- /******************************************************************************/
- BUFFER(Dof)
- Vec4 DofParams; // Intensity, Focus, SimpleMulAdd
- BUFFER_END
- inline Flt DofIntensity() {return DofParams.x;}
- inline Flt DofFocus () {return DofParams.y;}
- inline Flt DofMul () {return DofParams.z;}
- inline Flt DofAdd () {return DofParams.w;}
- /******************************************************************************/
- inline Flt Blur(Flt z, uniform Bool realistic)
- {
- if(realistic)
- {
- #if 0 // F makes almost no difference
- Flt F=0.075f; return DofIntensity() /* * F */ * (z - DofFocus()) / (z * (DofFocus() - F));
- #else
- return DofIntensity()*(z-DofFocus())/(z*DofFocus()); // 'DofRange' ignored
- #endif
- }else return DofIntensity()*Mid(z*DofMul() + DofAdd(), -1, 1); // (z-DofFocus())/DofRange, z/DofRange - DofFocus()/DofRange
- }
- /******************************************************************************/
- Vec4 DofDS_PS(NOPERSP Vec2 inTex:TEXCOORD,
- uniform Bool do_clamp ,
- uniform Bool realistic ,
- uniform Bool half ,
- uniform Bool gather ):COLOR
- {
- Vec4 ret; // RGB=col, W=Blur
- if(half)
- {
- ret.rgb=TexLod(Col, UVClamp(inTex, do_clamp)).rgb; // use linear filtering because we're downsampling
- #if MODEL>=SM_4
- if(gather)ret.w=DEPTH_MIN(Depth.Gather(SamplerPoint, inTex));else
- #endif
- {
- Vec2 tex_min=inTex-ColSize.xy*0.5f,
- tex_max=inTex+ColSize.xy*0.5f;
- ret.w=DEPTH_MIN(TexDepthRawPoint(Vec2(tex_min.x, tex_min.y)),
- TexDepthRawPoint(Vec2(tex_max.x, tex_min.y)),
- TexDepthRawPoint(Vec2(tex_min.x, tex_max.y)),
- TexDepthRawPoint(Vec2(tex_max.x, tex_max.y)));
- }
- }else // quarter
- {
- Vec2 tex_min=UVClamp(inTex-ColSize.xy, do_clamp),
- tex_max=UVClamp(inTex+ColSize.xy, do_clamp);
- Vec2 t00=Vec2(tex_min.x, tex_min.y),
- t10=Vec2(tex_max.x, tex_min.y),
- t01=Vec2(tex_min.x, tex_max.y),
- t11=Vec2(tex_max.x, tex_max.y);
- // use linear filtering because we're downsampling
- ret.rgb=(TexLod(Col, t00).rgb
- +TexLod(Col, t10).rgb
- +TexLod(Col, t01).rgb
- +TexLod(Col, t11).rgb)/4;
- #if MODEL>=SM_4
- if(gather)ret.w=DEPTH_MIN(DEPTH_MIN(Depth.Gather(SamplerPoint, t00)),
- DEPTH_MIN(Depth.Gather(SamplerPoint, t10)),
- DEPTH_MIN(Depth.Gather(SamplerPoint, t01)),
- DEPTH_MIN(Depth.Gather(SamplerPoint, t11)));else
- #endif
- {
- // this is approximation because we would have to take 16 samples
- ret.w=DEPTH_MIN(TexDepthRawPoint(t00),
- TexDepthRawPoint(t10),
- TexDepthRawPoint(t01),
- TexDepthRawPoint(t11));
- }
- }
- ret.w=Blur(LinearizeDepth(ret.w), realistic)*0.5f+0.5f;
- return ret;
- }
- /******************************************************************************/
- inline Flt Center(Flt center_blur_u) // center_blur_u=0..1 (0.5=focus) here we can offload some of the calculation done for each sample, by making necessary adjustments to 'center_blur_u'
- {
- return center_blur_u*2-1;
- }
- inline Flt Weight(Flt center_blur, Flt test_blur_u,
- #if MODEL!=SM_GL // have to forget about uniform because it will fail on Mac
- uniform
- #endif
- Int dist, uniform Int range) // center_blur=-1..1 (0=focus), center_blur_u=0..1 (0.5=focus), test_blur_u=0..1 (0.5=focus)
- {
- Flt f=dist/Flt(range+1),
- //center_blur=center_blur_u*2-1, // -1..1, we've already done this in 'Center'
- test_blur= test_blur_u*2-1, // -1..1
- cb=Abs(center_blur), // 0..1
- tb=Abs( test_blur), // 0..1
- b=Max(tb, cb // have to extend search radius for cases when center is in the front
- *Sat(FRONT_EXTEND ? (tb-center_blur)*DEPTH_TOLERANCE+1 : -center_blur*DEPTH_TOLERANCE)) // skip if: test focused and center in the back, or apply if: center in front
- *Sat((cb-test_blur)*DEPTH_TOLERANCE+1); // skip if: center focused and test in the back
- if(!b)return 0; // this check is needed only for low precision devices, or when using high precision RT's. Low precision unsigned RT's don't have exact zero, however we scale 'b' above and zero could be reached?
- Flt x=f/b; // NaN
- x=Sat(x); // x=Min(x, 1); to prevent for returning 'LerpCube' values outside 0..1 range
- return (1-LerpCube(x))/b; // weight, divide by 'b' to make narrower ranges more intense to preserve total intensity
- // !! if changing from 'LerpCube' to another function then we need to change 'WeightSum' as well !!
- }
- inline Flt FinalBlur(Flt blur, Flt blur_smooth) // 'blur'=-Inf .. Inf, 'blur_smooth'=0..1
- {
- if(SHOW_BLURRED)return 1;
- //blur_smooth=(FINAL_MODE ? Sat(blur_smooth*-2+1) : Abs(blur_smooth*2-1)); already done in 'DofBlurY_PS'
- return Sat(Max(Abs(blur), blur_smooth)*FINAL_SCALE);
- }
- inline Flt WeightSum(uniform Int range) {return range+1;} // Sum of all weights for all "-range..range" steps, calculated using "Flt weight=0; for(Int dist=-range; dist<=range; dist++)weight+=BlendSmoothCube(dist/Flt(range+1));"
- /******************************************************************************/
- #define SCALE 0.5f // at the end we need 0 .. 0.5 range, and since we start with 0..1 we need to scale by "0.5"
- Vec4 DofBlurX_PS(NOPERSP Vec2 inTex:TEXCOORD,
- uniform Int range ):COLOR
- { // INPUT: Col: RGB , Blur
- // OUTPUT: RGB BlurredX, BlurSmooth
- Vec4 center=TexPoint(Col, inTex);
- Flt center_blur=Center(center.a),
- weight=0,
- blur_abs=0;
- Vec4 color =0;
- Vec2 t; t.y=inTex.y;
- UNROLL for(Int i=-range; i<=range; i++)if(i)
- {
- t.x=inTex.x+ColSize.x*i;
- Vec4 c=TexPoint(Col, t);
- Flt test_blur=c.a,
- #if MODEL==SM_GL
- w=Weight(center_blur, test_blur, (i>=0) ? i : -i, range);
- #else
- w=Weight(center_blur, test_blur, Abs(i), range);
- #endif
- weight +=w;
- color +=w* c;
- blur_abs+=w*Abs(c.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
- }
- Flt b=Abs(center_blur),
- w=Lerp(WeightSum(range)-weight, 1, b);
- color +=w* center;
- blur_abs+=w*Abs(center.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
- weight +=w;
- blur_abs/=weight;
- //return Vec4(color.rgb/weight, color.a/weight);
- return Vec4(color.rgb/weight, (color.a>=0.5f*weight) ? 0.5f+blur_abs : 0.5f-blur_abs); // color.a/weight>=0.5f ? .. : ..
- }
- #undef SCALE
- #define SCALE 1.0f // at the end we need 0..1 range, and since we start with 0..1 we need to scale by "1"
- Vec4 DofBlurY_PS(NOPERSP Vec2 inTex:TEXCOORD,
- uniform Int range ):COLOR
- { // INPUT: Col: RGB BlurredX , BlurSmooth
- // OUTPUT: RGB BlurredXY, BlurSmooth
- Vec4 center=TexPoint(Col, inTex);
- Flt center_blur=Center(center.a),
- weight=0,
- blur_abs=0;
- Vec4 color =0;
- Vec2 t; t.x=inTex.x;
- UNROLL for(Int i=-range; i<=range; i++)if(i)
- {
- t.y=inTex.y+ColSize.y*i;
- Vec4 c=TexPoint(Col, t);
- Flt test_blur=c.a,
- #if MODEL==SM_GL
- w=Weight(center_blur, test_blur, (i>=0) ? i : -i, range);
- #else
- w=Weight(center_blur, test_blur, Abs(i), range);
- #endif
- weight +=w;
- color +=w* c;
- blur_abs+=w*Abs(c.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
- }
- Flt b=Abs(center_blur),
- w=Lerp(WeightSum(range)-weight, 1, b);
- color +=w* center;
- blur_abs+=w*Abs(center.a * (2*SCALE) - (1*SCALE)); // SCALE here so we don't have to do it later
- weight +=w;
- blur_abs/=weight;
- //color.a =((color.a>=0.5f*weight) ? 0.5f+blur_abs : 0.5f-blur_abs); // color.a/weight>=0.5f ? .. : ..
- return Vec4(color.rgb/weight, FINAL_MODE ? ((color.a>=0.5f*weight) ? 0 : blur_abs) : blur_abs);
- }
- /******************************************************************************/
- Vec4 Dof_PS(NOPERSP Vec2 inTex:TEXCOORD,
- NOPERSP PIXEL ,
- uniform Bool dither ,
- uniform Bool realistic ):COLOR
- {
- Flt z=TexDepthPoint(inTex),
- b=Blur(z, realistic);
- #if SHOW_BLUR
- b=1-Abs(b); return Vec4(b, b, b, 1);
- #endif
- Vec4 focus=TexLod(Col , inTex), // can't use 'TexPoint' because 'Col' can be supersampled
- blur =TexLod(Col1, inTex), // use linear filtering because 'Col1' may be smaller RT
- col;
- #if SHOW_SMOOTH_BLUR
- col.rgb=blur.a;
- #else
- col.rgb=Lerp(focus.rgb, blur.rgb, FinalBlur(b, blur.a));
- #endif
- col.a=1; // force full alpha so back buffer effects can work ok
- if(dither)col.rgb+=DitherValueColor(pixel);
- return col;
- }
- /******************************************************************************/
- // TECHNIQUES
- /******************************************************************************/
- TECHNIQUE (DofDS , Draw_VS(), DofDS_PS(false, false, false, false));
- TECHNIQUE (DofDSC , Draw_VS(), DofDS_PS(true , false, false, false));
- TECHNIQUE (DofDSR , Draw_VS(), DofDS_PS(false, true , false, false));
- TECHNIQUE (DofDSCR , Draw_VS(), DofDS_PS(true , true , false, false));
- TECHNIQUE (DofDSH , Draw_VS(), DofDS_PS(false, false, true , false));
- TECHNIQUE (DofDSCH , Draw_VS(), DofDS_PS(true , false, true , false));
- TECHNIQUE (DofDSRH , Draw_VS(), DofDS_PS(false, true , true , false));
- TECHNIQUE (DofDSCRH , Draw_VS(), DofDS_PS(true , true , true , false));
- TECHNIQUE_4_1(DofDSG , Draw_VS(), DofDS_PS(false, false, false, true ));
- TECHNIQUE_4_1(DofDSCG , Draw_VS(), DofDS_PS(true , false, false, true ));
- TECHNIQUE_4_1(DofDSRG , Draw_VS(), DofDS_PS(false, true , false, true ));
- TECHNIQUE_4_1(DofDSCRG , Draw_VS(), DofDS_PS(true , true , false, true ));
- TECHNIQUE_4_1(DofDSHG , Draw_VS(), DofDS_PS(false, false, true , true ));
- TECHNIQUE_4_1(DofDSCHG , Draw_VS(), DofDS_PS(true , false, true , true ));
- TECHNIQUE_4_1(DofDSRHG , Draw_VS(), DofDS_PS(false, true , true , true ));
- TECHNIQUE_4_1(DofDSCRHG, Draw_VS(), DofDS_PS(true , true , true , true ));
- #define DOF_BLUR(range) TECHNIQUE(DofBlurX##range, Draw_VS(), DofBlurX_PS(range)); TECHNIQUE(DofBlurY##range, Draw_VS(), DofBlurY_PS(range));
- DOF_BLUR(2)
- DOF_BLUR(3)
- DOF_BLUR(4)
- DOF_BLUR(5)
- DOF_BLUR(6)
- DOF_BLUR(7)
- DOF_BLUR(8)
- DOF_BLUR(9)
- DOF_BLUR(10)
- DOF_BLUR(11)
- DOF_BLUR(12)
- TECHNIQUE(Dof , Draw_VS(), Dof_PS(false, false));
- TECHNIQUE(DofD , Draw_VS(), Dof_PS(true , false));
- TECHNIQUE(DofR , Draw_VS(), Dof_PS(false, true ));
- TECHNIQUE(DofDR, Draw_VS(), Dof_PS(true , true ));
- /******************************************************************************/
|