WPF网格类型像素着色器

wpf · 浏览次数 : 0

小编点评

这段代码主要介绍了如何使用WPF的ShaderEffect进行图形渲染,特别是在处理纹理坐标和顶点着色器方面的一些技巧。以下是对这些代码片段的详细解释: 1. **固定功能与纹理坐标的处理**: - WPF的ShaderEffect主要用于实现像素着色器,因此无法直接编写顶点着色器。 - 纹理坐标(TEXCOORD)在WPF中提供了便利,尤其是在处理二维纹理映射时。 2. **二分网格示例**: - 示例中展示了如何使用ceil0-1移动定义域到-0.5 - 0.5,并向上取整的方法来处理二分网格。 - 这种方法允许开发者在一个有限的定义域内(如0-1)进行插值和计算。 3. **四分网格示例**: - 在四分网格的例子中,使用了ceil0-1来处理放大和移动定义域的过程。 - 这里涉及到对uv.y坐标的操作,以及如何通过向上取整来处理四分网格的细分。 4. **二值化多分网格示例**: - 该示例展示了如何使用sin round和abs函数来处理二值化多分网格。 - 这种方法通过周期函数调整定义域,并通过四舍五入来实现二值化效果。 5. **二值化方格示例**: - 在这个例子中,使用了sin round和abs函数来处理二值化方格。 - 与二分网格类似,这里也涉及到了如何通过阈值过滤出山尖部分。 6. **动态方格示例**: - 动态方格的示例中,使用了sin abs max step来创建动态的线框网格。 - 这种方法通过周期性函数和阈值来生成动态的线条和形状。 7. **线框网格示例**: - 线框网格的示例中,使用了sin abs max step来创建线框网格。 - 这种方法通过周期函数和阈值来生成线性的图案。 8. **线框网格上滚动的小球示例**: - 在这个示例中,结合了sin abs max step和鼠标交互来创建一个动态的小球效果。 - 这种方法通过结合线框网格和鼠标位置来创建一个交互式的视觉效果。 9. **鼠标操控小球示例**: - 这个示例展示了一个自定义的ShaderEffect,它能够响应鼠标的移动,并根据鼠标的位置动态改变其颜色。 - 通过绑定InputProperty和MousePositionProperty,实现了鼠标位置的实时更新和显示。 请注意,上述代码可能需要根据您的具体需求进行调整和优化。此外,由于WPF和ShaderEffect的复杂性,可能需要对图形编程和渲染管线有一定的了解才能正确地实现这些效果。

正文

由于WPF只能写像素着色器,没法写顶点着色器,所以只能在这上面做文章了
刚好有个纹理坐标TEXCOORD输入可用,而且值的范围是已知的0-1,左上角是原点,这就好办了

例子

索引

二分网格

  • 使用ceil
  • 0-1移动定义域到-0.5 - 0.5,然后向上取整变成 0 / 1
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float ab =  ceil( uv.y-0.5 );
    return float4(ab,ab,ab,1.0);
}

image

4分网格

  • 使用ceil
  • 0-1,先放大定义域0-4,然后向左移动定义域,-0.5 - 3.5,向上取整 0/1/2/3,最后压缩0/0.25/0.5/0.75/1
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float ab =  ceil( uv.y*4-0.5 );
    float scale=ab/4;
    return float4(scale,scale,scale,1.0);
}

image

二值化多分网格

  • 使用sin round
  • 利用周期函数把定义域0-1范围的周期调整到指定数,然后值域压扁-0.5 - 0.5,向上移动0-1,四舍五入二值化
//三角函数是天然的周期函数
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float num=6;
    float2 ab =  0.5*sin(uv*3.1415*num )+0.5;
    float2 scale=round(ab);
    return float4(scale.y,scale.y,scale.y,1.0);
}

image

