首页 > 其他分享 >[WPF]使用HLSL实现百叶窗动效

[WPF]使用HLSL实现百叶窗动效

时间:2023-09-06 19:24:26浏览次数:40  
标签:HLSL 代码 着色器 百叶窗 动效 WPF Shazzam public

百叶窗动画是制作PPT时常用的动画之一,本文将通过实现百叶窗动画效果的例子介绍在WPF中如何使用ShaderEffect。ShaderEffect是使用高级着色器语言(High Level Shading Language,HLSL)事先制作好并且已经编译过的效果。先看下百叶窗动画实现效果:
image

准备工作与实现

  • 编写和编译HLSL代码,创建ShaderEffect。由于HLSL有自己的语言语法,本文不做讨论。这里使用一个已有的的HLSL文件,也是后边将介绍的一个HLSL编辑器工具Shazzam Shader Editor中的案例。
  • 定义像素着色器,在UI元素中使用像素着色器,并通过动画设置百叶窗动画。
    百叶窗效果的像素着色器代码中:
public class BlindsShader : ShaderEffect
{
    public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(BlindsShader), 0);
    public static readonly DependencyProperty ProgressProperty = DependencyProperty.Register("Progress", typeof(double), typeof(BlindsShader), new UIPropertyMetadata(((double)(30D)), PixelShaderConstantCallback(0)));
    public static readonly DependencyProperty NumberOfBlindsProperty = DependencyProperty.Register("NumberOfBlinds", typeof(double), typeof(BlindsShader), new UIPropertyMetadata(((double)(5D)), PixelShaderConstantCallback(1)));
    public static readonly DependencyProperty Texture2Property = ShaderEffect.RegisterPixelShaderSamplerProperty("Texture2", typeof(BlindsShader), 1);
    public BlindsShader()
    {
        PixelShader pixelShader = new PixelShader();
        pixelShader.UriSource = new Uri("/WPFTest;component/Shader/ShaderSource/BlindsShader.ps", UriKind.Relative);
        this.PixelShader = pixelShader;

        this.UpdateShaderValue(InputProperty);
        this.UpdateShaderValue(ProgressProperty);
        this.UpdateShaderValue(NumberOfBlindsProperty);
        this.UpdateShaderValue(Texture2Property);
    }
    public Brush Input
    {
        get
        {
            return ((Brush)(this.GetValue(InputProperty)));
        }
        set
        {
            this.SetValue(InputProperty, value);
        }
    }
    /// <summary>The amount(%) of the transition from first texture to the second texture. </summary>
    public double Progress
    {
        get
        {
            return ((double)(this.GetValue(ProgressProperty)));
        }
        set
        {
            this.SetValue(ProgressProperty, value);
        }
    }
    /// <summary>The number of Blinds strips </summary>
    public double NumberOfBlinds
    {
        get
        {
            return ((double)(this.GetValue(NumberOfBlindsProperty)));
        }
        set
        {
            this.SetValue(NumberOfBlindsProperty, value);
        }
    }
    public Brush Texture2
    {
        get
        {
            return ((Brush)(this.GetValue(Texture2Property)));
        }
        set
        {
            this.SetValue(Texture2Property, value);
        }
    }
}

BlindsShader.ps是编译好的HLSL文件,Progress表示百叶窗叶片打开的进度,NumberOfBlinds是百叶窗叶片的数量,Texture2是百叶窗叶片的纹理(通常使用一个纯色的图片)。

使用百叶窗效果时,只需在resources中添加着色器和动画,并对目标UI元素的Effect设置为百叶窗动画。为了展示效果,本例用图片111.jpg作为grid的背景,用纯色图片blinds.jpg作为叶片纹理。在grid的加载时触发动画设置百叶窗叶片打开的进度。

