threejs:流光效果封装

在网上看到的这种流光效果,在某宝买了源码后,决定把这个效果封装成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销毁前清理定时器。

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值