summaryrefslogtreecommitdiffstatshomepage
path: root/hlsl/post.fx
diff options
context:
space:
mode:
author ImJezze <jezze@gmx.net>2015-05-03 14:41:05 +0200
committer ImJezze <jezze@gmx.net>2015-05-03 14:41:05 +0200
commita70198a5fb532f1b5826bcc0a318c1d68291c0c4 (patch)
treeab035722cba9050061facc24ed893872ea4a5abf /hlsl/post.fx
parentcc3b682e52bf097d31db78032aad01d6a0b12e94 (diff)
HLSL shader improvements
- changed shadow mask implementation, shadow count XY now represent the number of pixel the shadow UV sized tiles will take on the screen - implemented rotation of the shadow mask texture depending on the default landscape or portrait view of the screen - removed prescale and pixel border of the shadow mask texture - added option to change the shadow UV offset, to reduce the color bleeding of the shadow mask - adjusted presets to work with the changed mask implementation - reduced defocus offset - improved downsampling for better blurring - improved alignment of bloom layers (raster and vector) - applied bloom effect to the render output of screenshot and AVI recording - changed curvature effect to fit screen size - changed scanlines to be not rendered into bloom layers - changed shadow mask to be not rendered into bloom layers - changed color floor to not light the bloom layers - changed shadow mask to not dark the color floor - added image vignetting simulation and option - added round screen corner simulation and option - added screen light reflection simulation and option - made usage of unused brightness offset (additive) - removed unused pincushion option - removed duplicate shadow count Y options - removed artwork/adapture.png - added artwork/adapture-grill.png - added artwork/shadow-mask.png - added artwork/slot-mask.png - added hlsl/simple.fx - removed unused shaders::blit() function - added shaders::screen_pass() function, which handles the (raster-)rendering on screen, into screenshot and AVI recording - added effect:set_bool() function
Diffstat (limited to 'hlsl/post.fx')
-rw-r--r--hlsl/post.fx365
1 files changed, 288 insertions, 77 deletions
diff --git a/hlsl/post.fx b/hlsl/post.fx
index 89a92fd6969..07b0aa92dbb 100644
--- a/hlsl/post.fx
+++ b/hlsl/post.fx
@@ -6,7 +6,7 @@ texture DiffuseTexture;
sampler DiffuseSampler = sampler_state
{
- Texture = <DiffuseTexture>;
+ Texture = <DiffuseTexture>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
@@ -19,7 +19,7 @@ texture ShadowTexture;
sampler ShadowSampler = sampler_state
{
- Texture = <ShadowTexture>;
+ Texture = <ShadowTexture>;
MipFilter = LINEAR;
MinFilter = LINEAR;
MagFilter = LINEAR;
@@ -32,46 +32,70 @@ sampler ShadowSampler = sampler_state
// Vertex Definitions
//-----------------------------------------------------------------------------
-struct VS_OUTPUT
+struct VS_INPUT
{
float4 Position : POSITION;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
};
-struct VS_INPUT
+struct VS_OUTPUT
{
float4 Position : POSITION;
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
- float2 Unused : TEXCOORD1;
+ float2 ScreenCoord : TEXCOORD1;
};
struct PS_INPUT
{
float4 Color : COLOR0;
float2 TexCoord : TEXCOORD0;
+ float2 ScreenCoord : TEXCOORD1;
};
//-----------------------------------------------------------------------------
// Scanline & Shadowmask Vertex Shader
//-----------------------------------------------------------------------------
-uniform float2 ScreenDims;
-uniform float2 SourceDims;
-uniform float2 SourceRect;
+uniform float2 ScreenDims; // size of the window or fullscreen
+uniform float2 ScreenRatio = float2(1.0f, 3.0f / 4.0f);
+
+uniform float2 SourceDims; // size of the texture in power-of-two size
+uniform float2 SourceRect; // size of the uv rectangle
+
+uniform float2 ShadowDims = float2(32.0f, 32.0f); // size of the shadow texture (extended to power-of-two size)
+uniform float2 ShadowUVOffset = float2(0.0f, 0.0f);
+
+uniform float2 Prescale = float2(8.0f, 8.0f);
+
+uniform bool OrientationSwapXY = false; // false landscape, true portrait
+uniform bool PrepareBloom = false; // disables some effects for rendering bloom textures
VS_OUTPUT vs_main(VS_INPUT Input)
{
VS_OUTPUT Output = (VS_OUTPUT)0;
-
+
+ float2 ScreenTexelDims = 1.0f / ScreenDims;
+ float2 SourceTexelDims = 1.0f / SourceDims;
+
+ // todo: calculate offset
+ float2 ScreenCoordPrescaleOffset = 0.0f;
+ ScreenCoordPrescaleOffset += ShadowUVOffset;
+
+ Output.ScreenCoord = Input.Position;
+ Output.ScreenCoord += ScreenCoordPrescaleOffset;
+
Output.Position = float4(Input.Position.xyz, 1.0f);
Output.Position.xy /= ScreenDims;
- Output.Position.y = 1.0f - Output.Position.y;
- Output.Position.xy -= 0.5f;
- Output.Position *= float4(2.0f, 2.0f, 1.0f, 1.0f);
+ Output.Position.y = 1.0f - Output.Position.y; // flip y
+ Output.Position.xy -= 0.5f; // center
+ Output.Position.xy *= 2.0f; // zoom
+
+ Output.TexCoord = Input.TexCoord;
+ Output.TexCoord -= SourceTexelDims * 0.5f;
+
Output.Color = Input.Color;
- Output.TexCoord = Input.TexCoord + 0.5f / SourceDims;
return Output;
}
@@ -80,90 +104,277 @@ VS_OUTPUT vs_main(VS_INPUT Input)
// Post-Processing Pixel Shader
//-----------------------------------------------------------------------------
-uniform float PI = 3.14159265f;
-
-uniform float PincushionAmount = 0.00f;
-uniform float CurvatureAmount = 0.08f;
-
uniform float ScanlineAlpha = 1.0f;
uniform float ScanlineScale = 1.0f;
uniform float ScanlineBrightScale = 1.0f;
uniform float ScanlineBrightOffset = 1.0f;
uniform float ScanlineOffset = 1.0f;
-uniform float ScanlineHeight = 0.5f;
+uniform float ScanlineHeight = 1.0f;
+
+uniform float CurvatureAmount = 0.0f;
+uniform float RoundCornerAmount = 0.0f;
+uniform float VignettingAmount = 0.0f;
+uniform float ReflectionAmount = 0.0f;
uniform float ShadowAlpha = 0.0f;
-uniform float2 ShadowCount = float2(320.0f, 240.0f);
-uniform float2 ShadowUV = float2(0.375f, 0.375f);
-uniform float2 ShadowDims = float2(8.0f, 8.0f);
+uniform float2 ShadowCount = float2(6.0f, 6.0f);
+uniform float2 ShadowUV = float2(0.25f, 0.25f);
uniform float3 Power = float3(1.0f, 1.0f, 1.0f);
uniform float3 Floor = float3(0.0f, 0.0f, 0.0f);
+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)
+
+float nextPowerOfTwo(float n)
+{
+ return pow(2, floor(log2(n) / log2(2)) + 1);
+}
+
+// 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);
+}
+
+// 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);
+}
+
+float GetNoiseFactor(float n, float random)
+{
+ // smaller n become more noisy
+ return 1.0f + random * max(0.0f, 0.25f * pow(E, -4 * n));
+}
+
+float GetVignetteFactor(float2 coord, float amount)
+{
+ float2 VignetteCoord = coord;
+
+ float VignetteBlur = amount * 2.0f;
+
+ // 0.5 full screen fitting circle
+ float VignetteRadius = 1.0f - amount * 0.5f;
+ float Vignette = smoothstep(VignetteRadius, VignetteRadius - VignetteBlur, length(VignetteCoord));
+
+ // reduce strength to 50%
+ Vignette = lerp(1.0, 1.0 * Vignette, 0.5f);
+
+ return saturate(Vignette);
+}
+
+float GetSpotAddend(float2 coord, float amount)
+{
+ float2 SpotCoord = coord;
+ SpotCoord += OrientationSwapXY
+ ? float2(-0.25f, -0.25f) * ScreenRatio // upper right quadrant
+ : float2(-0.25f, 0.25f) * ScreenRatio; // upper right quadrant
+
+ 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);
+}
+
+// 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;
+}
+
+float GetRoundCornerFactor(float2 coord, float amount)
+{
+ float2 HalfSourceDims = SourceDims * 0.5f;
+ float2 SourceTexelDims = 1.0f / SourceDims;
+
+ float2 RoundCoord = coord;
+
+ // bug: offset and scale correction (due to miss-aligned fullscreen quad)
+ RoundCoord *= (1.0f + SourceTexelDims * ScreenRatio * 2.0f);
+ RoundCoord -= SourceTexelDims * ScreenRatio;
+
+ // hint: roundness correction (base on the default ratio of 4:3)
+ RoundCoord *= SourceDims / ScreenRatio;
+
+ float radius = amount * 50.0f;
+
+ // compute box
+ float box = RoundBox(RoundCoord.xy, HalfSourceDims / ScreenRatio, radius);
+
+ float solidBorder = smoothstep(1.0f, 0.5f, box);
+
+ // apply blur
+ float blur = 1.0f / max(2.0f, amount * 100.0f); // blur amount
+ box *= blur * 2.0f; // blur stength
+ box += 1.0f - pow(blur * 0.5f, 0.5f); // blur offset
+
+ float blurBorder = smoothstep(1.0f, 0.5f, box);
+
+ float border = solidBorder * (blurBorder + 0.5f);
+
+ return saturate(border);
+}
+
float4 ps_main(PS_INPUT Input) : COLOR
{
+ float2 ScreenTexelDims = 1.0f / ScreenDims;
+
float2 UsedArea = 1.0f / SourceRect;
float2 HalfRect = SourceRect * 0.5f;
- float2 R2 = 1.0f / pow(length(UsedArea), 2.0f);
- // -- Screen Pincushion Calculation --
- float2 PinUnitCoord = Input.TexCoord * UsedArea * 2.0f - 1.0f;
- float PincushionR2 = pow(length(PinUnitCoord), 2.0f) * R2;
- float2 PincushionCurve = PinUnitCoord * PincushionAmount * PincushionR2;
+
+ // Screen Curvature
+ float2 CurvatureUnitCoord = Input.TexCoord * (UsedArea * 2.0f) - 1.0f;
+ float2 CurvatureCurve =
+ CurvatureAmount * 0.25f
+ * CurvatureUnitCoord
+ * pow(length(CurvatureUnitCoord), 2.0f)
+ / pow(length(UsedArea), 2.0f);
+ float2 CurvatureZoom = 1.0f - (CurvatureAmount * 0.25f) * (UsedArea * 0.5f);
+
+ float2 ScreenCoord = Input.ScreenCoord / ScreenDims;
+ ScreenCoord -= HalfRect;
+ ScreenCoord *= CurvatureZoom; // zoom
+ ScreenCoord += HalfRect;
+ ScreenCoord += CurvatureCurve; // distortion
+
float2 BaseCoord = Input.TexCoord;
- float2 ScanCoord = BaseCoord - 0.5f / ScreenDims;
-
BaseCoord -= HalfRect;
- BaseCoord *= 1.0f - PincushionAmount * UsedArea * 0.2f; // Warning: Magic constant
+ BaseCoord *= CurvatureZoom; // zoom
BaseCoord += HalfRect;
- BaseCoord += PincushionCurve;
-
- ScanCoord -= HalfRect;
- ScanCoord *= 1.0f - PincushionAmount * UsedArea * 0.2f; // Warning: Magic constant
- ScanCoord += HalfRect;
- ScanCoord += PincushionCurve;
-
- float2 CurveClipUnitCoord = Input.TexCoord * UsedArea * 2.0f - 1.0f;
- float CurvatureClipR2 = pow(length(CurveClipUnitCoord), 2.0f) * R2;
- float2 CurvatureClipCurve = CurveClipUnitCoord * CurvatureAmount * CurvatureClipR2;
- float2 ScreenClipCoord = Input.TexCoord;
- ScreenClipCoord -= HalfRect;
- ScreenClipCoord *= 1.0f - CurvatureAmount * UsedArea * 0.2f; // Warning: Magic constant
- ScreenClipCoord += HalfRect;
- ScreenClipCoord += CurvatureClipCurve;
-
- // RGB Pincushion Calculation
- float3 PincushionCurveX = PinUnitCoord.x * PincushionAmount * PincushionR2;
- float3 PincushionCurveY = PinUnitCoord.y * PincushionAmount * PincushionR2;
-
- float4 BaseTexel = tex2D(DiffuseSampler, BaseCoord);
-
- // -- Alpha Clipping (1px border in drawd3d does not work for some reason) --
- clip((BaseCoord < 1.0f / SourceDims) ? -1 : 1);
- clip((BaseCoord > (SourceRect + 1.0f / SourceDims)) ? -1 : 1);
-
- // -- Scanline Simulation --
- float InnerSine = ScanCoord.y * SourceDims.y * ScanlineScale;
- float ScanBrightMod = sin(InnerSine * PI + ScanlineOffset * SourceDims.y);
- float3 ScanBrightness = lerp(1.0f, (pow(ScanBrightMod * ScanBrightMod, ScanlineHeight) * ScanlineBrightScale + 1.0f) * 0.5f, ScanlineAlpha);
- float3 Scanned = BaseTexel.rgb * ScanBrightness;
-
- // -- Color Compression (increasing the floor of the signal without affecting the ceiling) --
- Scanned = Floor + (1.0f - Floor) * Scanned;
-
- // Shadow mask
- // Note: This is broken right now and needs fixed
- float2 ShadowFrac = frac(BaseCoord * ShadowCount);
- float2 ShadowCoord = ShadowFrac * ShadowUV + 0.5f / ShadowDims;
- float3 ShadowTexel = lerp(1.0f, tex2D(ShadowSampler, ShadowCoord).rgb, ShadowAlpha);
+ BaseCoord += CurvatureCurve; // distortion
+
+ float2 BaseCoordCentered = Input.TexCoord;
+ BaseCoordCentered -= HalfRect;
+ BaseCoordCentered *= CurvatureZoom; // zoom
+ BaseCoordCentered += CurvatureCurve; // distortion
+
+ // float2 BaseAreaRatioCoord = BaseCoord;
+ // BaseAreaRatioCoord *= UsedArea * ScreenRatio;
+
+ float2 BaseAreaRatioCoordCentered = BaseCoordCentered;
+ BaseAreaRatioCoordCentered *= UsedArea * ScreenRatio;
+
+ // float2 BaseAreaCoord = BaseCoord;
+ // BaseAreaCoord *= UsedArea;
+
+ float2 BaseAreaCoordCentered = BaseCoordCentered;
+ BaseAreaCoordCentered *= UsedArea;
+
+ // Alpha Clipping (1px border in drawd3d does not work for some reason)
+ clip(BaseCoord < ScreenTexelDims ? -1 : 1);
+ clip(BaseCoord > SourceRect + ScreenTexelDims ? -1 : 1);
+
+ float4 BaseColor = tex2D(DiffuseSampler, BaseCoord);
+ BaseColor.a = 1.0f;
+
+ // Vignetting Simulation (may affect bloom)
+ float2 VignetteCoord = BaseAreaRatioCoordCentered;
+
+ float VignetteFactor = GetVignetteFactor(VignetteCoord, VignettingAmount);
+ BaseColor.rgb *= VignetteFactor;
+
+ // Mask Simulation (may not affect bloom)
+ if (!PrepareBloom)
+ {
+ float2 ShadowTexelDims = 1.0f / ShadowDims;
+ ShadowTexelDims = OrientationSwapXY
+ ? ShadowTexelDims.yx
+ : ShadowTexelDims.xy;
- // -- Final Pixel --
- float4 Output = float4(Scanned * ShadowTexel, BaseTexel.a) * Input.Color;
+ float2 shadowUV = ShadowUV;
+ shadowUV = OrientationSwapXY
+ ? shadowUV.yx
+ : shadowUV.xy;
- Output.r = pow(Output.r, Power.r);
- Output.g = pow(Output.g, Power.g);
- Output.b = pow(Output.b, Power.b);
+ float2 screenCoord = ScreenCoord;
+ screenCoord = OrientationSwapXY
+ ? screenCoord.yx
+ : screenCoord.xy;
+
+ float2 shadowTile = (ScreenTexelDims * ShadowCount);
+ shadowTile = OrientationSwapXY
+ ? shadowTile.yx
+ : shadowTile.xy;
+
+ float2 ShadowFrac = frac(screenCoord / shadowTile);
+ float2 ShadowCoord = (ShadowFrac * shadowUV);
+ ShadowCoord += ShadowTexelDims * 0.5f; // half texel offset
+ ShadowCoord = OrientationSwapXY
+ ? ShadowCoord.yx
+ : ShadowCoord.xy;
+
+ float3 ShadowColor = tex2D(ShadowSampler, ShadowCoord).rgb;
+ ShadowColor = lerp(1.0f, ShadowColor, ShadowAlpha);
+
+ BaseColor.rgb *= ShadowColor;
+ }
+
+ // Color Compression (may not affect bloom)
+ if (!PrepareBloom)
+ {
+ // increasing the floor of the signal without affecting the ceiling
+ BaseColor.rgb = Floor + (1.0f - Floor) * BaseColor.rgb;
+ }
+
+ // Color Power (may affect bloom)
+ BaseColor.r = pow(BaseColor.r, Power.r);
+ BaseColor.g = pow(BaseColor.g, Power.g);
+ BaseColor.b = pow(BaseColor.b, Power.b);
+
+ // Scanline Simulation (may not affect bloom)
+ if (!PrepareBloom)
+ {
+ // todo: there is an offset which can be noticed at lower prescale in high-resolution
+ float2 ScanlinePrescaleOffset = 0.0f;
+
+ float InnerSine = BaseCoordCentered.y * ScanlineScale * SourceDims.y;
+ float ScanJitter = ScanlineOffset * SourceDims.y;
+ float ScanBrightMod = sin(InnerSine * PI + ScanJitter + ScanlinePrescaleOffset);
+ float3 ScanColor = lerp(1.0f, (pow(ScanBrightMod * ScanBrightMod, ScanlineHeight) * ScanlineBrightScale + 1.0f + ScanlineBrightOffset) * 0.5f, ScanlineAlpha);
+
+ BaseColor.rgb *= ScanColor;
+ }
+
+ // Output
+ float4 Output = BaseColor * Input.Color;
Output.a = 1.0f;
+ // Light Reflection Simulation (may not affect bloom)
+ if (!PrepareBloom)
+ {
+ float3 LightColor = float3(1.0f, 0.90f, 0.80f);
+
+ float2 SpotCoord = BaseAreaRatioCoordCentered;
+ float2 NoiseCoord = BaseAreaRatioCoordCentered;
+
+ float SpotAddend = GetSpotAddend(SpotCoord, ReflectionAmount);
+ float NoiseFactor = GetNoiseFactor(SpotAddend, random(NoiseCoord));
+ Output.rgb += SpotAddend * NoiseFactor * LightColor;
+ }
+
+ // Round Corners Simulation (may affect bloom)
+ float2 RoundCornerCoord = BaseAreaCoordCentered;
+
+ float roundCornerFactor = GetRoundCornerFactor(RoundCornerCoord, RoundCornerAmount);
+ Output.rgb *= roundCornerFactor;
+
return Output;
}
@@ -180,6 +391,6 @@ technique ScanMaskTechnique
//Sampler[0] = <DiffuseSampler>;
VertexShader = compile vs_3_0 vs_main();
- PixelShader = compile ps_3_0 ps_main();
+ PixelShader = compile ps_3_0 ps_main();
}
-}
+} \ No newline at end of file