头图

image.png
Are you used to seeing cookie-cutter rectangular windows on Windows systems? Want to do some different special effects but can only play within your own window? And this article will take you to make a realistic sunlight special effect, which can really illuminate other windows and pictures on your desktop, and bring a different special effect experience to your application! The whole process uses GPU acceleration, with ultra-high performance, and the code is super simple.

Effect preview

First put two animated pictures to see the effect, the GIF is relatively large, if you can't see it, you can go to the link in the note below to view it.

The sun sweeps through the clouds:

1.gif

The sun sweeps through Visual Studio:

2.gif

It can be seen that when the sunlight passes through the clouds, the strong light and the light part of the clouds are superimposed, which makes people feel that the illuminated part of the clouds is very dazzling. When the sunlight passes through the Visual Studio interface, the solid color part can see the shape of the sunlight, and the high saturation part is particularly dazzling under the sunlight.

The sun sweeps through the clouds:

https://blog.walterlv.com/static/posts/2021-08-05-sunshine-over-cloud.gif

The sun sweeps through Visual Studio:

https://blog.walterlv.com/static/posts/2021-08-05-sunshine-over-visual-studio.gif

Code

The code to achieve the effects of this article is actually very small, only the following steps:

  1. Make a fully transparent window
  2. Write a pixel shader
  3. Draw a simple sun shape

But before we start, let's create a blank WPF project:

3.png

Step 1: Make a fully transparent window

AllowsTransparency="True" , which is widely circulated on the Internet, is fine, but I personally don't like it because the performance is not good. I would recommend you to use the high-performance transparent window implementation scheme recommended in my other blog: WPF to make high-performance transparent background shaped windows

If you don’t want to see it now, I can directly post the code of MainWindow.xaml.cs (rest assured, no code is needed in other places):

<Window x:Class="Walterlv.DesktopSunshine.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Walterlv.DesktopSunshine"
        mc:Ignorable="d" Title="Walterlv.DesktopSunshine" Width="240" Height="240"
        Background="Transparent" WindowStyle="None" ResizeMode="NoResize">
    <WindowChrome.WindowChrome>
        <WindowChrome GlassFrameThickness="-1" ResizeBorderThickness="0" CornerRadius="0" CaptionHeight="240" />
    </WindowChrome.WindowChrome>
    <Grid>
    </Grid>
</Window>

The most important are the four attributes Background="Transparent" , WindowStyle="None" , ResizeMode="NoResize" and GlassFrameThickness="-1"

For other codes, I am just making a normal window. The size 240 is to accommodate the size of a sun.

WPF makes high-performance transparent background special-shaped windows:

https://blog.walterlv.com/post/wpf-transparent-window-without-allows-transparency

Step 2: Write a pixel shader

To learn how to write pixel shaders, you can read another blog of mine: Getting Started with WPF Pixel Shader: Use Shazzam Shader Editor to write HLSL pixel shader code.

This code needs to be written in the pixel shader.

sampler2D  inputSampler : register(S0);
float Threshold : register(C0);
​
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float4 color = tex2D(inputSampler, uv);
    float a = color.a;
​
    if(a < Threshold)
    {
         color.a  = 0;
    }
    else
    {
        color.a  = 1;
    }
​
    return color;
}

Put your own compiled files anywhere in the solution (in this example, put them in the Assets folder):
4.png

Important: Next, add the .ps file to the compilation. Please double-click the project (Walterlv.DesktopSunshine) to edit its project file (.csproj). I have highlighted the lines that need to be added below.

   <Project Sdk="Microsoft.NET.Sdk">
​
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net6.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <UseWPF>true</UseWPF>
      </PropertyGroup>
​
++    <ItemGroup>
++      <Resource Include="Assets\**\*.ps" />
++    </ItemGroup>
​
    </Project>

