打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
【OpenGL】Shader实例分析(八)

转发请保持地址:http://blog.csdn.net/stalendp/article/details/40690185

研究了一个彩色光圈效果,感觉挺不错的,分享给大家,效果如下:


代码如下:

  1. Shader "shadertoy/TotalNoob" {  //https://www.shadertoy.com/view/XdlSDs  
  2.     Properties{  
  3.         iMouse ("Mouse Pos", Vector) = (100,100,0,0)  
  4.         iChannel0("iChannel0", 2D) = "white" {}    
  5.         iChannelResolution0 ("iChannelResolution0", Vector) = (100,100,0,0)  
  6.     }  
  7.         
  8.     CGINCLUDE      
  9.         #include "UnityCG.cginc"     
  10.         #pragma target 3.0        
  11.         #pragma glsl  
  12.   
  13.         #define vec2 float2  
  14.         #define vec3 float3  
  15.         #define vec4 float4  
  16.         #define mat2 float2x2  
  17.         #define iGlobalTime _Time.y  
  18. //          #define mod fmod  // mod = sign*fmod  
  19.         #define mix lerp  
  20.         #define atan atan2  
  21.         #define fract frac   
  22.         #define texture2D tex2D  
  23.         // 屏幕的尺寸  
  24.         #define iResolution _ScreenParams  
  25.         // 屏幕中的坐标,以pixel为单位  
  26.         #define gl_FragCoord ((_iParam.srcPos.xy/_iParam.srcPos.w)*_ScreenParams.xy)   
  27.           
  28.         #define PI2 6.28318530718  
  29.         #define pi 3.14159265358979  
  30.         #define halfpi (pi * 0.5)  
  31.         #define oneoverpi (1.0 / pi)  
  32.           
  33.         fixed4 iMouse;  
  34.         sampler2D iChannel0;  
  35.         fixed4 iChannelResolution0;  
  36.           
  37.         struct v2f {      
  38.             float4 pos : SV_POSITION;      
  39.             float4 srcPos : TEXCOORD0;     
  40.         };                
  41.           
  42.        //   precision highp float;  
  43.         v2f vert(appdata_base v){    
  44.             v2f o;  
  45.             o.pos = mul (UNITY_MATRIX_MVP, v.vertex);  
  46.             o.srcPos = ComputeScreenPos(o.pos);    
  47.             return o;      
  48.         }    
  49.           
  50.         vec4 main(v2f _iParam);  
  51.           
  52.         fixed4 frag(v2f _iParam) : COLOR0 {    
  53.             return main(_iParam);  
  54.         }    
  55.           
  56.         vec4 main(v2f _iParam) {  
  57.             vec2 p = (2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;  
  58.             float tau = 3.1415926535*2.0;  
  59.             float a = atan(p.x,p.y);  
  60.             float r = length(p)*0.75;  
  61.             vec2 uv = vec2(a/tau,r);  
  62.               
  63.             //get the color  
  64.             float xCol = (uv.x - (iGlobalTime / 3.0)) * 3.0;  
  65.             xCol = sign(xCol)*fmod(xCol, 3.0);  
  66.             vec3 horColour = vec3(0.25, 0.25, 0.25);  
  67.               
  68.             if (xCol < 1.0) {  
  69.                 horColour.r += 1.0 - xCol;  
  70.                 horColour.g += xCol;  
  71.             } else if (xCol < 2.0) {  
  72.                 xCol -= 1.0;  
  73.                 horColour.g += 1.0 - xCol;  
  74.                 horColour.b += xCol;  
  75.             } else {  
  76.                 xCol -= 2.0;  
  77.                 horColour.b += 1.0 - xCol;  
  78.                 horColour.r += xCol;  
  79.             }  
  80.   
  81.             // draw color beam  
  82.             uv = (2.0 * uv) - 1.0;  
  83.             float beamWidth = (0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iGlobalTime)), 0.0, 10.0))) * abs(1.0 / (30.0 * uv.y));  
  84.             vec3 horBeam = vec3(beamWidth,beamWidth,beamWidth);  
  85.             vec4 gl_FragColor = vec4((( horBeam)* horColour ), 1.0);  
  86.               
  87.             return gl_FragColor;  
  88.         }  
  89.   
  90.     ENDCG      
  91.     SubShader {      
  92.         Pass {      
  93.             CGPROGRAM      
  94.             #pragma vertex vert      
  95.             #pragma fragment frag      
  96.             #pragma fragmentoption ARB_precision_hint_fastest       
  97.             ENDCG      
  98.         }      
  99.     }       
  100.     FallBack Off      
  101. }  

