1. 程式人生 > >Shader特效——“旋轉粒子”的實現【GLSL】

Shader特效——“旋轉粒子”的實現【GLSL】

效果圖:



GLSL程式碼及演算法解釋:


// 動畫相關引數
float dotSize = 0.01;
float iteration = 100.;
float xAmp = 0.3;
float yAmp = 0.1;
float speed = 0.05;
float rotateCanvas = 0.;
float rotateParticles = 1.;
float rotateMultiplier = 10.;
vec2 pos = vec2(.5, .5);
float xFactor = 0.2;
float yFactor = 0.2;

#define RENDERSIZE vec2(512., 512.)
uniform float iGlobalTime;

//rotation
vec2 rot(vec2 uv, float a)
{
	// [uv.x uv.y] * [cos(a),  sin(a),
	//                -sin(a), cos(a)]
	return vec2(uv.x * cos(a) - uv.y * sin(a), uv.y * cos(a) + uv.x * sin(a));
}

float circle(vec2 uv, float size)
{
	// 向量長度在範圍內為白色,範圍外為黑
	return length(uv) > size ? 0.0 : 1.0;
}

void main()
{

	vec2 uv = gl_FragCoord.xy / RENDERSIZE; // [0., 1.]
	uv -= vec2(pos);// [-.5, .5]
	uv.x *= RENDERSIZE.x / RENDERSIZE.y;	// ratio = X/Y

	vec3 color = vec3(0);

	//第一個粒子(i == 0)的 uv【其實第一個粒子是看不見的,因為size == 0】
	uv = rot(uv, rotateCanvas);

	// 99個粒子
	for (float i = 0.0; i < 100.0; i++)
	{
		// set max number of iterations
		if (iteration < i)
			break;

		// x:sin() y:cos() 的旋轉動畫
		vec2 new_pos = vec2(cos(i * xFactor * (iGlobalTime * speed)) * xAmp,
				sin(i * yFactor * (iGlobalTime * speed)) * yAmp);
		// st:新位置到uv的向量
		vec2 st = uv - new_pos;

		// 計算st向量的長度,並設定粒子的尺寸(從小到大)
		float dots = circle((st), dotSize * (i * 0.01));

		//旋轉當前粒子的uv得到下一個粒子的uv
		uv = rot(uv, rotateParticles * rotateMultiplier);

		// 更新紋素的顏色(只要當前紋素屬於其中一個粒子,則置為白色,否則仍然是黑色)
		// 嚴謹的話是應該clamp,但是超過1也是白色
		color += dots;
	}

	gl_FragColor = vec4(vec3(color), 1.0);
}