在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
相关推荐
wniuniu_25 分钟前
ceph基础知识
ceph·wpf
DataIntel1 小时前
WPF 操作之Dispatcher--- 只在多线程更新 UI 时使用。
wpf
Macbethad1 小时前
WPF工业设备远程控制程序技术方案
分布式·wpf
Macbethad10 小时前
工业设备数据记录程序技术方案
wpf·信息与通信
zzyzxb1 天前
WPF 中隧道事件和冒泡事件
wpf
闲人编程1 天前
API限流、鉴权与监控
分布式·python·wpf·限流·集群·令牌·codecapsule
TA远方1 天前
【WPF】桌面程序使用谷歌浏览器内核CefSharp控件详解
wpf·浏览器·chromium·控件·cefsharp·cefsharp.wpf
Macbethad2 天前
工业设备数据采集主站程序技术方案
wpf
关关长语2 天前
HandyControl 3.5.x 版本 ListViewItem不显示问题
windows·wpf
Macbethad2 天前
工业设备维护程序技术方案
wpf