在上文中,会发现,调用3维柏林实现海水的波动效果,实在是难为CPU了,在这里,我们用着色器Cg语言来把相关计算过程移到GPU,看下效果。
先说下,原来纹理我们拿来只限于给模型着色,而在现代GPGPU中,有个比较重要的概念就是,纹理就是数组,想想也对,纹理原来我们放的是RGBA值,那么如果我们用来存取一些别的数据,而不是RGBA,在着色器中把纹理里数据取出来,而不是用于给模型着色,那能实现什么样的功能了。
本文中主要功能都在着色器中,故下面先给出着色器代码,包含原来的noise计算,还有动画与着色,可以对比上文F#代码来看。
2
3 #define ONE 0.00390625
4 #define ONEHALF 0.001953125
5
6 float fade(float t) {
7 //return t*t*(3.0-2.0*t); // Old fade
8 return t*t*t*(t*(t*6.0-15.0)+10.0);
9 // Improved fade
10 }
11
12 float noise(float3 P,sampler2D permTexture)
13 {
14 float3 Pi = ONE*floor(P)+ONEHALF;
15 float3 Pf = P-floor(P);
16 // Noise contributions from (x=0, y=0), z=0 and z=1
17 float perm00 = tex2D(permTexture, Pi.xy).a ;
18 float3 grad000 = tex2D(permTexture, float2(perm00, Pi.z)).rgb * 4.0 - 1.0;
19 float n000 = dot(grad000, Pf);
20 float3 grad001 = tex2D(permTexture, float2(perm00, Pi.z + ONE)).rgb * 4.0 - 1.0;
21 float n001 = dot(grad001, Pf - float3(0.0, 0.0, 1.0));
22 // Noise contributions from (x=0, y=1), z=0 and z=1
23 float perm01 = tex2D(permTexture, Pi.xy + float2(0.0, ONE)).a ;
24 float3 grad010 = tex2D(permTexture, float2(perm01, Pi.z)).rgb * 4.0 - 1.0;
25 float n010 = dot(grad010, Pf - float3(0.0, 1.0, 0.0));
26 float3 grad011 = tex2D(permTexture, float2(perm01, Pi.z + ONE)).rgb * 4.0 - 1.0;
27 float n011 = dot(grad011, Pf - float3(0.0, 1.0, 1.0));
28 // Noise contributions from (x=1, y=0), z=0 and z=1
29 float perm10 = tex2D(permTexture, Pi.xy + float2(ONE, 0.0)).a ;
30 float3 grad100 = tex2D(permTexture, float2(perm10, Pi.z)).rgb * 4.0 - 1.0;
31 float n100 = dot(grad100, Pf - float3(1.0, 0.0, 0.0));
32 float3 grad101 = tex2D(permTexture, float2(perm10, Pi.z + ONE)).rgb * 4.0 - 1.0;
33 float n101 = dot(grad101, Pf - float3(1.0, 0.0, 1.0));
34 // Noise contributions from (x=1, y=1), z=0 and z=1
35 float perm11 = tex2D(permTexture, Pi.xy + float2(ONE, ONE)).a ;
36 float3 grad110 = tex2D(permTexture, float2(perm11, Pi.z)).rgb * 4.0 - 1.0;
37 float n110 = dot(grad110, Pf - float3(1.0, 1.0, 0.0));
38 float3 grad111 = tex2D(permTexture, float2(perm11, Pi.z + ONE)).rgb * 4.0 - 1.0;
39 float n111 = dot(grad111, Pf - float3(1.0, 1.0, 1.0));
40 // Blend contributions along x
41 float4 n_x = lerp(float4(n000, n001, n010, n011), float4(n100, n101, n110, n111), fade(Pf.x));
42 // Blend contributions along y
43 float2 n_xy = lerp(n_x.xy, n_x.zw, fade(Pf.y));
44 // Blend contributions along z
45 float n_xyz = lerp(n_xy.x, n_xy.y, fade(Pf.z));
46 return n_xyz;
47 }
48
49
50 float turbulence(int octaves, float3 P, float lacunarity, float gain,sampler2D permTexture)
51 {
52 float sum =
LongListSelector是一个加强版的列表控件,它可以实现分组的列表,如系统人脉列表的交互效果就可以利用LongListSelector控件去实现,同时LongListSelector也一样可以实现和ListBox一样的列表效果。在使用LongListSelector控件的时候可以使用IsGroupingEnabled属性来控制你要实现的是分组的效果,还是非分组的列表效果。
下面我们用LongListSelector来实现一个非分组的列表效果,同时还要实现的功能是列表下拉自动刷新的效果。LongListSelector实现非分组列表效果和ListBox控件是类似的,通过对ItemTemplate模板进行设置,然后绑定集合的相关属性就可以了。在前面的章节由介绍过一个使用ListBox控件判断列表滚动到底的例子,实现的原理是通过可视化树获取ListBox的ScrollViewer控件,然后根据ScrollViewer控件的垂直位移属性来判断ListBox控件什么时候滚动到底。但是LongListSelector内部没有采用ScrollViewer控件,所以我们不能采用这种方式来实现下拉自动刷新的功能。那么我们这个例子是通过LongListSelector控件的ItemRealized事件去控制自动刷新的逻辑,因为LongListSelector控件是对数据进行虚拟化处理的,当列表向下滚动的时候下面的数据就会不断地被实例化,当数据实例化的时候就会触发ItemRealized事件,所以我只需要监控到当列表最后一个数据实例化的时候就可以出发数据刷新的逻辑就可以了。代码如下所示:
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" FontSize="30"></TextBlock>
<TextBlock Text="{Binding LastName}" FontSize="30" Margin="30,0,0,0"></TextBlock>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
{
// 绑定的数据集合
public ObservableCollection<Item> Items { get; set; }
// 数据加载的标识
public bool IsLoading = false;
// 线程锁的对象
private object o = new object();
// 构造函数
public MainPage()
{
InitializeComponent();
// 列表初始化加载100个数据项
Items = new ObservableCollection<Item>();
for (int i = 0; i < 100; i++)
{
Items.Add(new Item { FirstName = "Li" + i, LastName = "Lei" + i });
}
this.DataContext = this;
}
// 页面加载完成,订阅列表的ItemRealized事件
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
lls.ItemRealized += lls_ItemRealized;
}
// ItemRealized事件处理程序,在这里判断刷新的时机
void lls_ItemRealized(object sender, ItemRealizationEventArgs e)
{
// 因为该事件会被多个线程进入,所以添加线程锁,控制下面的代码只能单个线程去执行
lock (o)
{
if (!IsLoading)
{
if (e.ItemKind == LongListSelectorItemKind.Item)
{
if ((e.Container.Content as Item).Equals(lls.ItemsSource[lls.ItemsSource.Count - 1]))
{
// 设置IsLoading为true,在加载数据的过程中,禁止多次进入
IsLoading = true;
// 显示系统托盘的进度条
Microsoft.Phone.Shell.ProgressIndicator progressIndicator = new Microsoft.Phone.Shell.ProgressIndicator();
Microsoft.Phone.Shell.SystemTray.ProgressIndicator = progressIndicator;
progressIndicator.Text = "加载中...";
progressIndicator.IsIndeterminate = true;
progressIndicator.IsVisible = true;
// 模拟后台耗时任务拉取数据的场景
Task.Factory.StartNew(async () =>
{
awai
没有评论:
发表评论