大数跨境

Shader带你走进科技感十足的 “泰森多边形”

Shader带你走进科技感十足的 “泰森多边形” 怿星科技
2019-12-20
1
导读:三步教你简单、快速生成泰森多边形

在生活中我们经常会看到一些基于泰森多边形的设计,如北京奥运会的水立方。在自然界中,泰森多边形更是随处可见,比如:蜻蜓的翅膀、树叶微观肌理等。那么我们该如何利用shader将其实现呢?




一、实现方法


1.1 什么是泰森多边形?

开始之前,我们先来了解一下泰森多边形的特征:
a. 每个泰森多边形内仅含有一个离散点数据
b. 泰森多边形内的点到相应离散点的距离最近
c. 位于泰森多边形边上的点到其两边的离散点距离相等

1.2 在shader中的实现方法

由其特征可知,我们需要先设置一组离散点,然后计算每一个像素与最近离散点的距离,也就是说我们需要遍历每个离散点,计算他们到当前像素点的距离,并把最近的那个距离保存下来。

伪代码如下:
float min_dist = 1.0;  
for (int i = 0; i < TOTAL_POINTS; i++) {
        float dist = distance(uv, points[i]);
        min_dist = min(min_dist, dist);
    }

当我们设置5个离散点,并把min_dist赋值给gl_FragColor时,就会得到类似下图的效果:




二、优化


上面的方法有些缺点,即当离散点数比较多时,我们虽然可以用for循环和数组来完成上述功能,但是遍历很多实例会显著降低着色器的性能,此外一个一个设置离散点也比较麻烦。


2.1 如何保证着色器的性能

保证着色器性能的方法就是把空间分割成网格。每个网格对应一个离散点,为避免网格交界区域的偏差,我们需要计算像素点到相邻网格中离散点的距离。每个像素点只需要计算到九个离散点的距离,即它所在的网格的离散点和相邻的八个网格的离散点。


——如何分割网格?
uv坐标默认是在0到1之间,如果我们把uv乘以一个系数,这样在0到1之间的图形就会重复生成网格。
a. 把uv乘以5,把坐标等比放大5倍:uv *= 5.0
b. 使用fract()函数单位化变量,使之在0.0到1.0之间:vec2 f_uv = fract(uv)
c. 使用floor()函数对uv取整,就知道是在哪个网格了:vec2 i_uv = floor(uv)

——计算最短距离
如何计算像素点到相邻网格中随机离散点的距离?从网格坐标来说,就是x坐标从-1(左)到1(右),y坐标从 -1(下)到1(上),一共9 个网格的3x3区域可以用两个 for 循环遍历:

伪代码如下:
for (int y= -1; y <= 1; y++) {
        for (int x= -1; x <= 1; x++) {
            vec2 neighbor = vec2(float(x),float(y));
            vec2 diff = neighbor + point - f_uv;
            float dist = length(diff);
            min_dist = min(min_dist, dist);
    }
}

2.2 随机构造离散点

我们知道可以通过把正弦函数打散成小片段来得到一些伪随机数。把sin(x)的值乘以大点的数,就无法区分sin波了,其小数部分的粒度将sin的循环变成了伪随机的混沌。y=fract(sin(x)*10000.0),会生成一个伪随机数,这就意味着输入相同的x值总会返回相同的值。我们如果把i_uv做为参数传入,这样每个网格内的离散点位置就都不一样了。但我们需要将一个二维向量转换为一个浮点数。最简单的就是与另一个向量进行点乘,其会返回一个0.0到1.0之间的值,通过以下随机函数我们能得到下面的图形。


伪代码如下:
float random (vec2 st) {
    return fract(sin(dot(st.xy,vec2(1,10)))*10000.);
}
void main(){
    precision mediump float;
    float rnd = random(i_uv);
    gl_FragColor = vec4(vec3(rnd),1.0);
}


我们可以通过调整所点乘的向量和系数来得到合适的效果。

2.3 最终效果

综上可得出如下效果:



三、进一步探索


这个算法还可以从离散点而非像素点的角度理解。算法可以表述为:每个离散点向外扩张生长,直到它碰到其它扩张的区域。这反映了自然界的生长规则——生命的形态是由内部扩张,并由生长力量和限制性的外部力量共同决定的。


我们可以对其展开进一步探索以创造出更多有趣的用法:
a. 修改缩放空间
b. 想办法让离散点动起来
c. 使用其它计算代替min_dist = min(min_dist, dist)。例如min_dist = min(min_dist, min_dist*dist)



讲了这么多,那么这种效果在汽车领域该如何应用呢?其实上文中的动效,我们可以把它做成车机背景,是不是很有科技感?当然其应用并不仅限于此。更多的应用还等着大家一起去挖掘和探索,也期待大家将各自的想法发送留言与我们一起讨论。



更多精彩推荐:

Kanzi优化利器-Resource Profiling

八一八Kanzi与Android这对好基友

AE在UI动效设计中的应用

炫酷特效来袭!车辆动态换漆

Kanzi 3.6.4焦点控制功能全面升级,速来体验吧

HMI设计中的色彩运用小技巧

帧缓存(FrameBuffer)与Kanzi Render Pass

Kanzi资讯快递

Shader之水波纹

Kanzi之文字一二事





【声明】内容源于网络
0
0
怿星科技
让智能汽车研发更高效!
内容 428
粉丝 0
怿星科技 让智能汽车研发更高效!
总阅读613
粉丝0
内容428