diff options
Diffstat (limited to 'hlsl/distortion.fx')
-rw-r--r-- | hlsl/distortion.fx | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/hlsl/distortion.fx b/hlsl/distortion.fx new file mode 100644 index 00000000000..9db6edd4fb5 --- /dev/null +++ b/hlsl/distortion.fx @@ -0,0 +1,330 @@ +// license:BSD-3-Clause +// copyright-holders:ImJezze +//----------------------------------------------------------------------------- +// Distortion Effect +//----------------------------------------------------------------------------- + +texture DiffuseTexture; + +sampler DiffuseSampler = sampler_state +{ + Texture = <DiffuseTexture>; + MipFilter = LINEAR; + MinFilter = LINEAR; + MagFilter = LINEAR; + AddressU = CLAMP; + AddressV = CLAMP; + AddressW = CLAMP; +}; + +//----------------------------------------------------------------------------- +// Vertex Definitions +//----------------------------------------------------------------------------- + +struct VS_INPUT +{ + float4 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct VS_OUTPUT +{ + float4 Position : POSITION; + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +struct PS_INPUT +{ + float4 Color : COLOR0; + float2 TexCoord : TEXCOORD0; +}; + +//----------------------------------------------------------------------------- +// Constants +//----------------------------------------------------------------------------- + +static const float Epsilon = 1.0e-7f; +static const float PI = 3.1415927f; +static const float E = 2.7182817f; +static const float Gelfond = 23.140692f; // e^pi (Gelfond constant) +static const float GelfondSchneider = 2.6651442f; // 2^sqrt(2) (Gelfond-Schneider constant) + +//----------------------------------------------------------------------------- +// Functions +//----------------------------------------------------------------------------- + +bool xor(bool a, bool b) +{ + return (a || b) && !(a && b); +} + +// www.stackoverflow.com/questions/5149544/can-i-generate-a-random-number-inside-a-pixel-shader/ +float random(float2 seed) +{ + // irrationals for pseudo randomness + float2 i = float2(Gelfond, GelfondSchneider); + + return frac(cos(dot(seed, i)) * 123456.0f); +} + +// www.dinodini.wordpress.com/2010/04/05/normalized-tunable-sigmoid-functions/ +float normalizedSigmoid(float n, float k) +{ + // valid for n and k in range of -1.0 and 1.0 + return (n - n * k) / (k - abs(n) * 2.0f * k + 1); +} + +// www.iquilezles.org/www/articles/distfunctions/distfunctions.htm +float roundBox(float2 p, float2 b, float r) +{ + return length(max(abs(p) - b + r, 0.0f)) - r; +} + +//----------------------------------------------------------------------------- +// Distortion Vertex Shader +//----------------------------------------------------------------------------- + +uniform float2 ScreenDims; // size of the window or fullscreen +uniform float2 TargetDims; +uniform float2 QuadDims; // size of the screen quad + +VS_OUTPUT vs_main(VS_INPUT Input) +{ + VS_OUTPUT Output = (VS_OUTPUT)0; + + Output.Position = float4(Input.Position.xyz, 1.0f); + Output.Position.xy /= ScreenDims; + Output.Position.y = 1.0f - Output.Position.y; // flip y + Output.Position.xy -= 0.5f; // center + Output.Position.xy *= 2.0f; // zoom + + Output.Color = Input.Color; + + Output.TexCoord = Input.Position.xy / ScreenDims; + Output.TexCoord += 0.5f / TargetDims; // half texel offset correction (DX9) + + return Output; +} + +//----------------------------------------------------------------------------- +// Post-Processing Pixel Shader +//----------------------------------------------------------------------------- + +uniform float2 DefaultScreenRatio = float2(1.0f, 3.0f / 4.0f); // normalized screen ratio (defalt ratio of 4:3) + +uniform float CurvatureAmount = 0.0f; +uniform float RoundCornerAmount = 0.0f; +uniform float SmoothBorderAmount = 0.5f; +uniform float VignettingAmount = 0.0f; +uniform float ReflectionAmount = 0.0f; + +uniform bool OrientationSwapXY = false; // false landscape, true portrait for default screen orientation +uniform bool RotationSwapXY = false; // swapped default screen orientation due to screen rotation +uniform int RotationType = 0; // 0 = 0°, 1 = 90°, 2 = 180°, 3 = 270° + +float2 GetRatioCorrecton() +{ + float ScreenRatio = ScreenDims.x / ScreenDims.y; + float QuadRatio = QuadDims.x / QuadDims.y; + float ScreenQuadRatio = QuadRatio / ScreenRatio; + + return ScreenQuadRatio > 1.0f + ? float2(1.0, 1.0f / ScreenQuadRatio) + : float2(ScreenQuadRatio, 1.0); +} + +float GetNoiseFactor(float3 n, float random) +{ + // smaller n become more noisy + return 1.0f + random * max(0.0f, 0.25f * pow(E, -8 * n)); +} + +float GetVignetteFactor(float2 coord, float amount) +{ + float2 VignetteCoord = coord; + + float VignetteLength = length(VignetteCoord); + float VignetteBlur = (amount * 0.75f) + 0.25; + + // 0.5 full screen fitting circle + float VignetteRadius = 1.0f - (amount * 0.25f); + float Vignette = smoothstep(VignetteRadius, VignetteRadius - VignetteBlur, VignetteLength); + + return saturate(Vignette); +} + +float GetSpotAddend(float2 coord, float amount) +{ + float2 RatioCorrection = GetRatioCorrecton(); + + float2 defaultScreenRatio = xor(OrientationSwapXY, RotationSwapXY) + ? DefaultScreenRatio.yx + : DefaultScreenRatio.xy; + + // upper right quadrant + float2 spotOffset = + RotationType == 1 // 90° + ? float2(-0.25f, -0.25f) + : RotationType == 2 // 180° + ? float2(0.25f, -0.25f) + : RotationType == 3 // 270° + ? float2(0.25f, 0.25f) + : float2(-0.25f, 0.25f); + + float2 SpotCoord = coord; + SpotCoord += spotOffset * defaultScreenRatio * RatioCorrection; + + float SpotBlur = amount; + + // 0.5 full screen fitting circle + float SpotRadius = amount * 0.75f; + float Spot = smoothstep(SpotRadius, SpotRadius - SpotBlur, length(SpotCoord)); + + float SigmoidSpot = normalizedSigmoid(Spot, 0.75) * amount; + + // increase strength by 100% + SigmoidSpot = SigmoidSpot * 2.0f; + + return saturate(SigmoidSpot); +} + +float GetRoundCornerFactor(float2 coord, float radiusAmount, float smoothAmount) +{ + float2 RatioCorrection = GetRatioCorrecton(); + + smoothAmount = min(smoothAmount, radiusAmount); + + float2 RoundCornerCoord = coord * 2; + + float MinScreenDims = min(ScreenDims.x, ScreenDims.y); + + float radius = MinScreenDims * 0.5 * max(radiusAmount, 0.01f); + float smooth = 1.0 / (MinScreenDims * 0.25 * max(smoothAmount, 0.01f)); + + // compute box + float box = roundBox(ScreenDims * RoundCornerCoord, ScreenDims * RatioCorrection, radius); + + // apply smooth + // box *= smooth; + // box += 1.0f - pow(smooth * 0.5f, 0.5f); + + float border = smoothstep(1.0f, 0.0f, box); + + return saturate(border); +} + +// www.francois-tarlier.com/blog/cubic-lens-distortion-shader/ +float2 GetDistortedCoords(float2 coord, float amount) +{ + amount *= 0.25f; // reduced amount + + float2 RatioCorrection = GetRatioCorrecton(); + + // center coordinates + coord -= 0.5f; + + coord /= RatioCorrection; + + // lens distortion coefficient + float k = amount; + + // cubic distortion value + float kcube = amount * 2.0f; + + // compute cubic distortion factor + float r2 = coord.x * coord.x + coord.y * coord.y; + float f = kcube == 0.0f + ? 1 + r2 * k + : 1 + r2 * (k + kcube * sqrt(r2)); + + // correct zoom + f /= 1.0f + amount * 0.5f; + + // apply cubic distortion factor + coord *= f; + + coord *= RatioCorrection; + + // uncenter coordinates + coord += 0.5f; + + return coord; +} + +float4 ps_main(PS_INPUT Input) : COLOR +{ + float2 TexCoord = Input.TexCoord; + float2 BaseCoord = TexCoord; + + // // test code + // // BaseCoord.x += (TexCoord.x > 0.5f ? -0.5f : 0.0f); + // BaseCoord.y += (TexCoord.y > 0.5f ? -0.5f : 0.0f); + // BaseCoord.y *= 2.0f; + + // Screen Curvature + BaseCoord = GetDistortedCoords(BaseCoord, CurvatureAmount); + + float2 BaseCoordCentered = BaseCoord; + BaseCoordCentered -= 0.5f; + + // // test code + // BaseCoord.y /= 2.0f; + // // BaseCoord.x += (TexCoord.x > 0.5f ? +0.5f : 0.0f); + // BaseCoord.y += (TexCoord.y > 0.5 ? +0.5f : 0.0f); + + float2 defaultScreenRatio = xor(OrientationSwapXY, RotationSwapXY) + ? DefaultScreenRatio.yx + : DefaultScreenRatio.xy; + + float2 BaseRatioCoordCentered = BaseCoordCentered; + BaseRatioCoordCentered *= defaultScreenRatio; + + // Color + float4 BaseColor = tex2D(DiffuseSampler, BaseCoord); + BaseColor.a = 1.0f; + + // Vignetting Simulation + float2 VignetteCoord = BaseCoordCentered; + + float VignetteFactor = GetVignetteFactor(VignetteCoord, VignettingAmount); + BaseColor.rgb *= VignetteFactor; + + // Light Reflection Simulation + float3 LightColor = float3(1.0f, 0.90f, 0.80f); + + float2 SpotCoord = BaseRatioCoordCentered; + float2 NoiseCoord = BaseRatioCoordCentered; + + float SpotAddend = GetSpotAddend(SpotCoord, ReflectionAmount); + float NoiseFactor = GetNoiseFactor(SpotAddend, random(NoiseCoord)); + BaseColor.rgb += SpotAddend * NoiseFactor * LightColor; + + // Round Corners Simulation + float2 RoundCornerCoord = BaseCoordCentered; + + float roundCornerFactor = GetRoundCornerFactor(RoundCornerCoord, RoundCornerAmount, 0); + BaseColor.rgb *= roundCornerFactor; + + // // test code + // BaseColor.rgb = BaseCoord.x * BaseCoord.y; + // BaseColor.rgb = TexCoord.y > 0.5f ? 1.0f : 0.5f; + + return BaseColor; +} + +//----------------------------------------------------------------------------- +// Distortion Effect +//----------------------------------------------------------------------------- + +technique DistortionTechnique +{ + pass Pass0 + { + Lighting = FALSE; + + VertexShader = compile vs_3_0 vs_main(); + PixelShader = compile ps_3_0 ps_main(); + } +}
\ No newline at end of file |