android雪花飘落效果,【OpenGL】Shader实例分析(七)- 雪花飘落效果

研究了一个雪花飘落效果。感觉挺不错的。分享给大家,效果例如以下:

e64a1ee8f5d946dbe94e4adc3d2e0aef.gif

代码例如以下:

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

{

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

{

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

{

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 );

}

然后再准备一张贴图,图片中间是一个白色像素,周围都是黑色

850836f44e0c861ef3b8e61a24d49885.png

效果例如以下:

d5d54e40440ebf55ac920b4429fad52a.png

这段代码处于fragment shader中,意味着屏幕上每个点都会进行上述的算法。详细例如以下,遍历贴图中该点周围的点(上面的代码中为距离该点为20单位的圆上的点)。把周围点中最亮的作为该点的颜色。 上面的贴图有点特殊。仅仅有一个点是白色,其余点都是黑色的。那么仅仅有距离该点正好为20单位的点才会变成亮色,其余的点都是黑色。如上图的结果。

一句话总结上面算法的效果:贴图中的每个“相对亮点”的周围都会产生“相对亮的特定图形”,图形的亮度取决于该点的亮度。越亮越明显。效果能够參考文末的图片。

接下来理解这段代码:

float dd = 150;

for( int i=0; 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 );

}

输出结果例如以下:

5ac42801ad89fe8eb02ac6b3319c23c1.png

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

baaabee5e902fccbaf0f180f185d5225.png

b)算法中 of 向量的路径为:

4fc445e365362314a0cc6377e5e3da0d.png

结果就非常清晰了;事实上这里算法和《【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中用到的贴图:

eaca0e74afc63552edc812ac57aabed3.png

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

08a90b638e72bfdc0d6a18cea73f871b.png

文章完成,欢迎讨论。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值