创建 Silverlight 中的反射着色器






4.85/5 (12投票s)
关于使用 Silverlight 3 新像素着色器功能创建反射着色器的示例代码。

引言
在 Silverlight 中创建像素着色器很容易。它基本上是类似于 C# 的代码。用于创建着色器的语言称为 HLSL - 高级着色器语言。 HLSL 在电子游戏中被广泛使用,以创建酷炫的图形。 :) 目前 Silverlight 不允许您定义顶点着色器,您只能使用像素着色器。
请阅读我的博客:Cellbi 软件博客。
查看反射着色器的工作原理: Silverlight 反射着色器效果。
创建新像素着色器的步骤
- 创建一个新的文本文件,扩展名为“fx”,并将您的 HLSL 代码放在那里。
- 然后编译(不是使用 Visual Studio,而是使用 DirectX SDK 中提供的特殊效果编译器工具 - 您可以从 Microsoft 网站下载此工具)您的“fx”文件以获取编译后的像素着色器。 编译后的像素着色器被放置在扩展名为“ps”的二进制文件中。
- 确保将此“ps”文件包含在您的项目中,并将其编译类型设置为“资源”。
- 最后,创建一个新的“*.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日:初始发布