简介
shader代码来自github上一个项目,compose libraries,但是链接找不到了。。。,代码很简洁,但是里面的技巧适合我这种初学者领会。
Shader代码
const float PI = 3.14159265359;// 按角度旋转。(安卓的坐标由于从左上开始,所以旋转角度与正常坐标系相反)
mat2 rot(float a) {float s = sin(a), c = cos(a);return mat2(c, -s, s, c);
}// 矩形区域
float sdBox(vec2 p, vec2 b) {vec2 d = abs(p)-b;return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}// 光柱数量
const float MAX_STEPS = 24.0;void mainImage( out vec4 fragColor, in vec2 fragCoord ) {// 坐标系变换至-1到1vec2 uv = fragCoord / iResolution.xy * 2.0 - 1.0; // -1..0..1 coordinate systemfloat aspect = iResolution.y / iResolution.x; // aspect ratioif (aspect > 1.0) { // landscape mode?uv.y *= aspect;} else {uv.x /= aspect;}// 随时间变化的角度float angle = -PI * 2.0 * iTime;float l = 0.0; // luminancefor (float i = .0; i < MAX_STEPS; i++) {// 光柱角度float rectAngle = PI * 2.0 / MAX_STEPS * i;// 旋转vec2 p = uv * rot(rectAngle); // rotate// 位移p.x += 0.4; // move outside// 与当前角度的差float angleDistance = mod(rectAngle - angle, 2.0 * PI);// 随当前角度距离越远,强度越低float intensity = 1.0 - (angleDistance / (PI * 2.0));// 矩形区域,长度随强度变化float box = sdBox(p, vec2(0.2 * (intensity + .7), 0.003));// 矩形随强度平滑缩小box = smoothstep(0.0, max(0.03, 0.13 * intensity) , box);//l = max(l, 1.0 - box);// 绘制矩形区域l += 1.0 - box;}// 校正至0 1区间。(shadertoy网页版clamp的实现有些问题,返回的都是1.;暂不清楚原因)l = clamp(0., 1., l);vec3 col = vec3(.1, 1., 0.) * l;//col = mix(vec3(1.), col, l);fragColor = vec4(col, l);
}
代码很少,但是效果还不错,个人觉得这里值得初学者领会的有几点:
1 旋转。涉及到二维变换矩阵。
2 旋转后绘制。与安卓Canvas画图时旋转画布的原理类似,不同的是这里是uv,对我个人来讲,直接面对uv,理解上总是会绕。
3 偏移。p.x += 0.4; 非常实用的小技巧,可以让光柱偏离圆心,视觉效果上,由于长度跟随intensity(角度)变化,看上去就是一个缓慢变化的位移。
4 循环,绘制区域的计算。l += 1.0 - box; 这里用到+号,但是由于输入是uv,而uv实际上只会存在于某个光柱区域,所以实际上累加到其它区域时加的是0,而循环的效果其实就是计算当前帧所有光柱区域。
总结
前面在写shader的时候,习惯于算相对位置和区域,对比这个例子,旋转、位移、循环,用的都很经典,值得好好领会。(我觉得领会这个词对我学习shader很适用,就是很多场景,你觉得你理解了,但其实并没有。。。)