OpenGL Shader實(shí)例分析(7)雪花飄落效果
研究了一個(gè)雪花飄落效果,感覺挺不錯(cuò)的,分享給大家,效果如下:

代碼如下:
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
// 屏幕中的坐標(biāo),以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 );
}
在理解這段代碼前,先理解怎么畫一個(gè)圈,代碼如下:
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 );
}
然后再準(zhǔn)備一張貼圖,圖片中間是一個(gè)白色像素,周圍都是黑色

效果如下:

這段代碼處于fragment shader中,意味著屏幕上每個(gè)點(diǎn)都會進(jìn)行上述的算法。具體如下,遍歷貼圖中該點(diǎn)周圍的點(diǎn)(上面的代碼中為距離該點(diǎn)為20單位的圓上的點(diǎn)),把周圍點(diǎn)中最亮的作為該點(diǎn)的顏色。 上面的貼圖有點(diǎn)特殊,只有一個(gè)點(diǎn)是白色,其余點(diǎn)都是黑色的。那么只有距離該點(diǎn)正好為20單位的點(diǎn)才會變成亮色,其余的點(diǎn)都是黑色,如上圖的結(jié)果。一句話總結(jié)上面算法的效果:貼圖中的每一個(gè)“相對亮點(diǎn)”的周圍都會產(chǎn)生“相對亮的特定圖形”,圖形的亮度取決于該點(diǎn)的亮度,越亮越明顯。效果可以參考文末的圖片。
接下來理解這段代碼:
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 );
}
輸出結(jié)果如下:

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

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

結(jié)果就很清晰了;其實(shí)這里算法和《【OpenGL】Shader實(shí)例分析(二)- Heart》中繪制心形的算法很類似。
最后加上時(shí)間就可以實(shí)現(xiàn)動(dòng)畫了:
vec2 of = vec2( cos(an), sin(an) ) * (1.0+0.6*cos(7.0*an+iGlobalTime)) + vec2( 0.0, iGlobalTime );
第一個(gè)iGlobalTime,用來控制雪花的旋轉(zhuǎn),第二個(gè)iGlobalTime使雪花下落。
2)后期顏色等處理
這里可以理解為一種postEffect處理,具體是如下的代碼貢獻(xiàn)的效果:
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)) 這句話使得顏色變成暖色調(diào)。col值的范圍為[0,1],對小數(shù)繼續(xù)pow運(yùn)算,次數(shù)越高,該值越小。比如:0.5的1次方是0.5, 2次方為0.25, 3次方為0.125等;所以這句話的作用很明顯:red成份不變,green變小一些,blue變的更小。達(dá)到的效果,使得整體顏色會偏向暖色調(diào)。
b)pow(4.0*p.y*(1.0-p.y), 0.2) 使得屏幕上下兩邊變暗。
最后附上shader中用到的貼圖:

經(jīng)過程序處理后,得到如下:

文章完畢,歡迎討論。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- OpenGL中的glutInitDisplayMode()函數(shù)的理解
- OpenGL關(guān)于glStencilFuncSeparate()和glStencilFunc()函數(shù)的區(qū)別講解
- OpenGL Shader實(shí)例分析(1)Wave效果
- SDL2和OpenGL使用踩坑筆記經(jīng)驗(yàn)分享
- Android利用OpenGLES繪制天空盒實(shí)例教程
- android使用OPENGL ES繪制圓柱體
- opengl實(shí)現(xiàn)任意兩點(diǎn)間畫圓柱體
- OpenGL ES透視投影實(shí)現(xiàn)方法(四)
- OpenGL ES著色器使用詳解(二)
- OpenGL實(shí)現(xiàn)Bezier曲線的方法示例
相關(guān)文章
Android WebView 應(yīng)用界面開發(fā)教程
WebView組件本身就是一個(gè)瀏覽器實(shí)現(xiàn),開發(fā)者可以直接在WebView中使用聚合(Polymer)和Material設(shè)計(jì)。接下來通過本文給大家介紹Android WebView 應(yīng)用界面開發(fā)教程,一起看下吧2016-08-08
Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(四)
這篇文章主要為大家詳細(xì)介紹了Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Android快速實(shí)現(xiàn)斷點(diǎn)續(xù)傳的方法
這篇文章主要為大家詳細(xì)介紹了Android快速實(shí)現(xiàn)斷點(diǎn)續(xù)傳的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
Android實(shí)現(xiàn)雙擊TitleBar回頂部的功能示例代碼
一個(gè)簡單易用的導(dǎo)航欄TitleBar,可以輕松實(shí)現(xiàn)IOS導(dǎo)航欄的各種效果,下面這篇文章主要給大家介紹了關(guān)于Android如何實(shí)現(xiàn)雙擊TitleBar回頂部功能的相關(guān)資料,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考借鑒,下面來一起看看吧。2017-09-09
Android SDK命令行工具M(jìn)onkey參數(shù)及使用解析
這篇文章主要介紹了Android SDK命令行工具M(jìn)onkey參,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值數(shù)及使用解析,需要的朋友可以參考下2020-10-10
Android實(shí)現(xiàn)從底部彈出的Dialog示例(一)
這篇文章主要介紹了Android實(shí)現(xiàn)從底部彈出的Dialog示例(一),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-01-01
Android Secret Code(輸入字符彈出手機(jī)信息)詳解
這篇文章主要介紹了Android Secret Code(輸入字符彈出手機(jī)信息)詳解的相關(guān)資料,需要的朋友可以參考下2016-11-11
Android編程實(shí)現(xiàn)在底端顯示選項(xiàng)卡的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)在底端顯示選項(xiàng)卡的方法,涉及Android界面線性布局、相對布局及選項(xiàng)卡設(shè)置相關(guān)操作技巧,需要的朋友可以參考下2017-02-02

