写在前面
颇为感慨,竟然真的有用到建筑数学的一天。🤨 今天的学习资料是iq老师这个基于voronoi的shader,由于这个版权的限制比较严格,我们就点到为止,主要是学习一下变形的思路~更多参考了其原理展示。
距离算法
在计算距离时,我们一般都是求两点之间的直线距离,也就是欧几里得距离,但常用的距离算法还有曼哈顿距离(出租车距离)和切比雪夫距离(国王距离)。这不是一个数学博客,咱也解释不清,咱就不多说了,详细不如读wiki。
回到Voronoi
Voronoi图是基于距离的算法,不同的距离算法就会产生不同的分格效果。 基于distance的算法,今天要拿WorleyNoise开刀,削一个帅气的随机立方体效果。
从泡泡到立方体
先整一个基础版的worley noise。我们需要一个2维的哈希函数来生成晶格中特征点的位置,这里就不上之前用的psrd了,码太长了。
vec2 hash( vec2 p )
{
p = vec2( dot(p,vec2(137.1,373.7)), dot(p,vec2(269.5,183.7)) );
return fract(sin(p)*43758.37);
}
float worley(vec2 p){
vec2 n = floor(p);
vec2 f = fract(p);
float d = 1.;
for(int i=-2;i<=2;i++){
for(int j=-2;j<=2;j++){
float D1 = distance(hash(n+vec2(i,j))+vec2(i,j),f);//Euclidean
d = min(d,D1);
}
}
return d;
}
换上出租车和国王,可以看到Manhattan的距离场是十字星状,Chebyshev的距离场是斜十字星状。
float D2 = abs(o.x-f.x)+abs(o.y-f.y);//Manhattan
float D3 = max(abs(o.x-f.x),abs(o.y-f.y));//Chebyshev
受Chebyshev距离场的启发,我们可以通过调整距离公式以获得轴测小立方体三条边的效果。 本视觉动物这样理解数学: 套入距离公式,我们的效果已经初具雏形了!
float D4 = max(abs(o.x-f.x)*0.866+(o.y-f.y)*0.5,-(o.y-f.y));//Triangle
d = min(d,D4);
我们最开始的函数输出是一维的float,这里改成vec3以增加一些数据输出。x分量记录距离场;y分量记录归一化的特征点x坐标,用以作为随机颜色的seed;z分量计算产生一个以特征点为中心的mask。
if(D4<r.x){
r.x = D4;//distance
r.y = (o.x-float(i))*0.5+0.5;//for colorseed
r.z = 1.-step(0.0,0.5*abs(o.x-f.x)+0.866*(o.y-f.y))*(1.0+step(0.0,o.x-f.x))*0.4;//mask
}
看起来不错! 接下来其实就可以做许多事,比如去掉hash的随机性,来获得一些规则图案—— (啊好气!因为根三的精度 差那么一丝丝🤬 比如利用距离场伪造一点AO—— 比如加点动画——
o = sin(iTime + hash(n+vec2(i,j))*6.28)*0.5+0.5;//animate
vec2 dp = 2.0*vec2( 1.0/iResolution.y, 0.0 );
float d = abs(worley( 2.*(uv+dp.xy)).z - worley( 2.*(uv-dp.xy)).z )+
abs(worley( 2.*(uv+dp.yx)).z - worley( 2.*(uv-dp.yx)).z );
还可以根据z分量的mask去扭曲uv,获得贴图坐标系,给每个面贴点小图案—— 哎呀这个详见原shader。不能再做了 再像要被骂了x 总之今天就到这里!晚安! 👉完整代码👈
ODOS —— One Day One Shader 努力日更的学习计划。 包括但不限于基于[Shadertoy][22]、UnityShaderLab等平台的shader学习笔记