原文:【HLSL学习笔记】WPF Shader Effect Library算法解读之[BandedSwirl]

因工作原因,需要在Silverlight中使用Pixel Shader技术,这对于我来说可算是相当有难度了,首先我是个Java Web开发程序员,从来没正经地学过微软的开发语言和工具;其次,对于算法这种东西,向来有种天生的排斥,一看便头疼。不过项目逼到份上了,只能硬着头皮上,真不知道领导们是怎么想的。还是言归正传吧,记录记录自己的学习心得。

熟悉Silverlight的人都知道,SL中有一物名为Pixel Shader,江湖人称像素着色器。是Sl中可以单独操控像素的一门技术。SL3中集成了两个Shader,一为DropShadowEffect,二谓BlurEffect,可为用户产生投影与模糊的效果。此外,MS还为程序员开辟了自定义通道,程序员可以自行编写Shader文件,并通过C#封装,最终应用在SL中。而编写Shader文件则需要采用HLSL(高级着色器语言High-Level-Shader-Language),正如当年新手上路用文本文件编写Java的HelloWorld程序一样,Shader同样可以用文本文件编写,同样可以用命令行编译。本文是我工作中的一些琐碎的片段,主要针对的是开源的WPF Pixel Shader Effect Library项目中的Shader源代码进行研究和学习,从而不断的提高自己。

项目地址为:http://wpffx.codeplex.com/

其中提供了18个Shader:

 

图1 Shader列表

 

初学Shader,不知从何做起,前人有高质量的代码,何不直接取来,参详研习。这两天刚开始研究BandedSwirl.fx,做点记录:

有必要说的是逆向的解读别人的算法是一个非常痛苦的过程,只有通过特效展示结合算法文件自己去构建算法模型方可,至少这是我笨人所采用的笨办法:)

BandedSwirl直译的话应该叫做【带状螺旋】效果,初见时觉得挺震撼,觉得这种算法程序应该很长才是,没想到不过区区30行左右,可见Shader编程之精炼。先看看效果截图:

 再来瞅瞅源代码:

图2 带状螺旋效果图

 

 

//++++++++++++++++++++++++++++++SRC+++++++++++++++++++++++++++++
//--------------------------------------------------------------------------------------
// 全局变量,供应用程序设置,在Silverlight中动态改变这些参数便成了动画
//--------------------------------------------------------------------------------------

//定义螺旋效果的中心点,默认是(0.5,0.5),存放在常量寄存器C0里
float2 center : register(C0);
//定义螺旋效果的强度
float spiralStrength : register(C1);
//距离的阈值
float distanceThreshold : register(C2);

//定义了2D采样器,如果应用在MediaElement上的话,MediaElement的实时画面便是采样器的内容,存放在临时寄存器S0中。
sampler2D implicitInputSampler : register(S0);

//--------------------------------------------------------------------------------------
// 像素着色器
//--------------------------------------------------------------------------------------

float4 main(float2 uv : TEXCOORD) : COLOR
{
 //定义2d向由中心指向某一纹理坐标的向量
   float2 dir = uv - center;
   //求取向量的长度,l的值域为[0,√2/2]
   float l = length(dir);
   //向量除以自己的长度就是单位向量,只用于表示方向
   dir = dir/l;
   //求取向量和水平线的夹角,这里值域为[-PI/2,PI/2]
   float angle = atan2(dir.y, dir.x);
//为了进行交替的螺旋对流,避免采用类似for循环的流程控制语句,导致额外的性能耗费,需要用一个值来控制螺旋对流的循环周期,这里采用了一个名为距离阈值的参数,remainder和l的关系图为一组周期为distanceThreshold的三角波,见图3
  //值域为[0,1]
   float remainder = frac(l / distanceThreshold);
   //该参数是为了让螺旋周期内两路相反带装束过渡的更为平滑,在波形图上看就是为了让波形连续。
   float preTransitionWidth = 0.25;
   //定义一个参数,控制每个螺旋周期内的对流,每个漩涡周期内共有两路正向带状束和一路反向带装束,分别交替呈现。Fac和remainder的关系见图4
   float fac;  
   //控制对流方向的交替以及波形的连续
   if (remainder < .25)
   {
      fac = 1.0;
   }
   else if (remainder < 0.5)
   {
      fac = 1 - 8 * (remainder - preTransitionWidth);
   }
   else if (remainder < 0.75)
   {
      fac = -1.0;
   }
   else
   {
      fac = -(1 - 8 * (remainder - 0.75));
   }
   //计算基于参数【螺旋强度】的变换角度,意思就是在原来向量方向的基础上正向或者反向增大扭曲角度
   float newAng = angle + fac * spiralStrength * l;
   //按照螺旋强度计算出来的变换角度重新定义纹理坐标
   float xAmt = cos(newAng) * l;
   float yAmt = sin(newAng) * l;
     
   float2 newCoord = center + float2(xAmt, yAmt);
   //按照新的纹理坐标对原来的采样器进行纹理的渲染,得出最终的结果
   return tex2D( implicitInputSampler, newCoord );
}

