65.9K
CodeProject 正在变化。 阅读更多。
Home

创建 Silverlight 中的反射着色器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (12投票s)

2009年5月25日

CPOL

3分钟阅读

viewsIcon

35971

downloadIcon

292

关于使用 Silverlight 3 新像素着色器功能创建反射着色器的示例代码。

引言

在 Silverlight 中创建像素着色器很容易。它基本上是类似于 C# 的代码。用于创建着色器的语言称为 HLSL - 高级着色器语言。 HLSL 在电子游戏中被广泛使用,以创建酷炫的图形。 :) 目前 Silverlight 不允许您定义顶点着色器,您只能使用像素着色器。

请阅读我的博客:Cellbi 软件博客

查看反射着色器的工作原理: Silverlight 反射着色器效果

创建新像素着色器的步骤

  1. 创建一个新的文本文件,扩展名为“fx”,并将您的 HLSL 代码放在那里。
  2. 然后编译(不是使用 Visual Studio,而是使用 DirectX SDK 中提供的特殊效果编译器工具 - 您可以从 Microsoft 网站下载此工具)您的“fx”文件以获取编译后的像素着色器。 编译后的像素着色器被放置在扩展名为“ps”的二进制文件中。
  3. 确保将此“ps”文件包含在您的项目中,并将其编译类型设置为“资源”。
  4. 最后,创建一个新的“*.cs”文件并将 C# 着色器代码放在那里。

Fx 文件

效果文件应包含 HLSL 指令以便编译。 如果您不熟悉 HLSL,请在此处阅读 HLSL 参考:HLSL 参考 应该为您提供有关语言语法、可用数据类型、运算符和函数的信息。

以下是最简单的“fx”文件的外观

sampler2D input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR
{
  return tex2D(input, uv);
}

这行:“sampler2D input : register(s0);”定义了 sampler2D 类型的“input”变量。 此指令“register(s0)”定义了输入变量的数据来自“s0”寄存器。 接下来定义 main 函数 - 它的语法类似于 C,除了“TEXTCOORD”和“COLOR” - 这些是效果编译器和 GPU 使用的 HLSL 语义。 TEXTCOORD 表示“uv”参数包含纹理坐标,其值范围可以从 0 到 1。由于“uv”变量具有 float2 数据类型,因此可以访问其“u”和“v”组件,例如“uv.u”、“uv.v”,或者您可以使用“uv.x”、“uv.y”。 COLOR 语义表示 main 函数返回颜色数据。 在 main 函数主体内使用的“text2D”是 HLSL 函数,它从给定的采样器和纹理坐标返回颜色数据。

我们将为我们的反射着色器定义 Reflect 函数。 见下文

float4 Reflect(float2 uv : TEXCOORD) : COLOR
{
  float edge = 0.5;
  if (uv.y > edge)
  {
    uv.y = edge - (uv.y - edge);
    return tex2D(input, uv) * uv.y;
  }
  return tex2D(input, uv);
}

代码真的很简单,如果 uv.y > 0.5,我们反射 uv 坐标并返回 color 数据,否则我们使用原始纹理坐标返回 color 数据。 所以现在我们只需要从我们的 main 调用 Reflect 函数

float4 main(float2 uv : TEXCOORD) : COLOR
{
  return Reflect(uv);
}

要编译 fx 代码,您需要运行以下命令行

fxc /T ps_2_0 /E main /Fo "Reflection.ps" "Reflection.fx"

有关更多信息,请参阅 Fxc 工具

您可以为您的项目定义预构建操作

"fxc" /T ps_2_0 /E main /Fo "$(ProjectDir)Reflection.ps" "$(ProjectDir)Reflection.fx"

fxc 工具将创建“Reflection.ps”二进制文件 - 将其包含在您的项目中并将编译类型设置为资源。

C# 着色器文件

创建一个新的 C# 文件,并粘贴以下代码

using System;
using System.Windows.Media.Effects;
using System.Windows;

namespace ReflectionShader
{
  public class ReflectionShader : ShaderEffect
  {
    public ReflectionShader()
    {
      Uri u = new Uri(@"ReflectionShader;component/Reflection.ps", UriKind.Relative);
      PixelShader = new PixelShader() { UriSource = u };
    }

    public static readonly DependencyProperty ElementHeightProperty =
            DependencyProperty.Register("ElementHeight",
            typeof(double), typeof(ReflectionShader),
            new PropertyMetadata(100.0, OnElementHeightChanged));

    static void OnElementHeightChanged(DependencyObject d, 
      DependencyPropertyChangedEventArgs e)
    {
      (d as ReflectionShader).OnElementHeightChanged((double)e.OldValue, 
						(double)e.NewValue);
    }

    protected virtual void OnElementHeightChanged(double oldValue, double newValue)
    {
      PaddingBottom = newValue;
    }

    public double ElementHeight
    {
      get { return (double)base.GetValue(ElementHeightProperty); }
      set { base.SetValue(ElementHeightProperty, value); }
    }
  }
}

查看 ReflectionShader 构造函数中的代码 - 它设置了从 ShaderEffect 类继承的 PixelShader 属性。 "ReflectionShader;component/Reflection.ps" - 此 string 设置了我们“ps”文件的相对 URL。 由于反射着色器需要在 UI 元素下方留出一些空间,我们使用 PaddingBottom 属性在 OnElementHeightChanged 方法内。

如何使用像素着色器

这真的很简单。 这是 XAML 代码

<Button x:Name="btnReflected" Width="200" Height="70">
  <TextBlock FontWeight="Bold" FontSize="25" Text="Reflection" />
  <Button.Effect>
    <local:ReflectionShader ElementHeight="70">
    </local:ReflectionShader>
  </Button.Effect>
</Button>

就是这样。

历史

  • 2009年5月25日:初始发布
© . All rights reserved.