二值化方格

  • 使用sin round abs
  • 在上一篇基础上,相乘生成纵横条纹。但这形成十字条纹,为了产生交错条纹,就不能相乘,只能相加
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float num=7;
    float abx =  0.5*sin(uv.x*3.1415*num )+0.5;
    float aby =  0.5*sin(uv.y*3.1415*num )+0.5;
    float scale=abs((round(abx)/2)+(round(aby)/2)-0.5);
    //0.4是避免浮点数精度问题,否则直接用round(scale)
    float scale2=ceil(scale-0.4);
    return float4(scale2,scale2,scale2,1.0);
}

image

动态方格

  • 使用sin round abs
/// <summary> time </summary>
/// <minValue>0</minValue>
/// <maxValue>100</maxValue>
/// <defaultValue>0</defaultValue>
float time : register(C0);
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float num=7;
    float abx =  0.5*sin(uv.x*3.1415*num+time )+0.5;
    float aby =  0.5*sin(uv.y*3.1415*num )+0.5;
    float scale=abs((round(abx)/2)+(round(aby)/2)-0.5);
    float scale2=ceil(scale-0.4);
    return float4(scale2,scale2,scale2,1.0);
}

image

线框网格

  • 使用sin abs max step
  • 将周期函数取绝对值,变成一个个山峰,然后下沉,利用一个阈值,过滤出山尖
float4 main(float2 uv : TEXCOORD) : COLOR
{
    float gridLines = 11;

    float gridLineX = step(0.99, abs(sin(uv.x * 3.1415 * gridLines))); 
    float gridLineY = step(0.99, abs(sin(uv.y * 3.1415 * gridLines))); 

    float4 color = float4(max(gridLineX,gridLineY) , max(gridLineX,gridLineY) , max(gridLineX,gridLineY) , 1.0);

    return color;
}

image

线框网格上滚动的小球

  • 使用sin abs max step
  • 在前一篇基础上,再传入鼠标位置,并再鼠标周围画一个白色圆形,覆盖线框颜色设置。使用语义VPOS获取像素位置判断和鼠标距离
float2 mousePosition : register(C0);
float4 main(float2 uv : TEXCOORD,float2 positon : VPOS) : COLOR
{
    float gridLines = 11;

    float gridLineX = step(0.99, abs(sin(uv.x * 3.1415 * gridLines))); 
    float gridLineY = step(0.99, abs(sin(uv.y * 3.1415 * gridLines)));
    float maxline=max(gridLineX,gridLineY);
    
    float innerCircle = 1.0 - step(50,length(positon-mousePosition));
    float maxResult=max(maxline,innerCircle);

    float4 color = float4(maxResult , maxResult , maxResult , 1.0);

    return color;
}

image

鼠标操控小球

public class MouseCaptureEffect : ShaderEffect
{
    public static readonly DependencyProperty InputProperty = ShaderEffect.RegisterPixelShaderSamplerProperty("Input", typeof(MouseCaptureEffect), 0);
    public static readonly DependencyProperty MousePositionProperty = DependencyProperty.Register("MousePosition", typeof(Point), typeof(MouseCaptureEffect), new UIPropertyMetadata(new Point(0D, 0D), PixelShaderConstantCallback(0)));
    public MouseCaptureEffect()
    {
        PixelShader pixelShader = new PixelShader();
        pixelShader.UriSource = new Uri("pack://application:,,,/你的程序集名称;component/路径/TextEffect3.ps", UriKind.Absolute);
        this.PixelShader = pixelShader;

        this.UpdateShaderValue(InputProperty);
        this.UpdateShaderValue(MousePositionProperty);
    }
    public Brush Input
    {
        get
        {
            return ((Brush)(this.GetValue(InputProperty)));
        }
        set
        {
            this.SetValue(InputProperty, value);
        }
    }
    /// <summary> mouse </summary>
    public Point MousePosition
    {
        get
        {
            return ((Point)(this.GetValue(MousePositionProperty)));
        }
        set
        {
            this.SetValue(MousePositionProperty, value);
            Debug.WriteLine("aaa");
        }
    }
}
<Button Content="Btn">
    <Button.Effect>
        <local:MouseCaptureEffect x:Name="me" MousePosition="{Binding MousePositionw,Mode=TwoWay}" >
        </local:MouseCaptureEffect>
    </Button.Effect>