//++++++++++++++++++++++++++++++SRC+++++++++++++++++++++++++++++

 

图3 remainder和L的关系图

图4 fac和remainder的关系图

 

到这里也算大致搞明白这个算法的原理了,对于我来说,算是费了九牛二虎。从中也学到不少,以前自己写HLSL的时候,总喜欢用for循环来控制流程,比如要写一个百叶窗,首先想到的就是设定百叶窗的间隔,然后用1/间隔当做循环次数,每次用HLSLTester都勉强能编译过去,但是一旦到了要编译成ps_2_0的ps文件时总会报错,意思是每个Shader只允许64条汇编指令,超出这个数量就编译不过去。想想若是把for循环转变成汇编语言,会产生多少指令啊,效率能不低吗!!!

好像ps_3_0没有这个限制,但是SL貌似只支持ps_2_0,所以还是精炼下自己的代码吧。

总结一下心得:

1、  写Shader最好用向量,少用标量

2、  诸如for、do-while这一类的循环尽量少用

 

 

【HLSL学习笔记】WPF Shader Effect Library算法解读之[BandedSwirl]的更多相关文章

  1. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...

  2. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果)          浮雕效果主要有两个参数:Amount和Wid ...

  3. V-rep学习笔记:Reflexxes Motion Library 3

    路径规划 VS 轨迹规划 轨迹规划的目的是将输入的简单任务描述变为详细的运动轨迹描述.注意轨迹和路径的区别:Trajectory refers to a time history of positio ...

  4. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  5. 机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记

    机器学习实战(Machine Learning in Action)学习笔记————06.k-均值聚类算法(kMeans)学习笔记 关键字:k-均值.kMeans.聚类.非监督学习作者:米仓山下时间: ...

  6. V-rep学习笔记:Reflexxes Motion Library 2

    VREP中的simRMLMoveToPosition函数可以将静态物体按照设定的运动规律移动到指定的目标位置/姿态.If your object is dynamically enabled, it ...

  7. 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT)

    再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Bluestein算法+分治FFT+FFT的优化+任意模数NTT) 目录 再探快速傅里叶变换(FFT)学习笔记(其三)(循环卷积的Blueste ...

  8. HMM的学习笔记1:前向算法

    HMM的学习笔记 HMM是关于时序的概率模型.描写叙述由一个隐藏的马尔科夫链随机生成不可观測的状态随机序列,再由各个状态生成不可观測的状态随机序列,再由各个状态生成一个观測而产生观測的随机过程. HM ...

  9. jvm学习笔记一(垃圾回收算法)

    一:垃圾回收机制的原因 java中,当没有对象引用指向原先分配给某个对象的内存时候,该内存就成为了垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息 ...

随机推荐

  1. 8、linux下输入子系统

    input_sync(button_dev);    /*通知接收者,一个报告发送完毕*/ 参考:http://www.51hei.com/bbs/dpj-27652-1.html  很详细说明 in ...

  2. openGL线型和线宽以及线的抗锯齿

    openGL线型和线宽以及线抗锯齿 一. 线宽 Opengl的线宽设置:glLineWidth(width); width为float类型值,在0~10.0,大于10以上按10来处理. 若开启线的反走 ...

  3. 【跟我一起学Unity3D】代码中分割图片而且载入帧序列动画

    在Cocos2dx中.对大图的处理已经封装好了一套自己的API,可是在Unity3D中貌似没有类似的API(好吧,实际上是有的,并且功能更强大),或者说我没找到. 只是这也在情理之中,毕竟Unity3 ...

  4. 2.3系列系统中不支持SimpleDateFormat作字段被序列化

    安卓问题记录:在2.3系列系统中不支持SimpleDateFormat作字段被序列化,使用时需要将SimpleDateFormat作临时变量使用.

  5. JDK8 JVM性能优化-1

    原文地址:https://blog.csdn.net/xingkongtianma01/article/details/80689928 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的 ...

  6. (一)RabbitMQ消息队列-RabbitMQ的优劣势及产生背景

    原文:(一)RabbitMQ消息队列-RabbitMQ的优劣势及产生背景 本篇并没有直接讲到技术,例如没有先写个Helloword.我想在选择了解或者学习一门技术之前先要明白为什么要现在这个技术而不是 ...

  7. iOS开发Quarz2D 九:图片加水印

    #import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutl ...

  8. jquery-12 jquery常用动画效果有哪些

    jquery-12 jquery常用动画效果有哪些 一.总结 一句话总结:jquery可以用户animate()自定义动画,也可以slide和fade系列方法来设置动画. 1.动画效果如何设置执行时间 ...

  9. HTML5 canvas 指针时钟

    <!doctype html> <html> <head></head> <body> <canvas id="> 您 ...

  10. CMakeListx.txt 编辑语法学习

    已hello.cpp为源文件,构建一个CMakeLists.txt cmake_minimum_required(VERSION 2.8) project(hello) add_executable( ...