在WPF中使用着色器

概念类比

范畴 CPU GPU
二进制文件 .exe .cso / .ps
二进制指令 机器码 CSO(shader指令)
助记符 汇编 SL
高级语言 C# HLSL
高级语言文件 .cs .hlsl / .fx
高级语言编译器 csc.exe fxc.exe
API .NET API DirectX API
运行时环境 CLR DirectX
调试工具 Visual Studio Debugger RenderDoc
  • 着色器类型
着色器简称 着色器名 解释
cs_4_0 Compute Shader model 4.0 计算着色器,用于处理非图形计算任务
ds_5_0 Domain Shader model 5.0 域着色器,用于曲面细分技术中,生成顶点后处理顶点数据
fx_2_0 Effect model 2.0 效果文件,用于组合多个渲染状态和着色器程序,方便管理和使用
gs_4_0 Geometry Shader model 4.0 几何着色器,能接收一些图形形状作为输入,并输出其他形状,用于生成新顶点和图形
hs_5_0 Hull Shader model 5.0 曲面控制着色器,用于图形的曲面细分
ps_2_0 Pixel Shader model 2.0 像素着色器,用于计算像素颜色
tx_1_0 Texture Shader model 1.0 (software) 纹理着色器,主要用于处理纹理映射
vs_1_1 Vertex Shader model 1.1 顶点着色器,用于处理每个顶点数据

3DS Max HLSL编写与预览

  • 首先,为了避免折腾和跟上b站的视频教程,下载3DS Max,接着添加一个茶壶
    只是教程用的是Direct9,我们现在用的是Direct11,语法有点差异

    打开3DS Max,按下快捷键M,或者点击材质编辑器

    然后切换模式,换成精简材质编辑器

    点击物理材质切换自己写的shader

    选择DirectX Shader材质

    点击确定

    点击路径,可选择自定义材质

可以事先在桌面上新建一个txt文件,然后把扩展名改为.fx,可以使用vscode或者visualStudio下载HLSL扩展进行编辑

这列我提供一个Direct11的最简单的纯色着色器效果文件solidColor.fx

// solidColor.fx


//世界投影矩阵
//用来将顶点从模型空间转换到最终的裁剪空间
float4x4 WorldViewProjection : WorldViewProjection < string UIWidget="None"; >;

//UI面板项目
float4 SolidColor
<
    string UIWidget = "Color";
    string UIName="Solid Color";
> = float4(1.0f, 1.0f, 1.0f, 1.0f);

struct VertexShaderInput
{
    //顶点着色器输入用这个语义
    //表示顶点的位置信息
    //模型空间(或世界空间)中定义的
    float4 Position : POSITION;
};

struct VertexShaderOutput
{
    //顶点着色器输出用这个语义
    //表示顶点在裁剪空间(Clip Space)中的位置
    //用来决定顶点在屏幕上位置的空间
    float4 Position : SV_Position;
};

struct PixelShaderOutput
{
    float4 Color : SV_TARGET;
};

//================== 简单的顶点着色器函数
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    // 计算最终的顶点位置
    output.Position = mul(input.Position, WorldViewProjection);

    return output;
}


//=============== 基本像素着色器函数
PixelShaderOutput PixelShaderFunction()
{
    PixelShaderOutput output;

    // 设置像素颜色为 SolidColor 定义的颜色
    output.Color = SolidColor;

    return output;
}

// 定义渲染效果
//Direct9写technique
//Direct10写technique10
//Direct11写technique11
technique11 SolidColorTechnique
{
    pass P0
    {
        // 基本顶点着色器
        VertexShader = compile vs_5_0 VertexShaderFunction();

        // 基本像素着色器
        PixelShader = compile ps_5_0 PixelShaderFunction();
    }
}

然后把这个材质拖到模型上

参数Solid Color是我们在代码中定义的组件,用来选材质颜色

float4 SolidColor
<
    string UIWidget = "Color";
    string UIName="Solid Color";
> = float4(1.0f, 1.0f, 1.0f, 1.0f);

WPF着色器编写与使用

看了下,似乎wpf只支持像素着色器,不支持顶点着色器。那代码就简化许多了。