Then, write a C# type that uses this .ps file. I named it BinaryAlphaEffect.cs.

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;
​
namespace Walterlv.DesktopSunshine
{
    public class BinaryAlphaEffect : ShaderEffect
    {
        public static readonly DependencyProperty InputProperty = RegisterPixelShaderSamplerProperty(
            "Input", typeof(BinaryAlphaEffect), 0);
​
        public static readonly DependencyProperty ThresholdProperty = DependencyProperty.Register(
            "Threshold", typeof(double), typeof(BinaryAlphaEffect),
            new UIPropertyMetadata(1.0d, PixelShaderConstantCallback(0)));
​
        public BinaryAlphaEffect()
        {
            PixelShader = new PixelShader
            {
                UriSource = new Uri("/Assets/BinaryAlphaEffect.ps", UriKind.Relative),
            };
​
            UpdateShaderValue(InputProperty);
            UpdateShaderValue(ThresholdProperty);
        }
​
        public Brush Input
        {
            get => (Brush)GetValue(InputProperty);
            set => SetValue(InputProperty, value);
        }
​
        public double Threshold
        {
            get => (double)GetValue(ThresholdProperty);
            set => SetValue(ThresholdProperty, value);
        }
    }
}

This Threshold is a binary threshold, which can be used to adjust the sunlight effect. I set the default value to 1, so that the sunlight effect is the strongest. (In fact, the effect of other values is horrible. Because I originally wrote this code for not making sunlight, but I accidentally made the sunlight effect in the middle. I think it is very interesting to teach you.)

Use Shazzam Shader Editor to write HLSL pixel shader code:

https://blog.walterlv.com/post/create-wpf-pixel-shader-effects-using-shazzam-shader-editor

Step 3: Draw a simple sun shape

I only draw a circle to represent the shape of sunlight (if you want to use other shapes, you can use your own creativity). So add a little code in MainWindow.xaml:

        </WindowChrome.WindowChrome>
++      <Border>
++          <Ellipse Fill="White" Width="160" Height="160">
++              <UIElement.Effect>
++                  <BlurEffect Radius="40" />
++              </UIElement.Effect>
++          </Ellipse>
++      </Border>
    </Window>

Here, some blur effect is added to the circle, which is necessary.

Then, use the pixel shader we wrote in the second step:

    <Border>
++      <UIElement.Effect>
++          <local:BinaryAlphaEffect />
++      </UIElement.Effect>
        <Ellipse Fill="White" Width="160" Height="160">
            <UIElement.Effect>
                <BlurEffect Radius="40" />
            </UIElement.Effect>
        </Ellipse>
    </Border>

So far, all the code has been completed.

To summarize, we wrote these codes:

  1. A newly created WPF project template (including App.xaml App.xaml.cs MainWindow.xaml MainWindow.xaml.cs AssemblyInfo.cs that comes with the template)
  2. Downloaded or compiled BinaryAlphaEffect.ps pixel shader file, and BinaryAlphaEffect.cs file to use it
  3. Use several Border and Ellipse in MainWindow.xaml of BinaryAlphaEffect class

Is the amount of code very small? Next, is the moment to witness the miracle.

Effect and performance

The sun sweeps through Windows 11 comes with wallpaper. Near the sun, it merges with the sun; in the forest, the sun is blocked by leaves; on the water, the sun shines with the waves; on the rocks, the sun shines brightly on the rocks.
6.gif

You can put this sunlight anywhere, even in front of the video being played, it still has real-time effects in every frame.

The most important thing is-it hardly consumes performance! Because it runs in the pixel shader part of the graphics rendering pipeline, all its code is executed in parallel on the GPU, and each execution requires less than 10 instructions. You can see that in the task manager, its CPU and GPU consumption are both 0.

7.png

This article will be updated frequently, please read the original text:

https://blog.walterlv.com/post/create-a-realistic-sunshine-on-your-desktop-using-wpf.html to avoid the misleading of outdated wrong knowledge and have a better reading experience.

The sun sweeps through Windows 11 comes with wallpaper:
https://blog.walterlv.com/static/posts/2021-08-05-sunshine-over-forest.gif

Microsoft's Most Valuable Expert is a global award granted by Microsoft to third-party technology professionals. For 27 years, technology community leaders around the world have won this award for sharing their expertise and experience in online and offline technology communities.

MVP is a rigorously selected team of experts. They represent the most skilled and intelligent people. They are experts who are passionate and helpful to the community. MVP is committed to helping others through speeches, forum questions and answers, creating websites, writing blogs, sharing videos, open source projects, organizing conferences, etc., and to help users in the Microsoft technology community use Microsoft technology to the greatest extent.
For more details, please visit the official website:
https://mvp.microsoft.com/zh-cn


微软技术栈
423 声望998 粉丝

微软技术生态官方平台。予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。