1. 程式人生 > >【OpenGL】Shader實例分析(七)- 雪花飄落效果

【OpenGL】Shader實例分析(七)- 雪花飄落效果

mouse llb cto 接下來 pix lan details effect art

轉發請保持地址:http://blog.csdn.net/stalendp/article/details/40624603

研究了一個雪花飄落效果。感覺挺不錯的。分享給大家,效果例如以下:

技術分享

代碼例如以下:

Shader "shadertoy/Flakes" {  // https://www.shadertoy.com/view/4d2Xzc
	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
  		#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 = gl_FragCoord.xy/iResolution.xy;
		    vec3  col = vec3(0,0,0);
		    float dd = 150;
		    for( int i=0; i<dd; i++ )
		    {
		        float an = 6.2831*float(i)/dd;
		        vec2  of = vec2( cos(an), sin(an) ) * (1.0+0.6*cos(7.0*an+iGlobalTime)) + vec2( 0.0, iGlobalTime );
		        col = max( col, texture2D( iChannel0, p + 20*of/iResolution.xy ).xyz );
		        col = max( col, texture2D( iChannel0, p +  5.0*of/iResolution.xy ).xyz );
		    }
		    col = pow( col, vec3(1.0,2.0,3.0) ) * pow( 4.0*p.y*(1.0-p.y), 0.2);
		    
			return vec4( col, 1.0 );
		}

    ENDCG    
  
    SubShader {    
        Pass {    
            CGPROGRAM    
  
            #pragma vertex vert    
            #pragma fragment frag    
            #pragma fragmentoption ARB_precision_hint_fastest     
  
            ENDCG    
        }    
    }     
    FallBack Off    
}

代碼分析:


1)七邊形雪花的繪制算法

詳細代碼例如以下:

float dd = 150;
for( int i=0; i<dd; i++ )
{
	float an = 6.2831*float(i)/dd;
	vec2  of = vec2( cos(an), sin(an) ) * (1.0+0.6*cos(7.0*an+iGlobalTime)) + vec2( 0.0, iGlobalTime );
	col = max( col, texture2D( iChannel0, p + 20*of/iResolution.xy ).xyz );
	col = max( col, texture2D( iChannel0, p +  5.0*of/iResolution.xy ).xyz );
}
在理解這段代碼前。先理解怎麽畫一個圈,代碼例如以下:

float dd = 30;
for( int i=0; i<dd; i++ )
{
	float an = 6.2831*float(i)/dd;
	vec2  of = vec2( cos(an), sin(an) );
	col = max( col, texture2D( iChannel0, p + 20*of/iResolution.xy ).xyz );
}
然後再準備一張貼圖,圖片中間是一個白色像素,周圍都是黑色

技術分享

效果例如以下:

技術分享

這段代碼處於fragment shader中,意味著屏幕上每個點都會進行上述的算法。詳細例如以下,遍歷貼圖中該點周圍的點(上面的代碼中為距離該點為20單位的圓上的點)。把周圍點中最亮的作為該點的顏色。 上面的貼圖有點特殊。僅僅有一個點是白色,其余點都是黑色的。那麽僅僅有距離該點正好為20單位的點才會變成亮色,其余的點都是黑色。如上圖的結果。

一句話總結上面算法的效果:貼圖中的每個“相對亮點”的周圍都會產生“相對亮的特定圖形”,圖形的亮度取決於該點的亮度。越亮越明顯效果能夠參考文末的圖片。

接下來理解這段代碼:

float dd = 150;
for( int i=0; i<dd; i++ )
{
	float an = 6.2831*float(i)/dd;
	vec2  of = vec2( cos(an), sin(an) ) * (1.0+0.7*cos(7.0*an));
	col = max( col, texture2D( iChannel0, p + 20*of/iResolution.xy ).xyz );
//	col = max( col, texture2D( iChannel0, p +  5.0*of/iResolution.xy ).xyz );
}
輸出結果例如以下:

技術分享

a) 1.0+0.7*cos(7.0*an)的圖像例如以下:

技術分享

b)算法中 of 向量的路徑為:

技術分享

結果就非常清晰了;事實上這裏算法和《【OpenGL】Shader實例分析(二)- Heart》中繪制心形的算法非常類似。

最後加上時間就能夠實現動畫了:

vec2  of = vec2( cos(an), sin(an) ) * (1.0+0.6*cos(7.0*an+iGlobalTime)) + vec2( 0.0, iGlobalTime );
第一個iGlobalTime。用來控制雪花的旋轉。第二個iGlobalTime使雪花下落。


2)後期顏色等處理

這裏能夠理解為一種postEffect處理。詳細是例如以下的代碼貢獻的效果:

col = pow( col, vec3(1.0,2.0,3.0) ) * pow( 4.0*p.y*(1.0-p.y), 0.2);

a) pow(col, vec3(1.0, 2.0, 3.0)) 這句話使得顏色變成暖色調。

col值的範圍為[0,1],對小數繼續pow運算,次數越高,該值越小。

比方:0.5的1次方是0.5。 2次方為0.25。 3次方為0.125等。所以這句話的作用非常明顯:red成份不變,green變小一些,blue變的更小。達到的效果。使得總體顏色會偏向暖色調。

b)pow(4.0*p.y*(1.0-p.y), 0.2) 使得屏幕上下兩邊變暗。


最後附上shader中用到的貼圖:

技術分享

經過程序處理後,得到例如以下:

技術分享

文章完成,歡迎討論。

【OpenGL】Shader實例分析(七)- 雪花飄落效果