彩色光圈shader完全剖析

http://blog.csdn.net/stalendp/article/details/40690185

Shader "shadertoy/TotalNoob" {  //https://www.shadertoy.com/view/XdlSDs
	Properties{
		iMouse ("Mouse Pos", Vector) = (100,100,0,0)
		iChannel0("iChannel0", 2D) = "white" {}  
		iChannelResolution0 ("iChannelResolution0", Vector) = (100,100,0,0)
	}
	  
	CGINCLUDE    
	 	#include "UnityCG.cginc"   
  		#pragma target 3.0      
  		#pragma glsl
 
  		#define vec2 float2
  		#define vec3 float3
  		#define vec4 float4
  		#define mat2 float2x2
  		#define iGlobalTime _Time.y
//  		#define mod fmod  // mod = sign*fmod
  		#define mix lerp
  		#define atan atan2
  		#define fract frac 
  		#define texture2D tex2D
  		// 屏幕的尺寸
  		#define iResolution _ScreenParams
  		// 屏幕中的座標,以pixel爲單位
  		#define gl_FragCoord ((_iParam.srcPos.xy/_iParam.srcPos.w)*_ScreenParams.xy) 
  		
  		#define PI2 6.28318530718
  		#define pi 3.14159265358979
  		#define halfpi (pi * 0.5)
  		#define oneoverpi (1.0 / pi)
  		
  		fixed4 iMouse;
  		sampler2D iChannel0;
  		fixed4 iChannelResolution0;
  		
        struct v2f {    
            float4 pos : SV_POSITION;    
            float4 srcPos : TEXCOORD0;   
        };              
        
       //   precision highp float;
        v2f vert(appdata_base v){  
        	v2f o;
        	o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
            o.srcPos = ComputeScreenPos(o.pos);  
            return o;    
        }  
        
        vec4 main(v2f _iParam);
        
        fixed4 frag(v2f _iParam) : COLOR0 {  
			return main(_iParam);
        }  
        
		vec4 main(v2f _iParam) {
		   	vec2 p = (2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;
		    float tau = 3.1415926535*2.0;
		    float a = atan(p.x,p.y);
		    float r = length(p)*0.75;
		    vec2 uv = vec2(a/tau,r);
			
			//get the color
			float xCol = (uv.x - (iGlobalTime / 3.0)) * 3.0;
			xCol = sign(xCol)*fmod(xCol, 3.0);
			vec3 horColour = vec3(0.25, 0.25, 0.25);
			
			if (xCol < 1.0) {
				horColour.r += 1.0 - xCol;
				horColour.g += xCol;
			} else if (xCol < 2.0) {
				xCol -= 1.0;
				horColour.g += 1.0 - xCol;
				horColour.b += xCol;
			} else {
				xCol -= 2.0;
				horColour.b += 1.0 - xCol;
				horColour.r += xCol;
			}
 
			// draw color beam
			uv = (2.0 * uv) - 1.0;
			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));
			vec3 horBeam = vec3(beamWidth,beamWidth,beamWidth);
			vec4 gl_FragColor = vec4((( horBeam)* horColour ), 1.0);
			
			return gl_FragColor;
		}
 
    ENDCG    
    SubShader {    
        Pass {    
            CGPROGRAM    
            #pragma vertex vert    
            #pragma fragment frag    
            #pragma fragmentoption ARB_precision_hint_fastest     
            ENDCG    
        }    
    }     
    FallBack Off    
}

以上是完整的代碼,下面是每句代碼的解析:

對於shadertoy來說,他是對於屏幕像素來說的,我們如果想設置爲頂點或者片元shader,我們其實不需要vec2 p = (2.0*gl_FragCoord.xy-iResolution.xy)/iResolution.y;這行代碼
我們只需要在frag函數中加入o.uv = TRANSFORM_TEX(v.uv, _MainTex);,對於座標來說,是以左下角爲原點,右上角爲(1,1),因此我們需要o.uv = 2 * o.uv - 1; 將原點調整到中心點處。
主要對於main函數進行主要的解釋

		    float tau = 3.1415926535*2.0; //tau是2pi
		    float a = atan(p.x,p.y);//值域是(-pi,pi),也就是整個360°
		    float r = length(p)*0.75;//距離原點的長度
		    vec2 uv = vec2(a/tau,r);//對於uv.x的值域(-1/2,1/2)	
			//get the color
			float xCol = (uv.x - (iGlobalTime / 3.0)) * 3.0;
			xCol = sign(xCol)*fmod(xCol, 3.0);//xCol的值域是(0,3)(上一篇有講爲啥是(0,3))
			vec3 horColour = vec3(0.25, 0.25, 0.25);
			//將xCol分爲3份
			if (xCol < 1.0) {
				horColour.r += 1.0 - xCol;
				horColour.g += xCol;
			} else if (xCol < 2.0) {
				xCol -= 1.0;
				horColour.g += 1.0 - xCol;
				horColour.b += xCol;
			} else {
				xCol -= 2.0;
				horColour.b += 1.0 - xCol;
				horColour.r += xCol;
			}
 
			// draw color beam
			uv = (2.0 * uv) - 1.0;//這句是畫圓的關鍵句 如果我們將uv.y當作顏色輸出,那麼如果uv是負的,那麼就是黑色,因此對於uv.y<1/2的時候,圖1表示的就是在uv.y小於0.5時,那麼就顯示爲黑色,大於0.5時顯示爲其他顏色。
			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));

//這句代碼可以分爲四個部分
//1、floor(5.0 + 10.0*cos(iGlobalTime) floor()函數表示向下取整,也就是要小於或者等於x的整數,圖2可以看出其值域(-5,14),因此有cos函數,因此是一個循環函數。
//2、f(x)=clamp(floor(5.0 + 10.0*cos(iGlobalTime)), 0.0, 10.0) clamp(x,a,b)函數,當x<a時,x=a,當x>b時,x=b,在ab之間的時候,就取x的值,這樣我們可以看出,是將這句代碼的值域限制在(0,10)之間,且其值只能爲整數,圖3表示出其圖像。
//3、cos(uv.x*10.0*tau*0.15*f(x)) 將cos函數簡化爲cos(3pi*uv.x*f(x))
當f(x)=1時,cos函數的週期爲2PI/3
當f(x)=2時,cos函數的週期爲2PI/30

至於後面的abs(1/30*uv.y)這個數值
我們可以看一下1/30x的圖形圖5  我們已知的是小於當uv.y<1/2時,uv小於0,此時是黑色,因此我們只看uv.y>1/2的部分,在uv.y增大的過程中,1/30x的值逐漸趨向於0,因此圖6可以表示一個圓環,將1/30x加以絕對值則左右兩邊都有圓環。

因此對於每個角度對應的顏色是不一樣的,
圖4表示圖像循環,當我們將f(x)=1時,我們可以發現現在是


			vec3 horBeam = vec3(beamWidth,beamWidth,beamWidth);
			vec4 gl_FragColor = vec4((( horBeam)* horColour ), 1.0);
			
			return gl_FragColor;

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章