// Copyright (C) Microsoft Corporation. All rights reserved. // On update: build, rename & replace ShaderEffect.cso #define D2D_INPUT_COUNT 1 #define D2D_REQUIRES_SCENE_POSITION #include "d2d1effecthelpers.hlsli" // Uniform // Color the screen slowly turns as the ripple completes float4 glimmerColor; float2 resolution; float2 clickPos; float time; // Wavelength of the ripple static const float wavelength = 0.75; // Height of the wave static const float amplitude = 0.04; // Duration of the animation in seconds // NOTE - if the click is in the center of the screen, the animation reaches the edges of the // screen faster than if the click is at one edge of the screen. This duration is the MAXIMUM // amount of time the animation will take. It will finish twice as fast if the click is in the // center of the screen. static const float duration = 0.7; // Color shift for chromatic aberration, as a multipler of the wave static const float2 redShift = float2(0.0115, 1.15); static const float2 greenShift = float2(0.01, 1.0); static const float2 blueShift = float2(0.0085, 0.85); static const float M_2PI = 6.28318530718; D2D_PS_ENTRY(main) { // Calculate distance of pixel from click position float2 fragCoord = D2DGetScenePosition().xy; float resolution1D = min(resolution.x, resolution.y); float2 offset = fragCoord - clickPos; float dist = length(offset) / resolution1D; // Time passed from 0 to 1 float t = min(1.0, time / duration); // Define the ripple radius based on time // -(x-1)^2 + 1 is a fast-in/ease-out function float rippleRadius = -(t-1)*(t-1)+1; // Fade the wavelength to widen with time // (we will also adjust amplitude down with time, like it is spreading out) // Careful to never let it reach 0, since we divide by this later. float lambda = wavelength * (1 + t * 0.1); // Calculate how many periods away this fragment is float d = max(0, (rippleRadius-dist) / lambda); // Height of the sine wave float sinFactor = -sin(d * M_2PI); // Fade the ripple amplitude the farther away this fragment is from the current radius float fade = exp(-d * d * 4); // Calculate the height of the wave using all those parameters. // Multiply by 1-t to make the amplitude fade down linearly over time. float h = sinFactor * fade * max(1-t,0); // Uncomment to see the sine wave // return float4(h,h,h,1); // Multiply by the amplitude h *= amplitude; float2 redChrom = resolution1D / 2 * redShift; float2 greenChrom = resolution1D / 2 * greenShift; float2 blueChrom = resolution1D / 2 * blueShift; // Chromatic aberration offsets // Alpha is disabled for the moment but can be re-enabled if we want. float2 uvRed = (fragCoord + h * redChrom) / resolution; float2 uvGreen = (fragCoord + h * greenChrom) / resolution; float2 uvBlue = (fragCoord + h * blueChrom) / resolution; // Clamp to the last pixel float2 minBorder = float2(1,1) / resolution; float2 maxBorder = (resolution-float2(1,1)) / resolution; uvRed = clamp(uvRed, minBorder, maxBorder); uvGreen = clamp(uvGreen, minBorder, maxBorder); uvBlue = clamp(uvBlue, minBorder, maxBorder); float red = D2DSampleInput(0, uvRed).r; float green = D2DSampleInput(0, uvGreen).g; float blue = D2DSampleInput(0, uvBlue).b; // Add in some blue haze // e^(-t*t*4) is a smooth-in smooth-out easing function from 1 to 0, so subtract from 1 float glimmerAlpha = glimmerColor.a * (1 - exp(-t * t * 4)); return float4(float3(red,green,blue) * (1 - glimmerAlpha) + glimmerColor.rgb * glimmerAlpha, 1); }