//----------------------------------------------------------------------------- // Scanline & Shadowmask Effect //----------------------------------------------------------------------------- texture DiffuseTexture; sampler DiffuseSampler = sampler_state { Texture = ; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; AddressU = CLAMP; AddressV = CLAMP; AddressW = CLAMP; }; texture ShadowTexture; sampler ShadowSampler = sampler_state { Texture = ; MipFilter = LINEAR; MinFilter = LINEAR; MagFilter = LINEAR; AddressU = WRAP; AddressV = WRAP; AddressW = WRAP; }; //----------------------------------------------------------------------------- // Vertex Definitions //----------------------------------------------------------------------------- struct VS_OUTPUT { float4 Position : POSITION; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; struct VS_INPUT { float4 Position : POSITION; float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; float2 Unused : TEXCOORD1; }; struct PS_INPUT { float4 Color : COLOR0; float2 TexCoord : TEXCOORD0; }; //----------------------------------------------------------------------------- // Scanline & Shadowmask Vertex Shader //----------------------------------------------------------------------------- uniform float2 ScreenDims; uniform float2 SourceDims; uniform float2 SourceRect; 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; Output.Position.xy -= 0.5f; Output.Position *= float4(2.0f, 2.0f, 1.0f, 1.0f); Output.Color = Input.Color; Output.TexCoord = Input.TexCoord + 0.5f / SourceDims; return Output; } //----------------------------------------------------------------------------- // Post-Processing Pixel Shader //----------------------------------------------------------------------------- uniform float PI = 3.14159265f; uniform float Epsilon = 0.00000001f; uniform float CurvatureAmount = 0.0f; uniform float PincushionAmount = 0.0f; 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 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 float3 Power = float3(1.0f, 1.0f, 1.0f); uniform float3 Floor = float3(0.0f, 0.0f, 0.0f); static const float MagicConst = 0.5f; float4 ps_main(PS_INPUT Input) : COLOR { float2 UsedArea = 1.0f / SourceRect; float2 HalfRect = SourceRect * 0.5f; float2 R2 = 1.0f / pow(length(UsedArea), 2.0f); // Warning: Magic constant float2 CoordCorrection0 = float2(UsedArea.x * (MagicConst) / SourceDims.x, UsedArea.y * (MagicConst) / SourceDims.y); float2 CoordCorrection1 = float2(UsedArea.x * (1.0f + MagicConst) / SourceDims.x, UsedArea.y * (1.0f + MagicConst) / SourceDims.y); // Reduce Pincushion Amount float CurvatureAmountReduced = CurvatureAmount * 0.25f; // -- Screen Pincushion Calculation -- float2 PinUnitCoord = Input.TexCoord * UsedArea * 2.0f - 1.0f; float CurvatureR2 = pow(length(PinUnitCoord), 2.0f) * R2; float2 CurvatureCurve = PinUnitCoord * CurvatureAmountReduced * CurvatureR2; float2 BaseCoord = Input.TexCoord; float2 ScanCoord = BaseCoord - 0.5f / ScreenDims; BaseCoord -= HalfRect; BaseCoord *= 1.0f - CurvatureAmountReduced * UsedArea * 0.2f; // Warning: Magic constant BaseCoord += HalfRect; BaseCoord += CurvatureCurve; ScanCoord -= HalfRect; ScanCoord *= 1.0f - CurvatureAmountReduced * UsedArea * 0.2f; // Warning: Magic constant ScanCoord += HalfRect; ScanCoord += CurvatureCurve; float4 BaseTexel = tex2D(DiffuseSampler, BaseCoord); // BaseTexel.r = 0.5f; // debug // BaseTexel.g = 0.5f; // debug // BaseTexel.b = 0.5f; // debug // BaseTexel.a = 1.00f; // debug // -- 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; float2 ShadowMaskSize = float2( ShadowCount.x < 0.0f ? SourceDims.x * SourceRect.x / ShadowCount.x * -1.0f : ShadowCount.x, ShadowCount.y < 0.0f ? SourceDims.y * SourceRect.y / ShadowCount.y * -1.0f : ShadowCount.y); float2 ShadowFrac = frac(BaseCoord * ShadowMaskSize * UsedArea); float2 ShadowCoord = ShadowFrac * ShadowUV + 1.5f / ShadowDims; float3 ShadowTexel = lerp(1.0f, tex2D(ShadowSampler, ShadowCoord).rgb, ShadowAlpha); // -- Final Pixel -- float4 Output = float4(Scanned * ShadowTexel, BaseTexel.a) * Input.Color; Output.r = pow(Output.r, Power.r); Output.g = pow(Output.g, Power.g); Output.b = pow(Output.b, Power.b); Output.a = 1.0f; // Output.r = 0.25f; // debug // Output.g = 0.25f; // debug // Output.b = 0.25f; // debug float2 DefaultUsedArea = float2(10.0f / 7.0f, 1.0f); // float2 DefaultUsedArea = float2(4.0f / 3.0f, 1.0f); float2 CurvatureCoord = Input.TexCoord; CurvatureCoord -= HalfRect; CurvatureCoord *= 1.0f - CurvatureAmountReduced * UsedArea * MagicConst; // Warning: Magic constant // CurvatureCoord += HalfRect; CurvatureCoord += CurvatureCurve; // CurvatureCoord *= UsedArea * DefaultUsedArea; // CurvatureCoord *= UsedArea * DefaultUsedArea * 1.5f; CurvatureCoord *= UsedArea * DefaultUsedArea * 1.25f; // -- Vignetting -- float2 VignetteCoord = CurvatureCoord; float VignetteAmount = 1.0f - saturate(dot(VignetteCoord, VignetteCoord)); float VignetteDarkness = pow(1.0f - PincushionAmount, 2.0f); float VignetteRadius = PincushionAmount * 2.0f + 1.0f; float Vignette = pow(VignetteAmount, VignetteRadius) + VignetteDarkness; Output.rgb *= saturate(Vignette); // Output.r = 0.25f; // debug // Output.g = 0.25f; // debug // Output.b = 0.25f; // debug // -- Light Spot -- float2 SpotCoord = CurvatureCoord; SpotCoord += float2(-0.25f, 0.25f) * DefaultUsedArea; // float SpotAmount = 1.0f - saturate(pow(dot(SpotCoord, SpotCoord), 0.5f)); // float SpotRadius = CurvatureAmount * 2.0f + 4.0f; // float Spot = pow(SpotAmount, SpotRadius) * 0.25f; float SpotAmount = 1.0f - saturate(pow(dot(SpotCoord, SpotCoord), 0.25f)); float SpotRadius = CurvatureAmount * 4.0f + 2.0f; float Spot = pow(SpotAmount, SpotRadius) * 0.5f; // -- Light Reflection -- float2 ReflectionCoord = BaseCoord * UsedArea; ReflectionCoord.x = 1.0f + CoordCorrection1.x - ReflectionCoord.x; ReflectionCoord.y = 0.0f + CoordCorrection0.y + ReflectionCoord.y; float ReflectionAmount = pow(ReflectionCoord.x * ReflectionCoord.y, 0.25f); float Reflection = ReflectionAmount * 0.125f; Output.rgb += (saturate(Reflection) + saturate(Spot)) * CurvatureAmount; // -- Round Corners -- float2 CornerCoords = BaseCoord * UsedArea; float radius = 0.0f; if (CurvatureAmount > 0.0f) { radius = pow(CurvatureAmount, 0.125f) * 0.125f; } float threshold = pow(radius, 4.0f); if ( (CornerCoords.x - CoordCorrection0.x) * (CornerCoords.y - CoordCorrection0.y) <= threshold || (1.0f + CoordCorrection1.x - CornerCoords.x) * (CornerCoords.y - CoordCorrection0.y) <= threshold || (CornerCoords.x - CoordCorrection0.x) * (1.0f + CoordCorrection1.y - CornerCoords.y) <= threshold || (1.0f + CoordCorrection1.x - CornerCoords.x) * (1.0f + CoordCorrection1.y - CornerCoords.y) <= threshold ) { Output.rgb = float3(0.0f, 0.0f, 0.0f); } return Output; } //----------------------------------------------------------------------------- // Scanline & Shadowmask Effect //----------------------------------------------------------------------------- technique ScanMaskTechnique { pass Pass0 { Lighting = FALSE; //Sampler[0] = ; VertexShader = compile vs_3_0 vs_main(); PixelShader = compile ps_3_0 ps_main(); } }