让物体从上到下消失的shader处理。使用 threejs material中的onBeforeCompile方法,在编译前修改shader。
/**
*
* @param params
* target: Mesh。 目标Mesh物体
* isVertical: Boolean类型。 ture是y方向动画,false是x方向
* isStart: Boolean类型。true是从显示=>隐藏。false是 从隐藏=>显示
* callback: fn函数。动画执行完回调
* @returns
*/
export let MachineAnimateShader = function (params: any) {
const { target, isVertical, isStart, callback } = params;
if (!target.material) return false;
if(isStart) {
saveTarget[target.name] = {
mesh: target,
isVertical: isVertical,
material: target.material.clone()
};
}
// 物体的高度和宽度范围
const { min, max } = target.geometry.boundingBox;
const diff = 2.0;
const MaxObject = { x: max.x + diff, y: max.y + diff };
const MinObject = { x: min.x - diff, y: min.y - diff };
const startValue = isStart ? ((isVertical ? max.y : max.x) + diff) : ((isVertical ? min.y : min.x) - diff);
let newMaterial = target.material.clone();
target.material = newMaterial;
let targetShader: any = null;
newMaterial.onBeforeCompile = (shader: any) => {
targetShader = shader;
// 顶部颜色
shader.uniforms.uTopColor = {
value: new THREE.Color("#51ddef"),
};
// 时间
shader.uniforms.iTime = {
value: startValue,
};
// 修改顶点着色器
shader.vertexShader = shader.vertexShader.replace(
"#include <common>",
`
#include <common>
varying vec3 vPosition;
`
);
shader.vertexShader = shader.vertexShader.replace(
"#include <fog_vertex>",
`
#include <fog_vertex>
vPosition = position;
`
);
// 修改片元着色器
shader.fragmentShader = shader.fragmentShader.replace(
"#include <common>",
`
#include <common>
uniform vec3 uTopColor;
// uniform float uHeight;
uniform float iTime;
varying vec3 vPosition;
`
);
let fragmentStr = '';
if (isVertical) { // 垂直方向
fragmentStr = `
#include <dithering_fragment>
if(abs(iTime - vPosition.y) < 0.05) {
gl_FragColor = vec4(uTopColor, 0.7);
}
if(iTime < vPosition.y) {
discard;
}`
} else { // 水平方向
fragmentStr = `
#include <dithering_fragment>
if(abs(iTime - vPosition.x) < 0.05) {
gl_FragColor = vec4(uTopColor, 0.7);
}
if(iTime < vPosition.x) {
discard;
}`
}
shader.fragmentShader = shader.fragmentShader.replace(
"#include <dithering_fragment>", fragmentStr
);
}
// 清除shader缓存
newMaterial.customProgramCacheKey = function() {
return '1' + target.name + newMaterial.uuid;
}
target.material.needsUpdate = true;
// const tweenStartobject = { x: max.x + diff, y: max.y + diff };
// const tweenEndObject = { x: min.x - diff, y: min.y - diff };
const tweenStartobject = isStart ? MaxObject : MinObject;
const tweenEndObject = isStart ? MinObject : MaxObject;
const tween = new TWEEN.Tween(tweenStartobject);
tween.to(tweenEndObject, 2000)
.onUpdate(function (object) {
if (targetShader) {
targetShader.uniforms.iTime.value = isVertical ? object.y : object.x;
}
})
.onComplete(function () {
callback && callback();
})
.start();
}