在网上看到的这种流光效果,在某宝买了源码后,决定把这个效果封装成js文件,以后用起来就很方便了。
flyCurve.js文件代码如下:
import * as THREE from 'three'
var uniforms = {
u_time: { value: 0.0 }
};
var clock = new THREE.Clock();
export const timerFlyCurve = setInterval(()=>{
const elapsed = clock.getElapsedTime();
uniforms.u_time.value = elapsed;
},20);
// 着色器设置
const vertexShader = `
varying vec2 vUv;
attribute float percent;
uniform float u_time;
uniform float number;
uniform float speed;
uniform float length;
varying float opacity;
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;
}
`
const fragmentShader = `
#ifdef GL_ES
precision mediump float;
#endif
varying float opacity;
uniform vec3 color;
void main(){
if(opacity <=0.2){
discard;
}
gl_FragColor = vec4(color,1.0);
}
`
export function createFlyCurve(points, closed) {
var curve = new THREE.CatmullRomCurve3(points, closed);
// 流光的颜色,三个数字分别代表rgb的值,不过注意,需要除以255
// 比如浅绿色的rgb是(0,255,127),那么这里的Vector3就等于(0,1,127/255)也就是(0,1,0.49803921)
var color = new THREE.Vector3( 0.5999758518718452, 0.7798940272761521, 0.6181903838257632 );
var flyLine = initFlyLine( curve, {
speed: 0.4,
color: color,
number: 3, //同时跑动的流光数量
length: 0.2, //流光线条长度
size: 3 //粗细
}, 5000 );
return flyLine;
}
function initFlyLine( curve, matSetting, pointsNumber ) {
var points = curve.getPoints( pointsNumber );
var geometry = new THREE.BufferGeometry().setFromPoints( points );
const length = points.length;
var percents = new Float32Array( length );
for (let i = 0; i < points.length; i += 1) {
percents[i] = ( i / length );
}
geometry.setAttribute( 'percent', new THREE.BufferAttribute( percents, 1 ) );
const lineMaterial = initLineMaterial( matSetting );
var flyLine = new THREE.Points( geometry, lineMaterial );
return flyLine;
}
function initLineMaterial( setting ) {
const number = setting ? ( Number( setting.number ) || 1.0 ) : 1.0;
const speed = setting ? ( Number( setting.speed ) || 1.0 ) : 1.0;
const length = setting ? ( Number( setting.length ) || 0.5 ) : 0.5;
const size = setting ? ( Number( setting.size ) || 3.0 ) : 3.0;
const color = setting ? setting.color || new THREE.Vector3( 0, 1, 1 ) : new THREE.Vector3( 0, 1, 1 );
const singleUniforms = {
u_time: uniforms.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 }
};
const lineMaterial = new THREE.ShaderMaterial( {
uniforms: singleUniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true
} );
return lineMaterial;
}
export default
{
createFlyCurve,
timerFlyCurve
}
在vue中先引入createFlyCurve方法和timer定时器:
?createFlyCurve方法只有两个参数,points, closed,也就是组成曲线的点坐标和曲线是否闭合,该方法返回一个Points物体,然后将这个物体添加到场景就可以了。
?如果想要改变流光的速度、数量、长度、颜色等参数,可以直接去js文件里修改。
?最后,因为js文件里有一个定时器控制流光动起来,所以在vue销毁前最好还是清理一下定时器,以免内存泄漏等问题。
?完整的demo代码:
<template>
<div>
<!-- 本案例演示流光js文件的使用-->
<div id="container"></div>
</div>
</template>
<script>
import * as THREE from 'three'
// 注意OrbitControls要加{},注意路径是jsm
import {
OrbitControls
} from 'three/examples/jsm/controls/OrbitControls.js';
import {
createFlyCurve,timerFlyCurve
} from './flyCurve.js';
export default {
name: "hello",
props: {
},
components: {
},
data() {
return {
scene: null,
renderer: null,
camera: null
}
},
created() {},
mounted() {
this.init();
this.animate();
},
//后续还要在beforeDestory中进行销毁
beforeDestroy() {
this.scene = null;
this.renderer = null;
this.camera = null;
// 流光效果js文件中的定时器,为了避免内存泄漏问题,最好在销毁前清除
clearInterval(timerFlyCurve);
},
methods: {
// 场景初始化
init() {
let container = document.getElementById('container');
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 特别注意,相机的位置要大于几何体的尺寸
this.camera.position.x = 20;
this.camera.position.y = 20;
this.camera.position.z = 20;
this.scene = new THREE.Scene();
this.renderer = new THREE.WebGLRenderer(
{
// 抗锯齿性
antialias: true
}
);
this.renderer.setClearAlpha(0.0); // 设置alpha,合法参数是一个 0.0 到 1.0 之间的浮点数
this.renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(this.renderer.domElement);
var points = [
new THREE.Vector3(-10, 0, 10),
new THREE.Vector3(-5, 5, 5),
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(5, -5, 5),
new THREE.Vector3(10, 0, 10)
];
var closed = true;
var flyLine = createFlyCurve(points,closed);
var flyLine2 = createFlyCurve(points,closed);
flyLine2.position.set(0,10,0)
this.scene.add(flyLine);
this.scene.add(flyLine2);
var curve = new THREE.CatmullRomCurve3( [
new THREE.Vector3( -10, 0, 10 ),
new THREE.Vector3( -5, 5, 5 ),
new THREE.Vector3( 0, 0, 0 ),
new THREE.Vector3( 5, -5, 5 ),
new THREE.Vector3( 10, 0, 10 )
],true );
var points = curve.getPoints( 50 );
var geometry = new THREE.BufferGeometry().setFromPoints( points );
var material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
// Create the final object to add to the scene
var curveObject = new THREE.Line( geometry, material );
var curveObject2 = new THREE.Line( geometry, material );
curveObject2.position.set(0,10,0)
this.scene.add(curveObject);
this.scene.add(curveObject2);
// 初始化轨道控制器
// 还需要配合animate,不断循环渲染,达到用鼠标旋转物体的作用。
this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
},
animate() {
requestAnimationFrame(this.animate);
this.renderer.render(this.scene, this.camera);
}
}
}
</script>
<style scoped>
#container {
width: 100%;
height: 600px;
}
</style>
效果:
最后总结一下:
引入js,生成object,将object添加到scene,vue销毁前清理定时器。
|