cocos2d-x 强大的shader系列:【OpenGL】Shader实例分析一-Wave

转发请保持地址:http://www.jb51.cc/article/p-bzdgsshf-bap.html

这篇文章主要分析一个Shader,从而感受shader的魅力,并学习相关shader的函数用法

先看Shader运行的效果(随着时间移动的波浪,具体效果请参考https://www.shadertoy.com/view/4dsGzH):

下面是代码

  1. Shader"shadertoy/Waves"{//seehttps://www.shadertoy.com/view/4dsGzH
  2. CGINCLUDE
  3. #include"UnityCG.cginc"
  4. #pragmatarget3.0
  5. structvertOut{
  6. float4pos:SV_POSITION;
  7. float4srcPos;
  8. };
  9. vertOutvert(appdata_basev){
  10. vertOuto;
  11. o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
  12. o.srcPos=ComputeScreenPos(o.pos);
  13. returno;
  14. }
  15. fixed4frag(vertOuti):COLOR0{
  16. fixed3COLOR1=fixed3(0.0,0.0,0.3);
  17. fixed3COLOR2=fixed3(0.5,0.0);
  18. floatBLOCK_WIDTH=0.03;
  19. float2uv=(i.srcPos.xy/i.srcPos.w);
  20. //TocreatetheBGpattern
  21. fixed3final_color=fixed3(1.0);
  22. fixed3bg_color=fixed3(0.0);
  23. fixed3wave_color=fixed3(0.0);
  24. floatc1=fmod(uv.x,2.0*BLOCK_WIDTH);
  25. c1=step(BLOCK_WIDTH,c1);
  26. floatc2=fmod(uv.y,108); color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> c2=step(BLOCK_WIDTH,c2);
  27. bg_color=lerp(uv.x*COLOR1,uv.y*COLOR2,c1*c2);
  28. //TOcreatethewaves
  29. floatwave_width=0.01;
  30. uv=-1.0+2.0*uv;
  31. uv.y+=0.1;
  32. for(floati=0.0;i<10.0;i++){
  33. uv.y+=(0.07*sin(uv.x+i/7.0+_Time.y));
  34. wave_width=abs(1.0/(150.0*uv.y));
  35. wave_color+=fixed3(wave_width*1.9,wave_width,wave_width*1.5);
  36. }
  37. final_color=bg_color+wave_color;
  38. returnfixed4(final_color,1.0);
  39. ENDCG
  40. SubShader{
  41. Pass{
  42. CGPROGRAM
  43. #pragmavertexvert
  44. #pragmafragmentfrag
  45. #pragmafragmentoptionARB_precision_hint_fastest
  46. FallBackOff
  47. }

下面进行分析:

1.ComputeScreenPos的解析:

用于把三维的坐标转化为屏幕上的点。有两种方式,请参考官方例子

ComputeScreenPos在UnityCG.cginc文件中定义如下:

    //Projectedscreenpositionhelpers
  1. #defineV2F_SCREEN_TYPEfloat4
  2. inlinefloat4ComputeScreenPos(float4pos){
  3. float4o=pos*0.5f;
  4. #ifdefined(UNITY_HALF_TEXEL_OFFSET)
  5. o.xy=float2(o.x,o.y*_ProjectionParams.x)+o.w*_ScreenParams.zw;
  6. #else
  7. arams.x)+o.w;
  8. #endif
  9. #ifdefined(SHADER_API_FLASH)
  10. o.xy*=unity_NPOTScale.xy;
  11. o.zw=pos.zw;
  12. 原理解析(待续)

    2. 背景的绘制

    2.1)fmod用于求余数,比如fmod(1.5,1.0) 返回0.5;

    2.2) step用于大小的比较,step(a,x) : 0 if x<a; 1 if x>=a; 比如: step(1,1.2),返回1; step(1,0.8) 返回0;

    2.3) 结合fmod和step可以得到一个虚线的效果。 比如要得到虚线段长度为1的代码如下:

    c1 = fmod(x,2*width); c1=step(width,c1); //其中width为1

    那么如果x的范围是[0,1),c1的值为0;范围为[1,2),c1的值为1;2为一个周期;

    那么fmod起到了制作周期的作用,step计算周期内的0和1;

    2.4)把2.3中的知识运用到2维,就可以计算出方块。

    lerp函数用法lerp(a,b,f), f为百分数(取值范围[0,1]);如果f为0,则lerp返回a,f为1,则返回b。f为0到1之间,就返回a到b之间的值。

    代码中的 lerp(uv.x*COLOR1,c1*c2); 其中c1和c2的取值不是为1,就是为0,所以就可以变成网格的情况。 背景绘制如下:

    3. 波纹的绘制

    3.1 ) 坐标的转化

    uv = -1.0 + 2.0*uv; // 把uv的x和y轴压缩到原来的0.5倍后,向右上角移动1个单位。

    3.2 ) 画一条直线:

    由于上面把y轴移动到屏幕的中心,所以屏幕的上半部分为正的,下半部分为负的,代码如下:

    wave_width=abs(1.0/(50.0*uv.y));

  13. wave_color=fixed3(wave_width*1.9,wave_width*1.5);

其中50.0是用来控制线的宽度的(数值越大,线越细),效果如下:

3.3)把直线变为曲线,并使其动起来:

uv.y+=(0.07*sin(uv.x*10+_Time.y));

  • wave_width=abs(1.0/(50.0*uv.y));
  • wave_color=fixed3(wave_width*1.9,255)">效果如下:

    3.4)多画几条曲线,形成波浪:

    for(floati=0.0;i<10.0;i++){

  • uv.y+=(0.07*sin(uv.x+i/7.0+_Time.y));
  • wave_width=abs(1.0/(150.0*uv.y));
  • wave_color+=fixed3(wave_width*1.9,wave_width*1.5);
  • 最终效果请见文章开头。

    其实写shader,很多时候都是要通过不断地效果叠加并调试来达到效果

  • 相关文章

        本文实践自 RayWenderlich、Ali Hafizji 的文章《...
    Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
    第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
        Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
    1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
       Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...