写在前面
前两天又仔细读了一下the book of shader,写的真是太好了呜呜。今天来补一点点noise章节前面的基础知识。
极坐标系
暴露自己编程地基薄弱的时间到:
C/C++标准库中计算正切的函数有两个,一个是atan(y/x),一个是atan2(y, x)。 atan2(y, x)是4象限反正切,它的取值不仅取决于正切值y/x,还取决于点 (x, y) 落入哪个象限,返回值是-Pi~Pi。
而在Opengl中,atan(y,x)这个重载其实就是atan2。无语了,是谁上次还在傻傻用选择判断句。
所以将二维点的笛卡尔坐标转化为极坐标只需要:
float a = atan(uv.y,uv.x);
float r = length(uv);
然后就可以进行一些极坐标绘图————
float f =cos(a*3.);
vec3 col = vec3(1.-smoothstep(f,f+0.02,r));
HSB颜色
昨天用RGB做的彩虹斑纹,调色费死劲了。还是使用hsb取色更符合直觉。
//convert from RGB to HSB
vec3 rgb2hsb( in vec3 c ){
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz),
vec4(c.gb, K.xy),
step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r),
vec4(c.r, p.yzx),
step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 d + e)),
d / (q.x + e),
q.x);
}
//convert from HSB to RGB, refer to iq
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
vec3 rgb = clamp(abs(mod(c.x6.0+vec3(0.0,4.0,2.0),
6.0)-3.0)-1.0,
0.0,
1.0 );
rgb = rgbrgb(3.0-2.0rgb);// cubic smoothing
return c.z mix(vec3(1.0), rgb, c.y);
}
结合昨天的noise,就可以获得一只彩虹煎蛋:
float n = psrdnoise(vec2(cos(a),sin(a)), vec2(0), iTime,g);
float f = smoothstep(2.,2.005,r+n0.2)smoothstep(2.55-n0.5,2.5-n0.5,r+n0.2);
vec3 col = hsb2rgb(vec3(a/6.28,1,1))f;
这里的noise相当于从2d中取1d四方连续噪声,不过这不是今天要努力的方向。
卷起来
极坐标系中令r=a即可获得螺旋线,类似的,我们可以在shader中获得螺旋:
vec3 col = fract(vec3(0) + a/2./PI + r - iTime/8. );
// 基础相位 映射至-1~1 距离 加动画
smooth fract
因为之前只做过基于距离场的AA,fract产生的凄惨小锯齿就直接留在昨天的shader里了。今天早上看着实在太刺眼,整了个smoothstep重新发布了一下。
吃完午饭,正在阅读Fabrice老师和Shane老师七年前关于螺旋线图样里fract的讨论,昨天的shader就收到了Shane老师关于smooth fract的慈善式教学,呜呜,谢谢大佬。
// Smooth fract with the gradient taken into account.
// Smoothing factor. Set to 1 for a comparisson.
float sf = iResolution.y/300./max(length(g), .001);
n = min(n, n(1. - n)48.sf);
对于今天的大大泡泡糖,也是类似的方式,只是smooth factor不太一样。
vec2 uv = (2.fragCoord-iResolution.xy)/iResolution.y;
float a =atan(uv.y,uv.x);//angle -Pi~Pi
float w = iMouse.x / iResolution.x + 0.2;//width
float r = length(uv/w);
vec3 col = fract(vec3(0,1,2)/3.+ a/2./PI + r - iTime/8. );
col = min(col, col*(1. - col)*iResolution.y*w/(1. + .16/r));
col将初始相位改为(0,1/3,2/3),所以就产生了颜色的分层:
其他的AA方法可以参考原始shader。
原shader已经非常简单好看了,但不太好意思直接贴logo,所以再加一个渐变好了。iq大佬说,把色彩转到hsb调色再转回rgb是很多余的,呜呜好吧,我们改用这个函数:
// cosine based palette, 4 vec3 params
vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d )
{
return a + bcos( 6.28318(c*t+d) );
}
单一彩虹色太无聊了,要卷就再卷一点。
最后调调参数(这个gif压缩也太狠了。。):
➡️完整代码
下班!明天回学校啦。
ODOS —— One Day One Shader 努力日更的学习计划。 包括但不限于基于[Shadertoy][22]、UnityShaderLab等平台的shader学习笔记