<Window.Resources>
    <ImageBrush x:Key="imageBrush" ImageSource="111.jpg" />
    <ImageBrush x:Key="blindsBrush" ImageSource="blinds.jpg" />
    <local:BlindsShader x:Key="BlindsShader"
                        NumberOfBlinds="4"
                        Progress="0"
                        Texture2="{StaticResource blindsBrush}" />
    <Storyboard x:Key="DefaultBlindsShaderStoryboard" FillBehavior="HoldEnd">
        <DoubleAnimation Storyboard.TargetProperty="(UIElement.Effect).(local:BlindsShader.Progress)"
                            From="0"
                            To="100"
                            Duration="00:00:1.5" />
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Effect)">
            <DiscreteObjectKeyFrame KeyTime="00:00:1.5" Value="{x:Null}" />
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Grid Background="{StaticResource imageBrush}" Effect="{StaticResource BlindsShader}">
    <Grid.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard x:Name="sbLoaded" Storyboard="{DynamicResource DefaultBlindsShaderStoryboard}" />
        </EventTrigger>
    </Grid.Triggers>
</Grid>

Shazzam Shader Editor

可以使用任何一款编辑器编写HLSL,然后使用fxc.exe命令行工具编译(visual studio 2022或者Windows SDK for Windows中含有该工具)。但是Shazzam Shader Editor是一个免费的专门为 WPF 实现像素着色器而设计的一款编辑器,使用它来编写像素着色器,可以自动生成WPF中的ShaderEffect。

Shazzam Shader Editor已经好久没有维护了,其官网似乎也没了。原本开源在CodePlex上,而 CodePlex 已经关闭。但JohanLarsson 将其 Fork 到了 GitHub 上,https://github.com/JohanLarsson/Shazzam。

打开Shazzam Shader Editor,左侧显示着色器示例和全局设置(默认折叠)。选中具体的着色器后,右侧区域上方显示着色其效果,下方选项卡分别显示HLSL代码编辑窗口、预览调节窗口、生成的C#代码和生成的VB代码。
image

HLSL代码编辑窗口

HLSL代码文件是以.fx作为后缀名。编译后的文件后缀名是.ps。编辑窗口中可以编辑修改代码,按下F5就可以编译你的HLSL代码,并在界面上方预览效果。编辑器中会高亮关键词和方法,双击不要松开鼠标会弹出相应的提示。如何编写HLSL代码可以查阅HLSL and Pixel Shaders for XAML Developers这本书,Shazzam Shader Editor中左侧示例中的Tutorial也是配合该书使用的。

预览调节窗口

在这里可以设置各种预览参数,预览HLSL代码的效果。
image

生成的C#代码

这里是Shazzam Shader Editor自动生成的用C#编写的ShaderEffect,本文前边提到的百叶窗效果的像素着色器代码也就是从这里直接拷贝过去的。这里的代码默认的命名空间是Shazzam.Shaders,代码缩进是用Tab。可以在主窗体左侧的全局设置中修改。
image

生成的VB代码

这里和生成C#代码一样,只是提供VB语言编写的ShaderEffect。

在WPF中使用用HLSL

Shazzam Shader Editor编译HLSL后会生成XXX.psXXX.csXXX.vb三个文件,并保存在%LocalAppData%\Shazzam\GeneratedShaders目录下的XXXEffect目录中。这里的XXX就是你定义的HLSL的名称。
在WPF中使用时,需把XXX.ps文件以Resource的形式添加到工程中,然后把XXX.cs文件添加到工程,并根据项目结构,修改XXX.cs中引用XXX.ps文件的路径即可。

标签:HLSL,代码,着色器,百叶窗,动效,WPF,Shazzam,public
From: https://www.cnblogs.com/czwy/p/17683184.html

