|
@@ -1,153 +1,176 @@
|
|
|
<template>
|
|
|
- <div class="wave"></div>
|
|
|
+ <div class="wave"></div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
- import * as THREE from 'three';
|
|
|
+import * as THREE from "three";
|
|
|
+import $ from "jquery";
|
|
|
|
|
|
- let scene, camera, renderer, particles;
|
|
|
+let scene, camera, renderer, particles;
|
|
|
|
|
|
- export default {
|
|
|
- // 名称
|
|
|
- name: "wave",
|
|
|
- // 使用组件
|
|
|
- components: {},
|
|
|
- // 传入参数
|
|
|
- props: {},
|
|
|
- // 自定义事件
|
|
|
- emits: {},
|
|
|
- // 数据
|
|
|
- data() {
|
|
|
- return {
|
|
|
- SEPARATION: 100,
|
|
|
- AMOUNTX: 100,
|
|
|
- AMOUNTY: 100,
|
|
|
- count: 0,
|
|
|
- mouseX: 0,
|
|
|
- mouseY: -400,
|
|
|
- windowHalfX: window.innerWidth / 2,
|
|
|
- windowHalfY: window.innerHeight / 2,
|
|
|
- }
|
|
|
+export default {
|
|
|
+ // 名称
|
|
|
+ name: "wave",
|
|
|
+ // 使用组件
|
|
|
+ components: {},
|
|
|
+ // 传入参数
|
|
|
+ props: {},
|
|
|
+ // 自定义事件
|
|
|
+ emits: {},
|
|
|
+ // 数据
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ SEPARATION: 100,
|
|
|
+ AMOUNTX: 100,
|
|
|
+ AMOUNTY: 100,
|
|
|
+ count: 0,
|
|
|
+ mouseX: 0,
|
|
|
+ mouseY: -400,
|
|
|
+ windowHalfX: window.innerWidth / 2,
|
|
|
+ windowHalfY: window.innerHeight / 2,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 函数
|
|
|
+ methods: {
|
|
|
+ init() {
|
|
|
+ camera = new THREE.PerspectiveCamera(
|
|
|
+ 50,
|
|
|
+ window.innerWidth / window.innerHeight,
|
|
|
+ 1,
|
|
|
+ 10000
|
|
|
+ );
|
|
|
+ camera.position.z = 1000;
|
|
|
+ scene = new THREE.Scene();
|
|
|
+ const numParticles = this.AMOUNTX * this.AMOUNTY;
|
|
|
+ const positions = new Float32Array(numParticles * 3);
|
|
|
+ const scales = new Float32Array(numParticles);
|
|
|
+ let i = 0,
|
|
|
+ j = 0;
|
|
|
+ for (let ix = 0; ix < this.AMOUNTX; ix++) {
|
|
|
+ for (let iy = 0; iy < this.AMOUNTY; iy++) {
|
|
|
+ positions[i] =
|
|
|
+ ix * this.SEPARATION - (this.AMOUNTX * this.SEPARATION) / 2; // x
|
|
|
+ positions[i + 1] = 0; // y
|
|
|
+ positions[i + 2] =
|
|
|
+ iy * this.SEPARATION - (this.AMOUNTY * this.SEPARATION) / 2; // z
|
|
|
+ scales[j] = 1;
|
|
|
+ i += 3;
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const geometry = new THREE.BufferGeometry();
|
|
|
+ geometry.setAttribute(
|
|
|
+ "position",
|
|
|
+ new THREE.BufferAttribute(positions, 3)
|
|
|
+ );
|
|
|
+ geometry.setAttribute("scale", new THREE.BufferAttribute(scales, 1));
|
|
|
+ const material = new THREE.ShaderMaterial({
|
|
|
+ uniforms: {
|
|
|
+ color: {
|
|
|
+ value: new THREE.Color(
|
|
|
+ this.$store.state.themeName === "dark" ? 0x05bb4c : 0x36348e
|
|
|
+ ),
|
|
|
+ },
|
|
|
},
|
|
|
- // 函数
|
|
|
- methods: {
|
|
|
- init: function() {
|
|
|
- camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000);
|
|
|
- camera.position.z = 1000;
|
|
|
- scene = new THREE.Scene();
|
|
|
- const numParticles = this.AMOUNTX * this.AMOUNTY;
|
|
|
- const positions = new Float32Array(numParticles * 3);
|
|
|
- const scales = new Float32Array(numParticles);
|
|
|
- let i = 0,
|
|
|
- j = 0;
|
|
|
- for (let ix = 0; ix < this.AMOUNTX; ix++) {
|
|
|
- for (let iy = 0; iy < this.AMOUNTY; iy++) {
|
|
|
- positions[i] = ix * this.SEPARATION - ((this.AMOUNTX * this.SEPARATION) / 2); // x
|
|
|
- positions[i + 1] = 0; // y
|
|
|
- positions[i + 2] = iy * this.SEPARATION - ((this.AMOUNTY * this.SEPARATION) / 2); // z
|
|
|
- scales[j] = 1;
|
|
|
- i += 3;
|
|
|
- j++;
|
|
|
- }
|
|
|
- }
|
|
|
- const geometry = new THREE.BufferGeometry();
|
|
|
- geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
|
|
|
- geometry.setAttribute('scale', new THREE.BufferAttribute(scales, 1));
|
|
|
- const material = new THREE.ShaderMaterial({
|
|
|
- uniforms: {
|
|
|
- color: {
|
|
|
- value: new THREE.Color(0x05bb4c),
|
|
|
- },
|
|
|
- },
|
|
|
- vertexShader: `attribute float scale;
|
|
|
+ vertexShader: `attribute float scale;
|
|
|
void main() {
|
|
|
vec4 mvPosition = modelViewMatrix * vec4( position, 2.0 );
|
|
|
gl_PointSize = scale * ( 200.0 / - mvPosition.z );
|
|
|
gl_Position = projectionMatrix * mvPosition;
|
|
|
}`,
|
|
|
- fragmentShader: `uniform vec3 color;
|
|
|
+ fragmentShader: `uniform vec3 color;
|
|
|
void main() {
|
|
|
if ( length( gl_PointCoord - vec2( 0.5, 0.5 ) ) > 0.475 ) discard;
|
|
|
gl_FragColor = vec4( color, 0.7 );
|
|
|
}`,
|
|
|
- transparent: true,
|
|
|
- });
|
|
|
- particles = new THREE.Points(geometry, material);
|
|
|
- scene.add(particles);
|
|
|
- renderer = new THREE.WebGLRenderer({
|
|
|
- antialias: true,
|
|
|
- alpha: true,
|
|
|
- });
|
|
|
- renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
- renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
- renderer.setAnimationLoop(this.render);
|
|
|
- this.$el.appendChild(renderer.domElement);
|
|
|
- },
|
|
|
- render: function() {
|
|
|
- camera.position.x += (this.mouseX - camera.position.x) * .05;
|
|
|
- camera.position.y += (-this.mouseY - camera.position.y) * .05;
|
|
|
- camera.lookAt(scene.position);
|
|
|
- const positions = particles.geometry.attributes.position.array;
|
|
|
- const scales = particles.geometry.attributes.scale.array;
|
|
|
- let i = 0,
|
|
|
- j = 0;
|
|
|
- for (let ix = 0; ix < this.AMOUNTX; ix++) {
|
|
|
- for (let iy = 0; iy < this.AMOUNTY; iy++) {
|
|
|
- positions[i + 1] = (Math.sin((ix + this.count) * 0.3) * 50) +
|
|
|
- (Math.sin((iy + this.count) * 0.5) * 50);
|
|
|
- scales[j] = (Math.sin((ix + this.count) * 0.3) + 1) * 20 +
|
|
|
- (Math.sin((iy + this.count) * 0.5) + 1) * 20;
|
|
|
- i += 3;
|
|
|
- j++;
|
|
|
- }
|
|
|
- }
|
|
|
- particles.geometry.attributes.position.needsUpdate = true;
|
|
|
- particles.geometry.attributes.scale.needsUpdate = true;
|
|
|
- renderer.render(scene, camera);
|
|
|
- this.count += 0.1;
|
|
|
- }
|
|
|
- },
|
|
|
- // 生命周期钩子
|
|
|
- beforeCreate() {
|
|
|
- // 创建前
|
|
|
- },
|
|
|
- created() {
|
|
|
- // 创建后
|
|
|
- },
|
|
|
- beforeMount() {
|
|
|
- // 渲染前
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- // 渲染后
|
|
|
- camera = null;
|
|
|
- scene = null;
|
|
|
- renderer = null;
|
|
|
- this.init();
|
|
|
- },
|
|
|
- beforeUpdate() {
|
|
|
- // 数据更新前
|
|
|
- },
|
|
|
- updated() {
|
|
|
- // 数据更新后
|
|
|
- },
|
|
|
- beforeUnmount() {
|
|
|
- // 销毁前
|
|
|
- renderer.setAnimationLoop(null);
|
|
|
- camera = null;
|
|
|
- scene = null;
|
|
|
- renderer = null;
|
|
|
- },
|
|
|
- }
|
|
|
+ transparent: true,
|
|
|
+ });
|
|
|
+ particles = new THREE.Points(geometry, material);
|
|
|
+ scene.add(particles);
|
|
|
+ renderer = new THREE.WebGLRenderer({
|
|
|
+ antialias: true,
|
|
|
+ alpha: true,
|
|
|
+ });
|
|
|
+ renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
+ renderer.setPixelRatio(window.devicePixelRatio);
|
|
|
+ renderer.setAnimationLoop(this.render);
|
|
|
+ this.$el.appendChild(renderer.domElement);
|
|
|
+ },
|
|
|
+ render() {
|
|
|
+ camera.position.x += (this.mouseX - camera.position.x) * 0.05;
|
|
|
+ camera.position.y += (-this.mouseY - camera.position.y) * 0.05;
|
|
|
+ camera.lookAt(scene.position);
|
|
|
+ const positions = particles.geometry.attributes.position.array;
|
|
|
+ const scales = particles.geometry.attributes.scale.array;
|
|
|
+ let i = 0,
|
|
|
+ j = 0;
|
|
|
+ for (let ix = 0; ix < this.AMOUNTX; ix++) {
|
|
|
+ for (let iy = 0; iy < this.AMOUNTY; iy++) {
|
|
|
+ positions[i + 1] =
|
|
|
+ Math.sin((ix + this.count) * 0.3) * 50 +
|
|
|
+ Math.sin((iy + this.count) * 0.5) * 50;
|
|
|
+ scales[j] =
|
|
|
+ (Math.sin((ix + this.count) * 0.3) + 1) * 20 +
|
|
|
+ (Math.sin((iy + this.count) * 0.5) + 1) * 20;
|
|
|
+ i += 3;
|
|
|
+ j++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ particles.geometry.attributes.position.needsUpdate = true;
|
|
|
+ particles.geometry.attributes.scale.needsUpdate = true;
|
|
|
+ renderer.render(scene, camera);
|
|
|
+ this.count += 0.1;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ // 生命周期钩子
|
|
|
+ beforeCreate() {
|
|
|
+ // 创建前
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ // 创建后
|
|
|
+ },
|
|
|
+ beforeMount() {
|
|
|
+ // 渲染前
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 渲染后
|
|
|
+ camera = null;
|
|
|
+ scene = null;
|
|
|
+ renderer = null;
|
|
|
+ this.init();
|
|
|
+ },
|
|
|
+ beforeUpdate() {
|
|
|
+ // 数据更新前
|
|
|
+ },
|
|
|
+ updated() {
|
|
|
+ // 数据更新后
|
|
|
+ },
|
|
|
+ beforeUnmount() {
|
|
|
+ // 销毁前
|
|
|
+ renderer.setAnimationLoop(null);
|
|
|
+ camera = null;
|
|
|
+ scene = null;
|
|
|
+ renderer = null;
|
|
|
+ },
|
|
|
+
|
|
|
+ watch: {
|
|
|
+ "$store.state.themeName"() {
|
|
|
+ $(".wave").empty();
|
|
|
+ renderer.setAnimationLoop(null);
|
|
|
+ this.init();
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<style lang="less">
|
|
|
- .wave {
|
|
|
- position: absolute;
|
|
|
- left: 0;
|
|
|
- top: 0;
|
|
|
- width: 100%;
|
|
|
- height: 60%;
|
|
|
- z-index: -1;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
+.wave {
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 60%;
|
|
|
+ z-index: -1;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
</style>
|