bgfx/examples/45-bokeh/bokeh_dof.sh
2021-01-31 10:07:49 -08:00

191 lines
5.2 KiB
Bash

/*
* Copyright 2021 elven cache. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
#ifndef BOKEH_DOF_SH
#define BOKEH_DOF_SH
#define TWO_PI (6.28318531)
#define GOLDEN_ANGLE (2.39996323)
#define MAX_BLUR_SIZE (20.0)
#define RADIUS_SCALE (0.5)
float ShadertoyNoise (vec2 uv) {
return fract(sin(dot(uv.xy, vec2(12.9898,78.233))) * 43758.5453123);
}
float GetCircleOfConfusion (float depth, float focusPoint, float focusScale)
{
// if depth is less than focusPoint, result will be negative. want to keep this
// relationship so comparison of (signed) blur size is same as comparing depth.
return clamp((1.0/focusPoint - 1.0/depth) * focusScale, -1.0, 1.0);
}
float GetBlurSize (float depth, float focusPoint, float focusScale)
{
float circleOfConfusion = GetCircleOfConfusion(depth, focusPoint, focusScale);
return circleOfConfusion * u_maxBlurSize;
}
// this is the function at bottom of blog post...
//vec3 OriginalDepthOfField (vec2 texCoord, float focusPoint, float focusScale)
//{
// float depth = texture2D(s_depth, texCoord).x;
// float centerSize = GetBlurSize(depth, focusPoint, focusScale);
// vec3 color = texture2D(s_color, texCoord).xyz;
//
// float total = 1.0;
// float radius = RADIUS_SCALE;
// for (float theta = 0.0; radius < MAX_BLUR_SIZE; theta += GOLDEN_ANGLE)
// {
// vec2 spiralCoord = texCoord + vec2(cos(theta), sin(theta)) * u_viewTexel.xy * radius;
// vec3 sampleColor = texture2D(s_color, spiralCoord).xyz;
// float sampleDepth = texture2D(s_depth, spiralCoord).x;
//
// float sampleSize = GetBlurSize(sampleDepth, focusPoint, focusScale);
// if (sampleDepth > depth)
// {
// sampleSize = clamp(sampleSize, 0.0, centerSize*2.0);
// }
// float m = smoothstep(radius-0.5, radius+0.5, sampleSize);
// color += mix(color/total, sampleColor, m);
// total += 1.0;
// radius += RADIUS_SCALE/radius;
// }
// return color * (1.0/total);
//}
void GetColorAndBlurSize (
sampler2D samplerColor,
sampler2D samplerDepth,
vec2 texCoord,
float focusPoint,
float focusScale,
out vec3 outColor,
out float outBlurSize
) {
#if USE_PACKED_COLOR_AND_BLUR
vec4 colorAndBlurSize = texture2DLod(samplerColor, texCoord, 0);
vec3 color = colorAndBlurSize.xyz;
float blurSize = colorAndBlurSize.w;
outColor = color;
outBlurSize = blurSize;
#else
vec3 color = texture2DLod(samplerColor, texCoord, 0).xyz;
float depth = texture2DLod(samplerDepth, texCoord, 0).x;
float blurSize = GetBlurSize(depth, focusPoint, focusScale);
outColor = color;
outBlurSize = blurSize;
#endif
}
vec4 DepthOfField(
sampler2D samplerColor,
sampler2D samplerDepth,
vec2 texCoord,
float focusPoint,
float focusScale,
float samplePattern
) {
vec3 color;
float centerSize;
GetColorAndBlurSize(
samplerColor,
samplerDepth,
texCoord,
focusPoint,
focusScale,
/*out*/color,
/*out*/centerSize);
float absCenterSize = abs(centerSize);
// as sample count gets lower, visible banding. disrupt with noise.
// use a better random/noise/dither function than this..
vec2 pixelCoord = texCoord.xy * u_viewRect.zw;
float random = ShadertoyNoise(pixelCoord + vec2(314.0, 159.0)*u_frameIdx);
float theta = random * TWO_PI;
float thetaStep = GOLDEN_ANGLE;
float total = 1.0;
float totalSampleSize = 0.0;
// support two options for sample distribution ===========================
float loopValue;
float loopEnd;
if (0.5 < samplePattern)
{
// in sqrt distribution, take fixed number of steps, step count
// is fraction of full radius, with curve adjusted by sqrt function
loopValue = 0.5 / u_blurSteps; // radiusFraction
loopEnd = 1.0;
}
else
{
// in original distribution, looping value is radius directly,
// but radius grows in non-linear way
loopValue = u_radiusScale;
loopEnd = u_maxBlurSize;
}
//========================================================================
while (loopValue < loopEnd)
{
//====================================================================
float radius;
if (0.5 < samplePattern) {
radius = sqrt(loopValue) * u_maxBlurSize;
}
else
{
radius = loopValue;
}
//====================================================================
vec2 spiralCoord = texCoord + vec2(cos(theta), sin(theta)) * u_viewTexel.xy * radius;
vec3 sampleColor;
float sampleSize;
GetColorAndBlurSize(
samplerColor,
samplerDepth,
spiralCoord,
focusPoint,
focusScale,
/*out*/sampleColor,
/*out*/sampleSize);
float absSampleSize = abs(sampleSize);
// using signed sample size as proxy for depth comparison
if (sampleSize > centerSize)
{
absSampleSize = clamp(absSampleSize, 0.0, absCenterSize*2.0);
}
float m = smoothstep(radius-0.5, radius+0.5, absSampleSize);
color += mix(color/total, sampleColor, m);
totalSampleSize += absSampleSize;
total += 1.0;
theta += thetaStep;
//====================================================================
if (0.5 < samplePattern)
{
loopValue += (1.0 / u_blurSteps); // radiusFraction
}
else
{
loopValue += (u_radiusScale/loopValue); // radius
}
//====================================================================
}
color *= 1.0/total;
float averageSampleSize = totalSampleSize / (total-1.0);
return vec4(color, averageSampleSize);
}
#endif