web端的shader Threejs飞线

您所在的位置:网站首页 threejs拖尾效果 web端的shader Threejs飞线

web端的shader Threejs飞线

2023-11-11 08:43| 来源: 网络整理| 查看: 265

目标

之前想用粒子来实现一下飞线的效果,看到很多大佬的代码发现使用粒子会是一个不错的选择,因为粒子的渲染比较省性能,之前看到有人使用圆形的粒子 后来发现其实普通的正方形的粒子就行,因为在线的粗度比较小的情况下,是看不太出来是圆形还是方形,下面为最终效果。 three.js动态飞线 当然你可以在codepen上面查看在线演示以及代码。

思路

总的来说,粒子是一个个的小小的点,而点是线的基本构成单位,只要在一个路径上生成比较多的点,然后将他们从开始的地方比较大到最后很小依次排列,就变成了前端大末端细的线条,同时动态更改材质输入的时间,让其在顶点着色器中体现出这个点的大小,就能看到他在动的效果了。而其实他的几何体并没有动,改变的只是不同时间下的不同位置的点的大小而已。

过程 生成路径

最开始的一步, 需要生成路径,在这个例子中路径是在不同的状态下旋转的椭圆路径

function initCircleCurveGroup(number){ let curves = []; for (let i = 0; i let number = setting ? (Number(setting.number) || 1.0) : 1.0; // 在一个路径中同时存在的个数 let speed = setting ? (Number(setting.speed) || 1.0) : 1.0;// 速度约大越快 let length = setting ? (Number(setting.length) || 0.5) : 0.5;// 单根线的长度0-1之间1代表全满 let size = setting ?(Number(setting.size) || 3.0) : 3.0;// 在最大的地方的大小 默认为3像素 let color = setting ? setting.color || new THREE.Vector3(0,1,1) : new THREE.Vector3(0,1,1);// 颜色此处以Vector3的方式传入分别为RBG值 都是0-1的范围 let singleUniforms = { u_time: commonUniforms.u_time, number: {type: 'f', value:number}, speed: {type:'f',value:speed}, length: {type: 'f', value: length}, size: {type: 'f', value: size}, color: {type: 'v3', value: color} }; let lineMaterial = new THREE.ShaderMaterial({ uniforms:singleUniforms, vertexShader:document.getElementById('vertexShader').textContent,//顶点着色器部分 fragmentShader:document.getElementById('fragmentShader').textContent,// 片元着色器部分 transparent:true, //blending:THREE.AdditiveBlending, }); return lineMaterial; }

以上的方法会根据配置生成一个自定义的shader材质。 commonUniforms.u_time 是我在全局中同一的一个时间变量 当然这个时间变量也可以是不同材质拥有自己的时间。

顶点着色器 varying vec2 vUv; attribute float percent; varying float opacity; uniform float u_time; uniform float number; uniform float speed; uniform float length; uniform float size; void main() { vUv = uv; vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); float l = clamp(1.0-length,0.0,1.0);//空白部分长度占比 gl_PointSize = clamp(fract(percent*number + l - u_time*number*speed)-l ,0.0,1.) * size * (1./length); opacity = gl_PointSize/size; gl_Position = projectionMatrix * mvPosition; }

虽然顶点着色器的代码部分比较少,但是却是最为重要的部分,在此处我们专注于计算单个的点的大小。 首先percent代表的是该顶点在整个路径中的位置, 数值在0-1之间,0代表起点的位置 1代表终点的位置。 fract函数将整个的内容夹在0-1之间,相当于是取小数的部分。 l为空白部分的长度占比,在fract函数内部+l为的是让整个函数向前偏移空白的位置,这样线在最开始时是在起始位置,而在外面-l是因为让整个函数向下平移l个单位,这样在整个函数 percents[i] = (i/length); } geometry.addAttribute('percent', new THREE.BufferAttribute(percents,1)); let lineMaterial = initLineMaterial(matSetting); var flyLine = new THREE.Points( geometry, lineMaterial ); let euler = new THREE.Euler(Math.random()*Math.PI, Math.random()*Math.PI,0); flyLine.setRotationFromEuler(euler); scene.add(flyLine); }

这个函数会生成一条线并且会旋转随机的角度。

生成随机路径 function initCircleCurveGroup(number){ let curves = []; for (let i = 0; i return new THREE.Vector3( Math.random()*0.6 + 0.4, Math.random()*0.6 + 0.4, Math.random()*0.6 + 0.4 ) }

红绿蓝的通道都在0.4-1之间,稍微白一些的随机颜色;

创建多个路径 let curves = initCircleCurveGroup(500); for (let curve of curves){ initFlyLine(curve,{ speed: Math.random()*0.3+0.5, number: Math.floor(Math.random()*9+1), color: randomVec3Color(), size:4.0 },2000) }

将其放在渲染的前面

动画 function render() { commonUniforms.u_time.value +=0.01; renderer.render( scene, camera ); }

在渲染的时候将共用的时间uniform+=0.1; 如果你需要真实时间截则需要自己设定计时器获得,这里使用每一帧的时间。

这里是 角角兔 欢迎点赞评论哦 角角兔 towrabbit



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3