zoukankan      html  css  js  c++  java
  • 【OpenGL】Shader实例分析(七)- 雪花飘落效果

    转发请保持地址: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中用到的贴图:


    经过程序处理后,得到例如以下:


    文章完成,欢迎讨论。

  • 相关阅读:
    ArcGIS SilverLight/WPF API 2.0版本已正式发布,新特性
    ArcGIS Server Flex API 自定义缩放控件的级数[代码]
    First
    HTML和JavaScript代码分离、平稳退化(1)
    cocos2dx 仿射变换
    java数组创建
    第一次看CCControl
    从零开始のcocos2dx生活(四)ActionManager
    从零开始のcocos2dx生活(二)Node
    从零开始のcocos2dx生活(三)Scheduler
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/6842649.html
Copyright © 2011-2022 走看看