“我正在参加「掘金·启航计划」”
前文
所用知识
前文知识+ Clock threejs.org/docs/index.…以及shader。
shader的知识比较杂,还需要图形学基础,还在学习中。 较为出名的两个学习网站是
the book of shaders thebookofshaders.com/
shadertoy www.shadertoy.com/
画图工具 www.desmos.com/calculator?…
图形学学习推荐 b站搜索games101和202。101作业需要C++基础,202作业是webgl。
目标
上一篇文章实现了模型的粒子化,这一篇文章介绍一下如何实现从一个模型变换到另一个模型的粒子变换效果。
实现
先贴一下上期实现的效果和这期实现效果的代码
从63行处开始修改。
我们已经实现了一个马的模型,那么我想要将这个马的模型变换到另外一个模型,该怎么做呢?
很明显,我们需要另一个模型的位置信息。
如下所示,我们创建一个bufferGeometry,然后将第二个模型的position传入,这个pos2将在着色器中使用。
const model1=await glbloader.loadAsync('https://threejs.org/examples//models/gltf/Horse.glb')
const model2=await glbloader.loadAsync('https://threejs.org/examples//models/gltf/Flamingo.glb')
const model1pos=combineBuffer(model1.scene,'position')
const model2pos=combineBuffer(model2.scene,'position')
let buffer = new THREE.BufferGeometry()
buffer.setAttribute('position', model1pos)
buffer.setAttribute('pos2', model2pos)
接下来我们创建着色器
let Pointsvertex=`precision mediump float;
attribute vec3 position;
attribute vec3 pos2;
// attribute vec2 uv;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
// 获取时间
uniform float uTime;
// varying vec2 vUv;
// highp -2^16 - 2^16
// mediump -2^10 - 2^10
// lowp -2^8 - 2^8
void main(){
// vUv = uv;
vec3 dis =pos2-position;
vec3 pos=position+dis*abs(sin(uTime));
vec4 modelPosition = modelMatrix * vec4( pos, 1.0 );
gl_Position = projectionMatrix * viewMatrix * modelPosition ;
gl_PointSize=5.0;
gl_PointSize*=100./-(viewMatrix*modelPosition).z;
}`
let Pointsfrag=`precision mediump float;
void main()
{
gl_FragColor=vec4(1.0,0.0,0.0,1.0);
}`
let rawshader=new THREE.RawShaderMaterial(
{
vertexShader:Pointsvertex,
fragmentShader:Pointsfrag,
side:2,
uniforms:{
uTime:{
value:0
}
},
// transparent:true,
blending:THREE.AdditiveBlending,
depthTest:false
})
在顶点着色器中,attribute vec3 position和 attribute vec3 pos2是两个模型的位置,首先我们获取两个位置的差值,然后第一个模型的位置在一定时间内跑完这个差值就可以得到一个位置到另一个模型的动画了。 所以我们在uniform中创建一个uTime,当uTime为0时,为第一模型,当uTime为1时则为第二个模型,中间值为过渡动画。为了保证它在0-1中循环,我使用sin函数,并取其绝对值。
在片元着色器中,用来控制点的颜色。
接下来,我们需要控制uTime的变化,这里可以用一些动画库实现,比如gsap,为了方便,我直接用three自带的clock。
let clock1 = new THREE.Clock()
//渲染循环
let render=function(){
controls.update()
const elapsedTime = clock1.getElapsedTime();
rawshader.uniforms.uTime.value = elapsedTime/5;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render()
最后
细心的小伙伴可以发现,这个实现的点实际上是方形的,并不是圆,这可以通过修改片元着色器,用数学方法画个圆,iquilezles.org/articles/di…,the book of shaders中也有介绍。