一.前言
一如标题,如何变成狗?当然这里不是指的物种的变换或者是变成单身狗。看如下动画:
二.分析与思考
从上面的动画分析看,开头像液体球一样融合的动画很明显是前面文章中解析过的Metaball元球融合原理,不清楚的可以跳转去先看下解析。Metaball元球在视觉上的融合会给人一种多变,柔性转变的效果,所以这里用作变形恰到好处,但问题是如何变成狗呢?需要将元球摆放成狗的形状或是用像素拼成狗吗?如果是这样那就还需要狗的像素矩阵才行,未免太过于繁琐。
再仔细观察动画,metaball液体分散消失时,像素并没有汇聚到狗身上而且分散在不同的点随机消失了,而狗是扭曲着出来的。或许是视觉的原因,开头动画觉得Metaball在扭曲,后面狗又扭曲着出现,我们就联想到这是一个变身!这其实是动画的魔术!动画实现中我们只需要将两部分动画衔接起来即可,动画解析可能不难,但是能将两部分知识结合起来运用于动画,是非常需要创造力的。
三.实现
1.创建Meteball
如果懂得Metaball动画原理,这里的实现就不会再觉得难了。这边我还是结合代码复述一下,就当复习一遍了
创建带有自定义材质的Mesh用于着色器编程
_createShape() {
this._createMetaballs();
const geo = new THREE.PlaneBufferGeometry(this.width, this.height, 1, 1); //创建平面几何图形
const mat = new THREE.ShaderMaterial({
//自定义材质
vertexShader: vs,
fragmentShader: fs,
uniforms: this.uniforms,
transparent: true,
side: THREE.DoubleSide,
});
this.shape = new THREE.Mesh(geo, mat);
this.add(this.shape);
}
构建Metaball数据
_createMetaballs() {
for (let i = 0; i < 40; i++) {
this.balls.push(new THREE.Vector4(0, 0, 0.001, 0)); //初始化坐标为(0,0) 半径为0.001
}
}
这里balls的数据会由JS传到片元着色器中,数据由JS管理便于实现动画。比如修改balls的数据就可以对应改变Metaball的位置,大小,融合阈值。
2.片元着色器Metaball处理
precision mediump float;
varying vec2 v_uv; //线性uv
uniform float u_time; //u_time每帧累加的值
uniform float u_rangeMax; //最高阈值
uniform vec4 u_metaballs[40]; //metaball数据
void main() {
vec2 st = 2.0