|
@@ -16,28 +16,45 @@ uniform sampler2D grainSampler;
|
|
|
|
|
|
// uniforms
|
|
// uniforms
|
|
uniform float grain_amount;
|
|
uniform float grain_amount;
|
|
-uniform float maxZ;
|
|
|
|
uniform bool blur_noise;
|
|
uniform bool blur_noise;
|
|
uniform float screen_width;
|
|
uniform float screen_width;
|
|
uniform float screen_height;
|
|
uniform float screen_height;
|
|
uniform float distortion;
|
|
uniform float distortion;
|
|
-uniform float focus_depth;
|
|
|
|
|
|
+uniform bool dof_enabled;
|
|
|
|
+//uniform float focus_distance; // not needed; already used to compute screen distance
|
|
|
|
+uniform float screen_distance; // precomputed screen distance from lens center; based on focal length & desired focus distance
|
|
uniform float aperture;
|
|
uniform float aperture;
|
|
|
|
+uniform float darken;
|
|
uniform float edge_blur;
|
|
uniform float edge_blur;
|
|
uniform bool highlights;
|
|
uniform bool highlights;
|
|
|
|
|
|
|
|
+// preconputed uniforms (not effect parameters)
|
|
|
|
+uniform float near;
|
|
|
|
+uniform float far;
|
|
|
|
+
|
|
// varyings
|
|
// varyings
|
|
varying vec2 vUV;
|
|
varying vec2 vUV;
|
|
|
|
|
|
// constants
|
|
// constants
|
|
-#define PI 3.14159265
|
|
|
|
|
|
+#define PI 3.14159265
|
|
|
|
+#define TWOPI 6.28318530
|
|
|
|
+#define inverse_focal_length 0.1 // a property of the lens used
|
|
|
|
|
|
// common calculations
|
|
// common calculations
|
|
vec2 centered_screen_pos;
|
|
vec2 centered_screen_pos;
|
|
|
|
+vec2 distorted_coords;
|
|
float radius2;
|
|
float radius2;
|
|
float radius;
|
|
float radius;
|
|
|
|
|
|
|
|
|
|
|
|
+// on-the-fly constant noise
|
|
|
|
+vec2 rand(vec2 co)
|
|
|
|
+{
|
|
|
|
+ float noise1 = (fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453));
|
|
|
|
+ float noise2 = (fract(sin(dot(co, vec2(12.9898, 78.233)*2.0)) * 43758.5453));
|
|
|
|
+ return clamp(vec2(noise1, noise2), 0.0, 1.0);
|
|
|
|
+}
|
|
|
|
+
|
|
// applies edge distortion on texture coords
|
|
// applies edge distortion on texture coords
|
|
vec2 getDistortedCoords(vec2 coords) {
|
|
vec2 getDistortedCoords(vec2 coords) {
|
|
|
|
|
|
@@ -54,104 +71,111 @@ vec2 getDistortedCoords(vec2 coords) {
|
|
return dist_coords;
|
|
return dist_coords;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// sample screen with an offset (randomize offset angle for better smothness), returns partial sample weight
|
|
|
|
+float sampleScreen(inout vec4 color, const in vec2 offset, const in float weight) {
|
|
|
|
+
|
|
|
|
+ // compute coords with offset (a random angle is added)
|
|
|
|
+ vec2 coords = distorted_coords;
|
|
|
|
+ float angle = rand(coords * 100.0).x * TWOPI;
|
|
|
|
+ coords += vec2(offset.x * cos(angle) - offset.y * sin(angle), offset.x * sin(angle) + offset.y * cos(angle));
|
|
|
|
+
|
|
|
|
+ color += texture2D(textureSampler, coords)*weight;
|
|
|
|
+
|
|
|
|
+ return weight;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// returns blur level according to blur size required
|
|
|
|
+float getBlurLevel(float size) {
|
|
|
|
+ return min(3.0, ceil(size / 1.0));
|
|
|
|
+}
|
|
|
|
+
|
|
// returns original screen color after blur
|
|
// returns original screen color after blur
|
|
-vec4 getBlurColor(vec2 coords, float size) {
|
|
|
|
|
|
+vec4 getBlurColor(float size) {
|
|
|
|
|
|
- vec4 col = texture2D(textureSampler, coords);
|
|
|
|
|
|
+ vec4 col = texture2D(textureSampler, distorted_coords);
|
|
if (size == 0.0) { return col; }
|
|
if (size == 0.0) { return col; }
|
|
|
|
|
|
// there are max. 30 samples; the number of samples chosen is dependant on the blur size
|
|
// there are max. 30 samples; the number of samples chosen is dependant on the blur size
|
|
// there can be 10, 20 or 30 samples chosen; levels of blur are then 1, 2 or 3
|
|
// there can be 10, 20 or 30 samples chosen; levels of blur are then 1, 2 or 3
|
|
- float blur_level = min(3.0, ceil(size / 1.0));
|
|
|
|
|
|
+ float blur_level = getBlurLevel(size);
|
|
|
|
|
|
float w = (size / screen_width);
|
|
float w = (size / screen_width);
|
|
float h = (size / screen_height);
|
|
float h = (size / screen_height);
|
|
float total_weight = 1.0;
|
|
float total_weight = 1.0;
|
|
-
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-0.53*w, 0.15*h))*0.93;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(0.42*w, -0.69*h))*0.90;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(0.20*w, 1.00*h))*0.87;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-0.97*w, -0.72*h))*0.85;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(1.37*w, -0.14*h))*0.83;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-1.02*w, 1.16*h))*0.80;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-0.03*w, -1.69*h))*0.78;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(1.27*w, 1.34*h))*0.76;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-1.98*w, -0.14*h))*0.74;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(1.66*w, -1.32*h))*0.72;
|
|
|
|
- total_weight += 8.18;
|
|
|
|
|
|
+ vec2 sample_coords;
|
|
|
|
+
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-0.50*w, 0.24*h), 0.93);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(0.30*w, -0.75*h), 0.90);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(0.36*w, 0.96*h), 0.87);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-1.08*w, -0.55*h), 0.85);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(1.33*w, -0.37*h), 0.83);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-0.82*w, 1.31*h), 0.80);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-0.31*w, -1.67*h), 0.78);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(1.47*w, 1.11*h), 0.76);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-1.97*w, 0.19*h), 0.74);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(1.42*w, -1.57*h), 0.72);
|
|
|
|
|
|
if (blur_level > 1.0) {
|
|
if (blur_level > 1.0) {
|
|
- col += texture2D(textureSampler, coords + vec2(-0.35*w, 2.22*h))*0.70;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-1.31*w, -1.98*h))*0.67;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(2.42*w, 0.61*h))*0.65;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-2.31*w, 1.25*h))*0.63;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(0.90*w, -2.59*h))*0.61;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(1.14*w, 2.62*h))*0.59;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-2.72*w, -1.21*h))*0.56;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(2.93*w, -0.98*h))*0.54;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-1.56*w, 2.80*h))*0.52;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-0.77*w, -3.22*h))*0.49;
|
|
|
|
- total_weight += 5.96;
|
|
|
|
|
|
+ total_weight += sampleScreen(col, vec2(0.01*w, 2.25*h), 0.70);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-1.62*w, -1.74*h), 0.67);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(2.49*w, 0.20*h), 0.65);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-2.07*w, 1.61*h), 0.63);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(0.46*w, -2.70*h), 0.61);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(1.55*w, 2.40*h), 0.59);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-2.88*w, -0.75*h), 0.56);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(2.73*w, -1.44*h), 0.54);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-1.08*w, 3.02*h), 0.52);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-1.28*w, -3.05*h), 0.49);
|
|
}
|
|
}
|
|
|
|
|
|
if (blur_level > 2.0) {
|
|
if (blur_level > 2.0) {
|
|
- col += texture2D(textureSampler, coords + vec2(2.83*w, 1.92*h))*0.46;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-3.49*w, 0.51*h))*0.44;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(2.30*w, -2.82*h))*0.41;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(0.22*w, 3.74*h))*0.38;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-2.76*w, -2.68*h))*0.34;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(3.95*w, 0.11*h))*0.31;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(-3.07*w, 2.65*h))*0.26;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(0.48*w, -4.13*h))*0.22;
|
|
|
|
- col += texture2D(textureSampler, coords + vec2(2.49*w, 3.46*h))*0.15;
|
|
|
|
- total_weight += 2.97;
|
|
|
|
|
|
+ total_weight += sampleScreen(col, vec2(3.11*w, 1.43*h), 0.46);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-3.36*w, 1.08*h), 0.44);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(1.80*w, -3.16*h), 0.41);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(0.83*w, 3.65*h), 0.38);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-3.16*w, -2.19*h), 0.34);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(3.92*w, -0.53*h), 0.31);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-2.59*w, 3.12*h), 0.26);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(-0.20*w, -4.15*h), 0.22);
|
|
|
|
+ total_weight += sampleScreen(col, vec2(3.02*w, 3.00*h), 0.15);
|
|
}
|
|
}
|
|
|
|
|
|
col /= total_weight; // scales color according to weights
|
|
col /= total_weight; // scales color according to weights
|
|
- col.a = 1.0;
|
|
|
|
|
|
+
|
|
|
|
+ // darken if out of focus
|
|
|
|
+ if(darken > 0.0) {
|
|
|
|
+ col.rgb *= clamp(0.3, 1.0, 1.05-size*0.5*darken);
|
|
|
|
+ }
|
|
|
|
|
|
// blur levels debug
|
|
// blur levels debug
|
|
- // if(blur_level == 1.0) { col.b = 0.0; }
|
|
|
|
- // if(blur_level == 2.0) { col.r = 0.0; }
|
|
|
|
- // if(blur_level == 3.0) { col.g = 0.0; }
|
|
|
|
|
|
+ // if(blur_level == 1.0) { col.b *= 0.5; }
|
|
|
|
+ // if(blur_level == 2.0) { col.r *= 0.5; }
|
|
|
|
+ // if(blur_level == 3.0) { col.g *= 0.5; }
|
|
|
|
|
|
return col;
|
|
return col;
|
|
}
|
|
}
|
|
|
|
|
|
-// on-the-fly constant noise
|
|
|
|
-vec2 rand(vec2 co)
|
|
|
|
-{
|
|
|
|
- float noise1 = (fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453));
|
|
|
|
- float noise2 = (fract(sin(dot(co, vec2(12.9898, 78.233)*2.0)) * 43758.5453));
|
|
|
|
- return clamp(vec2(noise1, noise2), 0.0, 1.0);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
void main(void)
|
|
void main(void)
|
|
{
|
|
{
|
|
|
|
|
|
- // Common calc
|
|
|
|
|
|
+ // Common calc: position relative to screen center, screen radius, distorted coords, position in texel space
|
|
centered_screen_pos = vec2(vUV.x - 0.5, vUV.y - 0.5);
|
|
centered_screen_pos = vec2(vUV.x - 0.5, vUV.y - 0.5);
|
|
radius2 = centered_screen_pos.x*centered_screen_pos.x + centered_screen_pos.y*centered_screen_pos.y;
|
|
radius2 = centered_screen_pos.x*centered_screen_pos.x + centered_screen_pos.y*centered_screen_pos.y;
|
|
radius = sqrt(radius2);
|
|
radius = sqrt(radius2);
|
|
-
|
|
|
|
- vec4 final_color;
|
|
|
|
- vec2 distorted_coords = getDistortedCoords(vUV);
|
|
|
|
|
|
+ distorted_coords = getDistortedCoords(vUV); // we distort the screen coordinates (lens "magnifying" effect)
|
|
vec2 texels_coords = vec2(vUV.x * screen_width, vUV.y * screen_height); // varies from 0 to SCREEN_WIDTH or _HEIGHT
|
|
vec2 texels_coords = vec2(vUV.x * screen_width, vUV.y * screen_height); // varies from 0 to SCREEN_WIDTH or _HEIGHT
|
|
|
|
|
|
- // blur from depth of field effect
|
|
|
|
- float dof_blur_amount = 0.0;
|
|
|
|
- float depth_bias = 0.0; // positive if the pixel is further than focus depth; negative if closer
|
|
|
|
- if (focus_depth != -1.0) {
|
|
|
|
- vec4 depth_sample = texture2D(depthSampler, distorted_coords);
|
|
|
|
- float depth = depth_sample.r;
|
|
|
|
- depth_bias = depth - focus_depth;
|
|
|
|
|
|
+ float depth = texture2D(depthSampler, distorted_coords).r; // depth value from DepthRenderer: 0 to 1
|
|
|
|
+ float distance = near + (far-near)*depth; // actual distance from the lens
|
|
|
|
+ vec4 color = texture2D(textureSampler, vUV); // original raster
|
|
|
|
|
|
- // compute blur amount with distance
|
|
|
|
- if (depth_bias > 0.0) { dof_blur_amount = depth_bias * aperture * 2.2; }
|
|
|
|
- else { dof_blur_amount = depth_bias * depth_bias * aperture * 30.0; }
|
|
|
|
|
|
|
|
- if (dof_blur_amount < 0.05) { dof_blur_amount = 0.0; } // no blur at all
|
|
|
|
- }
|
|
|
|
|
|
+ // compute the circle of confusion size (CoC), i.e. blur radius depending on depth
|
|
|
|
+ // screen_distance is precomputed in code
|
|
|
|
+ float coc = abs( aperture * ( screen_distance * ( inverse_focal_length - 1.0 / distance ) - 1.0 ) );
|
|
|
|
+
|
|
|
|
+ // disable blur
|
|
|
|
+ if (dof_enabled == false || coc < 0.07) { coc = 0.0; }
|
|
|
|
|
|
// blur from edge blur effect
|
|
// blur from edge blur effect
|
|
float edge_blur_amount = 0.0;
|
|
float edge_blur_amount = 0.0;
|
|
@@ -160,7 +184,7 @@ void main(void)
|
|
}
|
|
}
|
|
|
|
|
|
// total blur amount
|
|
// total blur amount
|
|
- float blur_amount = max(edge_blur_amount, dof_blur_amount);
|
|
|
|
|
|
+ float blur_amount = max(edge_blur_amount, coc);
|
|
|
|
|
|
// apply blur if necessary
|
|
// apply blur if necessary
|
|
if (blur_amount == 0.0) {
|
|
if (blur_amount == 0.0) {
|
|
@@ -169,11 +193,11 @@ void main(void)
|
|
else {
|
|
else {
|
|
|
|
|
|
// add blurred color
|
|
// add blurred color
|
|
- gl_FragColor = getBlurColor(distorted_coords, blur_amount * 1.7);
|
|
|
|
|
|
+ gl_FragColor = getBlurColor(blur_amount * 1.7);
|
|
|
|
|
|
- // if further than focus depth & we have computed highlights: enhance highlights
|
|
|
|
- if (depth_bias > 0.0 && highlights) {
|
|
|
|
- gl_FragColor += clamp(dof_blur_amount, 0.0, 1.0)*texture2D(highlightsSampler, distorted_coords);
|
|
|
|
|
|
+ // if we have computed highlights: enhance highlights
|
|
|
|
+ if (highlights) {
|
|
|
|
+ gl_FragColor.rgb += clamp(coc, 0.0, 1.0)*texture2D(highlightsSampler, distorted_coords).rgb;
|
|
}
|
|
}
|
|
|
|
|
|
if (blur_noise) {
|
|
if (blur_noise) {
|
|
@@ -184,9 +208,11 @@ void main(void)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
// apply grain
|
|
// apply grain
|
|
if (grain_amount > 0.0) {
|
|
if (grain_amount > 0.0) {
|
|
vec4 grain_color = texture2D(grainSampler, texels_coords*0.003);
|
|
vec4 grain_color = texture2D(grainSampler, texels_coords*0.003);
|
|
- gl_FragColor.rgb += (-0.5 + grain_color.rgb) * 0.20;
|
|
|
|
|
|
+ gl_FragColor.rgb += (-0.5 + grain_color.rgb) * 0.30 * grain_amount;
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|