单位的吉祥物是云小宝。还是挺喜欢这个图像的,家里还有云小宝的抱枕。基于Shader的一些函数,实现了以下的效果
shader地址: www.shadertoy.com/view/XXtXRn
SDF构建基本形状
在iconfront找了下SVG,发现是通过三阶贝塞尔曲线画出来的,感觉有点太复杂了。。 不如直接用用几个圆组合组合. 这里的函数在之前绝大部分都推导过了, GPU优化的函数可以在IQ的文章 iquilezles.org/articles/di… 找。
这里通过圆角矩形,圆形,胶囊,圆弧四个SDF函数画出脸蛋,头,眼睛和嘴巴
代码就是很简单的SDF函数加上一些距离和宽高
float face = sdRoundedBox (uv - vec2(0.0, 0.0), vec2(1.0, .5), vec4(.5));
float head = sdCircle (uv - vec2(0.0, 0.15), .65);
float eyer = sdUnevenCapsule (uv - vec2(0.33, 0.0), 0.06, 0.06, 0.15 );
float eyel = sdUnevenCapsule (uv - vec2(-0.33, 0.0), 0.06, 0.06, 0.15 );
float month= sdArc (rotate(uv, PI), vec2(sin(0.22 * PI), cos(0.22 * PI)), 0.25, 0.04);
Mix函数产生过渡
云小宝本身就是嘴角往上笑的,但是我想如果把眼睛弯弯的应该会更加可爱吧。 这里介绍mix函数,最简单的可以讲一个图像转化成为另外一个图像, 其函数定义为
mix(a, b, h) = h * a + (1 - h) * b
例如我们需要像下面将一个眼睛转化成另外一个眼睛,只需要mix以下两个眼睛的distance
float animate2Eye(float eye1, float eye2, float eye3, float progress) {
return max(progress, 0.0) < 0.5 ?
mix(eye1, eye2, progress * 2.0):
mix(eye2, eye3, min((progress - .5 ) * 2.0, 1.0));
}
鼠标Uniform让眼睛跟随
shaderToy提供了鼠标的位置信息,在shader中称为uniform变量。 通过IMouse.xy获取,同样我们将其转化到[-1, 1]的空间中去
vec2 mouse = (2.0 * iMouse.xy - iResolution.xy) / iResolution.xy;
让眼睛看向鼠标,其实就是眼睛沿着鼠标的位置挪动一些距离。最简单的做法
float eyeR = Eye1(uv - vec2(0.33, 0.0) - mouse * .1);
float eyeL = Eye1(uv - vec2(-0.33, 0.0) - mouse * .1);
Fract函数产生重复
一个云小宝太单调了,给他找同类。这里的方法是通过操作坐标系来达到效果,关键是两个函数,fract和 floor。 这个技术在之前的tile图像中经常用到, 通过放大然后fract
id 是不同格子的坐标,例如我们要让不同云小宝都看向鼠标,就需要id计算格子与鼠标的相对坐标
float scale = 1.717;
vec2 uv = fract(uv2 * scale);
vec2 id = floor(uv2 * scale);
uv = 2. * uv - 1.0;
mouse = mouse * scale - id - uv;
Sin函数产生波纹
shadertoy除了提供mouse的坐标uniform之外,还提供了时间的uniform. 通过时间与sin函数的组合,便可以产生波纹的效果。 这里我们将波纹放在云小宝的外面. 首先找到外轮廓,其实很简单就是使用min函数把头发和脸结合起来
float border = min(face, hair);
通过sin函数构建波纹
if (border > 0. ) {
col = mix(col, vec3(1.0), sin(border*10.0));
}
为sin函数增加偏移,让其运动
col = mix(col, vec3(1.0), sin(border*10.0 - iTime * 5.));
函数产生光
光有一个现象是,距离光源越远,光强度越低。 可以用一个函数来模拟这个现象,x距离0越近,y值越大, 当然有时候我们要调节一下曲线的陡峭程度来达到合适的效果, 例如下面我使用了
if (border > 0. ) {
float d = sin(border*10.0 - iTime * 2. * PI);
d = 0.18 / d;
d = abs(d);
col = vec3(d);
}
三角函数产生丝滑颜色
如果只是需要一个颜色, 那么我们可以将上面的函数改为
col = vec3(1.0, 2.0, 3.0) * d;
但是如果我们要颜色丰富一些,可以使用IQ这篇博客中iquilezles.org/articles/pa… 介绍的通过三角函数产生美妙的色盘
// 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 + b*cos( 6.28318*(c*t+d) );
}
为了获取自己喜欢的颜色,也可以到 dev.thi.ng/gradients/ 这个网站去调配颜色, 这里我随便需选了一些颜色
vec3 palette( in float t )
{
vec3 a = vec3(0.318, 0.848, 0.798);
vec3 b = vec3(0.500, 0.500, 0.500);
vec3 c = vec3(1.000, 1.000, 1.000);
vec3 d = vec3(0.000, 0.333, -0.362);
return a + b*cos( 6.28318*(c*t+d) );
}
并且让颜色随着时间沿着distance移动
col = palette(border + iTime);
reference
- An introduction to shader art coding www.youtube.com/watch?v=f4s…
- The art of shader Making a smiley in shader toy www.youtube.com/watch?v=GgG…