</Button>
this.MouseMove += (sender, e) =>
{
    //这行代码不管用
    //MousePositionw = e.GetPosition(this);
    // 更新鼠标位置
    me.MousePosition= MousePositionw;
};

要注意的时,通过绑定的方式更新没成功,只好手动赋值,不知道哪里出问题了
image

与WPF网格类型像素着色器相似的内容:

WPF网格类型像素着色器

由于WPF只能写像素着色器,没法写顶点着色器,所以只能在这上面做文章了 刚好有个纹理坐标TEXCOORD输入可用,而且值的范围是已知的0-1,左上角是原点,这就好办了 例子 索引 二分网格 使用ceil 0-1移动定义域到-0.5 - 0.5,然后向上取整变成 0 / 1 float4 main(f

能快速构建和定制网络拓扑图的WPF开源项目-NodeNetwork

大家好,我是沙漠尽头的狼,今天介绍一个WPF开源项目-NodeNetwork,它可以帮助我们快速构建和定制网络拓扑图。 一、前言 在现代软件开发中,数据可视化和可交互性越来越受到关注。为了实现这一点,通常需要使用各种图表、表格、网络拓扑图等控件。然而,对于某些特殊的场景,这些控件可能无法满足需求,此

.NET C# 程序自动更新组件

引言 本来博主想偷懒使用AutoUpdater.NET组件,但由于博主项目有些特殊性和它的功能过于多,于是博主自己实现一个轻量级独立自动更新组件,可稍作修改集成到大家自己项目中,比如:WPF/Winform/Windows服务。大致思路:发现更新后,从网络上下载更新包并进行解压,同时在 WinFor

WPF/C#:实现导航功能

前言 在WPF中使用导航功能可以使用Frame控件,这是比较基础的一种方法。前几天分享了wpfui中NavigationView的基本用法,但是如果真正在项目中使用起来,基础的用法是无法满足的。今天通过wpfui中的mvvm例子来说明在wpfui中如何通过依赖注入与MVVM模式使用导航功能。实践起来

WPF/C#:在WPF中如何实现依赖注入

本文先介绍依赖注入的概念,再解释为什么要进行依赖注入,最后通过 WPF Gallery 这个项目学习如何在WPF中使用依赖注入。

在WPF中使用着色器

概念类比 范畴 CPU GPU 二进制文件 .exe .cso / .ps 二进制指令 机器码 CSO(shader指令) 助记符 汇编 SL 高级语言 C# HLSL 高级语言文件 .cs .hlsl / .fx 高级语言编译器 csc.exe fxc.exe API .NET API Direc

WPF/C#:如何实现拖拉元素

前言 在Canvas中放置了一些元素,需要能够拖拉这些元素,在WPF Samples中的DragDropObjects项目中告诉了我们如何实现这种效果。 效果如下所示: 拖拉过程中的效果如下所示: 具体实现 xaml页面 我们先来看看xaml:

WPF 做一个超级简单的 1024 数字接龙游戏

这是一个我给自己做着玩的游戏,没有什么复杂的界面,就一些简单的逻辑 游戏的规则十分简单,那就是有多个列表。程序会给出一个数字,玩家决定数字放在哪个列表里面。如果放入列表里面的数字和列表里面最后一个数字相同,那两个数字将会叠加进行合并,合并两个 1024 将会自动清理掉整个列表 如下图,有 5 个列表

WPF/C#:数据绑定到方法

在WPF Samples中有一个关于数据绑定到方法的Demo,该Demo结构如下: 运行效果如下所示: 来看看是如何实现的。 先来看下MainWindow.xaml中的内容:

WPF/C#:显示分组数据的两种方式

前言 本文介绍自己在遇到WPF对数据进行分组显示的需求时,可以选择的两种方案。一种方案基于ICollectionView,另一种方案基于IGrouping。 基于ICollectionView实现 相关cs代码: [ObservableProperty] private ObservableColl