代码分析

代码分两部分,颜色 * 光圈,如下图:

 * 
 = 

彩色的算法

代码如下:

  1. vec2 p = (2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;  
  2. float tau = 3.1415926535*2.0;  
  3. float a = atan(p.x,p.y);  
  4. float r = length(p)*0.75;  
  5. vec2 uv = vec2(a/tau,r);  
  6.   
  7. //get the color  
  8. float xCol = (uv.x - (iGlobalTime / 3.0)) * 3.0;  
  9. xCol = mod(xCol, 3.0);  
  10. vec3 horColour = vec3(0.25, 0.25, 0.25);  
  11.   
  12. if (xCol < 1.0) {  
  13.     horColour.r += 1.0 - xCol;  
  14.     horColour.g += xCol;  
  15. } else if (xCol < 2.0) {  
  16.     xCol -= 1.0;  
  17.     horColour.g += 1.0 - xCol;  
  18.     horColour.b += xCol;  
  19. } else {  
  20.     xCol -= 2.0;  
  21.     horColour.b += 1.0 - xCol;  
  22.     horColour.r += xCol;  
  23. }  

这段代码是写在fragment shader中的,也就是说,每个像素点的渲染都会调用这段代码。

a) vec2 p = (2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;

p表示把当前的坐标轴缩小到原来的1/2,原点移动到屏幕中间,并把x,y轴的坐标范围缩小到1左右的值(即p的y轴范围在-1到1之间,x轴的范围也在附近);

b)float a = atan(p.x, p.y);

a表示p点绕原点的角度,范围为[-π,π];所以uv.x = a/tau的范围为[-1/2, 1/2];

float xCol = (uv.x - (iGlobalTime / 3.0)) * 3.0; xCol=mod(xCol, 3)的范围为 [0,3]

c) xCol经过上面处理,其范围为[0,3]; 现在把这个范围平均分成3份,每一份做一个颜色的混合:

[0,1]:Red和Green混合;[1,2]:Green和Blue混合;[2,3]:Blue和Red混合。


光圈的算法

a)画光圈

式子:abs(1.0 / (30.0*uv.y)) 

知识:在shader中,如果color的值为负数,则认为是0,不显示该颜色。

uv变量中uv.y表示点到原点的距离,值的范围为 [0, ]

a-1) uv = (2.0 * uv) - 1.0;  先把uv缩小到原来的1/2,然后向外移动1单位。uv.y的值为[-1/2, ];由于负值color不被显示,如下图A:

a-2) 1.0/(30.0* uv.y); 缩小到原来的1/30,并做个倒数,如下图B

a-3) abs(1.0/(30.0* uv.y)); 然后做个绝对值,如下图C

=》
=》

画光圈的算法和《【OpenGL】Shader实例分析(一)-Wave》中画线的算法很类似。

b)光圈动画 

式子:(0.7+0.5*cos(uv.x*10.0*tau*0.15*clamp(floor(5.0 + 10.0*cos(iGlobalTime)), 0.0, 10.0)))

为了方便,把上面的式子分解如下:

式1:float tt = 5.0 + 10.0*cos(iGlobalTime); 
式2:float param = clamp(floor(tt), 0.0, 10.0);

式3:float beamWidth = (0.7+0.5*cos(uv.x*pi*param));

我们把beamWidth作为颜色输出;

先理解式3,如果当param为0,、1、2、3、10时,分别参考下图: 

 =》 
 =》
=》 
=》

式2的作用,把tt的值做一个包装,使其为0到10之间的整数

式1的作用,起周期作用,值域为[-5,15]; 其值如左下图所示; 又由于式2做了clamp,把大于10和小于0的值去掉,最终的动画如右下图所示:

 ====》

把光圈和颜色整合起来就看到了和文章开头的动画一样的效果了。

最后吧所有的效果整合起来,如下图:

【彩色】 => 【彩色旋转】 =》【彩色旋转+动画】 =》【彩色旋转+动画+光圈】

=》
=》
=》


本次分析到此结束,欢迎讨论。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
RenderDoc[03] 还原粒子特效shader
(Shader Library) Swirl Post Processing Filter in GLSL | Geeks3D
数字孪生系统中常用Three.js效果的实现原理
猫都能学会的Unity3D Shader入门指南(一)
【Unity Shader】2D动态云彩
openGL ES 2.0 笔记 6
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服