相关文章

  • C#+WPF上位机开发课程(模块化与反应式编程)
    点击下载:C#+WPF上位机开发课程(模块化与反应式编程)提取码:ak72上位机是指可以直接发出操控命令的计算机,一般是PC,通常用于屏幕上显示各种信号变化(液压,水位,温度等),并将这些数据存储下来,供分析。 下位机是直接控制设备,获取设备状况的计算机,一般是PLC(ProgrammableLogicController)/单......
  • 界面控件DevExpress WPF(v23.2)下半年发展路线图
    本文主要概述了DevExpress官方在下半年(v23.2)中一些与DevExpressWPF相关的开发计划。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。DevExpressWPFv23.1正式版下载DevExpress技术交流群8......
  • 【愚公系列】2023年09月 WPF控件专题 Calendar控件详解
    (文章目录)前言WPF控件是WindowsPresentationFoundation(WPF)中的基本用户界面元素。它们是可视化对象,可以用来创建各种用户界面。WPF控件可以分为两类:原生控件和自定义控件。原生控件是由Microsoft提供的内置控件,如Button、TextBox、Label、ComboBox等。这些控件都是WPF中常见......
  • dotnet 读 WPF 源代码笔记 渲染层是如何将字符 GlyphRun 画出来的
    从业务代码构建出来GlyphRun对象,在WPF的渲染层里,如何利用GlyphRun提供的数据将字符在界面呈现出来。本文将和大家聊聊从WPF的渲染层获取到GlyphRun数据,到调用DirectX的各个渲染相关方法的过程,也就是WPF绘制文本字符的原理或者实现方法大家印象中的绘制一段文本是调......
  • dotnet 读 WPF 源代码笔记 聊聊 HwndWrapper
    我在阅读WPF源代码,在HwndWrapper的静态构造函数看到了申请了HwndWrapper.GetGCMemMessage这个Windows消息,好奇这个消息是什么功能的。通过阅读WPF源代码和写测试应用,了解到这是一个完全用来内部测试或调试的消息,没有任何业务上的功能在WPF的HwndWrapper的静态构造......
  • dotnet 读 WPF 源代码笔记 GlyphRun 的 DeviceFontName 的功能是什么
    在WPF里面的GlyphRun里,有一个令人迷惑的DeviceFontName属性,似乎给这个属性传入什么值,结果都不会有变更。通过阅读源代码,可以了解到,这是一个没什么用途的属性。本文将告诉大家这个属性的细节逻辑在上一篇博客WPF简单聊聊如何使用DrawGlyphRun绘制文本里面就提到如何创......
  • WPF学习 - 自定义窗体(二)
    上一篇文章写了如何创建自定义窗体:使用WindowChrome或者WindowStyle=“None”这两种方式。本文将讲述如何设置窗体的效果(以阴影效果为例),以及在效果模式下,窗体各功能的配合。一、窗体的空间范围:窗体的范围,就是白色区域部分:包括窗体的边框,标题栏,以及内部的空白部分。出了白色......
  • cefsharp - WinForms 和 Wpf 示例之间的巨大性能差异
    https://www.coder.work/article/7217456我注意到在使用 http://www.vsynctester.com 时CefSharp.WinForms.Example和CefSharp.Wpf.Example之间存在非常重要的性能差异(以FPS计)在我的显卡控制面板和CefExampleInit()中的设置中关闭VSync时settings.CefCommandLi......
  • WPF - 之对象变形
    WPF(WindowsPresentationFoundation)是一个用于构建客户端应用程序的图形界面库,它提供了许多对象变形(ObjectTransformation)的功能。这些功能可以让你轻松地改变对象的大小、位置和角度,以实现各种视觉效果。以下是一些常用的WPF对象变形技术:TranslateTransform:用于平移(移动)......
  • 【愚公系列】2023年09月 WPF控件专题 DatePicker控件详解
    (文章目录)前言WPF控件是WindowsPresentationFoundation(WPF)中的基本用户界面元素。它们是可视化对象,可以用来创建各种用户界面。WPF控件可以分为两类:原生控件和自定义控件。原生控件是由Microsoft提供的内置控件,如Button、TextBox、Label、ComboBox等。这些控件都是WPF中常见......