第二个问题是wpf中没有通过HLSL生成UI控件,怎么调整SolidColor?

我看了下HLSL变量声明语法,原来<DataType名称 = 值;... ;>是批注语法效果框架能识别,但会被hlsl忽略
https://learn.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-syntax

[Storage_Class] [Type_Modifier] Type Name[Index] [: Semantic] [: Packoffset] [: Register]; [Annotations] [= Initial_Value]

wpf中使用的则是Register可选部分,从寄存器读取输入

wpfSolidColor.fx

struct PixelShaderOutput
{
    float4 Color : SV_TARGET;
};
float4 SolidColor : register(c0) = float4(1.0f, 1.0f, 1.0f, 1.0f);

//=============== 基本像素着色器函数
PixelShaderOutput PixelShaderFunction()
{
    PixelShaderOutput output;

    // 设置像素颜色为 SolidColor 定义的颜色
    output.Color = SolidColor;

    return output;
}
  • 编译
    然后使用效果编译工具fxc.exe编译这个文件
    ./fxc /T ps_3_0 /E PixelShaderFunction /Fo TextEffect2.ps wpfSolidColor.fx
    注意,wpf支持的directx版本比较老,这里只能用ps_3_0ps_2_0
    https://learn.microsoft.com/zh-cn/windows/win32/direct3dtools/dx-graphics-tools-fxc-syntax
    之后把TextEffect2.ps拷贝到项目,把生成方式改为资源
    在添加一个效果类

    namespace 你的命名空间
    {
    public class SolidShader:ShaderEffect
    {
    public static readonly DependencyProperty SolidColorProperty = DependencyProperty.Register("SolidColor", typeof(Color), typeof(SolidShader), new UIPropertyMetadata(Color.FromArgb(255, 0, 0, 0), PixelShaderConstantCallback(1)));
    public SolidShader()
    {
    PixelShader pixelShader = new PixelShader();
    pixelShader.UriSource = new Uri("pack://application:,,,/程序集命名空间;component/路径/TextEffect2.ps", UriKind.Absolute);
    this.PixelShader = pixelShader;

              this.UpdateShaderValue(SolidColorProperty);
          }
          public Color SolidColor
          {
              get
              {
                  return ((Color)(this.GetValue(SolidColorProperty)));
              }
              set
              {
                  this.SetValue(SolidColorProperty, value);
              }
          }
      }
    

    }

最后看到像素着色器正常运行

总结

  • 自定义
    着色器类型很多,3ds max中能自定义完整的渲染管线,包括顶点着色器和像素着色器。但是wpf只支持像素着色器的自定义。
  • 着色器编译入口
    使用fxc.exe我们可以自及指定入口函数,但是使用Shazzam Shader Editor 看起来已经在代码中固定了入口函数。
    Shazzam Shader Editor使用Shazzam Shader Editor 的好处是编译和预览方便
  • 版本
    Direct已经更新到11了,但wpf只支持Direct9
相关推荐
mrchip15 小时前
Simple WPF: WPF 实现按钮的长按,短按功能
c#·wpf·.net core
mrchip1 天前
Simple WPF: WPF 自定义按钮外形
c#·wpf
martian6651 天前
学懂C#编程:WPF应用开发系列——WPF之ComboBox控件的详细用法
开发语言·c#·wpf·控件·combobox
K哥爬虫2 天前
【0基础学爬虫】爬虫框架之 feapder 的使用
爬虫·wpf
云草桑2 天前
WPF UI 界面布局 魔术棒 文字笔记识别 技能提升 布局功能扩展与自定义 继承Panel的对象,测量与排列 系列七
ui·wpf·设计·布局·版式设计
罗迪尼亚的熔岩2 天前
使用附加属性 实现wpf中的passwordBox 的明文/密文密码切换
wpf·状态模式
小海聊工控上位机3 天前
WPF资源的使用
c#·wpf
无熵~3 天前
C#/WPF 自制白板工具
开发语言·c#·wpf
mingupup3 天前
WPF在.NET9中的重大更新:Windows 11 主题
windows·.net·wpf
小海聊工控上位机3 天前
WPF自定义模板--TreeView 实现菜单连接线
wpf