<template>
  <div>
    <canvas ref="webgl" class="webgl"></canvas>
  </div>
</template>

<script>
import * as THREE from 'three'

export default {
  name: "WebGLComponent",
  data() {
    return {
      mouseX: 0,  // 鼠标的X坐标，用于追踪鼠标移动
      mouseY: 0   // 鼠标的Y坐标
    };
  },
  mounted() {
    this.initWebGL();  // 组件加载完成后，初始化WebGL
  },
  methods: {
    // 初始化WebGL的方法
    initWebGL() {
      const canvas = this.$refs.webgl;  // 获取canvas元素
      canvas.width = window.innerWidth;  // 设置canvas的宽度为窗口宽度
      canvas.height = window.innerHeight;  // 设置canvas的高度为窗口高度

      const gl = canvas.getContext("webgl");  // 获取WebGL上下文

      // 顶点着色器源代码
      const vertexShaderSource = `
        attribute vec4 position;  // 顶点位置
        attribute float scale;  // 顶点大小
        uniform mat4 modelViewMatrix;  // 视图矩阵
        uniform mat4 projectionMatrix;  // 投影矩阵
        void main() {
          vec4 mvPosition = modelViewMatrix * position;  // 计算模型视图变换后的顶点位置
          gl_PointSize = scale * 1.0 * (200.0 / - mvPosition.z);  // 根据深度调整点的大小
          gl_Position = projectionMatrix * mvPosition;  // 最终的顶点位置
        }
      `;

      // 片段着色器源代码
      const fragShaderSource = `
        void main() {
          if (length(gl_PointCoord - vec2(0.5, 0.5)) > 0.49) discard;  // 如果超出圆形范围，则丢弃
          gl_FragColor = vec4(1.0, 0.51, 0.65, 1.0);  // 设置点的颜色
        }
      `;

      // 初始化着色器程序
      const program = this.initShader(gl, vertexShaderSource, fragShaderSource);

      // 获取着色器中属性和uniform的位置
      const aposLocation = gl.getAttribLocation(program, 'position');
      const scale = gl.getAttribLocation(program, 'scale');
      const modelViewMatrixLoc = gl.getUniformLocation(program, 'modelViewMatrix');
      const projectionMatrixLoc = gl.getUniformLocation(program, 'projectionMatrix');

      // 粒子系统的参数
      const SEPARATION = 100, AMOUNTX = 50, AMOUNTY = 50;
      const numParticles = AMOUNTX * AMOUNTY;

      // 存储粒子的位置和大小
      const positions = new Float32Array(numParticles * 3);
      const scales = new Float32Array(numParticles);

      let i = 0, j = 0;
      // 初始化粒子的位置和大小
      for (let ix = 0; ix < AMOUNTX; ix++) {
        for (let iy = 0; iy < AMOUNTY; iy++) {
          positions[i] = ix * SEPARATION - ((AMOUNTX * SEPARATION) / 2); // x
          positions[i + 1] = 0; // y
          positions[i + 2] = iy * SEPARATION - ((AMOUNTY * SEPARATION) / 2); // z
          scales[j] = 1;  // 默认大小
          i += 3;
          j++;
        }
      }

      // 创建颜色缓冲区
      const colorBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, scales, gl.STATIC_DRAW);
      gl.vertexAttribPointer(scale, 1, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray(scale);

      // 创建位置缓冲区
      const buffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
      gl.vertexAttribPointer(aposLocation, 3, gl.FLOAT, false, 0, 0);
      gl.enableVertexAttribArray(aposLocation);

      // 开启深度测试
      gl.enable(gl.DEPTH_TEST);

      // 初始化相机
      const width = window.innerWidth;
      const height = window.innerHeight;
      const camera = new THREE.PerspectiveCamera(60, width / height, 1, 10000);
      camera.position.set(944, 206, -262);  // 设置相机位置
      camera.lookAt(new THREE.Vector3(0, 0, 0));  // 设置相机朝向
      camera.updateProjectionMatrix();  // 更新相机的投影矩阵
      camera.updateMatrixWorld(true);  // 更新相机的世界矩阵

      // 将相机的投影矩阵传递给WebGL
      const mat4 = new THREE.Matrix4();
      mat4.copy(camera.projectionMatrix);
      const mxArr = new Float32Array(mat4.elements);
      gl.uniformMatrix4fv(projectionMatrixLoc, false, mxArr);

      // 将相机的反向矩阵传递给WebGL
      const mat4y = new THREE.Matrix4();
      mat4y.copy(camera.matrixWorldInverse);
      const myArr = new Float32Array(mat4y.elements);
      gl.uniformMatrix4fv(modelViewMatrixLoc, false, myArr);

      let count = 0;

      // 动画绘制函数
      const draw = () => {
        // 根据鼠标位置更新相机的位置
        camera.position.x += (this.mouseX - camera.position.x) * 0.01;
        camera.updateMatrixWorld(true);  // 更新相机世界矩阵
        mat4y.copy(camera.matrixWorldInverse);  // 获取更新后的相机反向矩阵
        const myArr = new Float32Array(mat4y.elements);
        gl.uniformMatrix4fv(modelViewMatrixLoc, false, myArr);  // 传递新的矩阵给WebGL

        // 更新粒子的位置和大小
        let i = 0, j = 0;
        for (let ix = 0; ix < AMOUNTX; ix++) {
          for (let iy = 0; iy < AMOUNTY; iy++) {
            positions[i + 1] = (Math.sin((ix + count) * 0.3) * 50) + (Math.sin((iy + count) * 0.5) * 50);
            scales[j] = (Math.sin((ix + count) * 0.3) + 1.3) * 8 + (Math.sin((iy + count) * 0.5) + 1.3) * 8;
            i += 3;
            j++;
          }
        }
        count += 0.1;

        // 更新缓冲区的数据
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, scales, gl.STATIC_DRAW);
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

        requestAnimationFrame(draw);  // 请求下一帧绘制
        gl.drawArrays(gl.POINTS, 0, 2500);  // 绘制粒子
      };

      draw();  // 启动绘制

      // 监听鼠标和触摸事件
      document.addEventListener('mousemove', this.onDocumentMouseMove, false);
      document.addEventListener('touchstart', this.onDocumentTouchStart, false);
      document.addEventListener('touchmove', this.onDocumentTouchMove, false);

      // 监听窗口大小变化，更新画布和相机的投影矩阵
      window.onresize = () => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        gl.viewport(0, 0, window.innerWidth, window.innerHeight);
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        mat4.copy(camera.projectionMatrix);
        const mxArr = new Float32Array(mat4.elements);
        gl.uniformMatrix4fv(projectionMatrixLoc, false, mxArr);
      };
    },

    // 初始化着色器的方法
    initShader(gl, vertexShaderSource, fragmentShaderSource) {
      const vertexShader = gl.createShader(gl.VERTEX_SHADER);
      const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(vertexShader, vertexShaderSource);
      gl.shaderSource(fragmentShader, fragmentShaderSource);
      gl.compileShader(vertexShader);
      gl.compileShader(fragmentShader);
      const program = gl.createProgram();
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
      gl.linkProgram(program);
      gl.useProgram(program);
      return program;
    },

    // 鼠标移动事件处理
    onDocumentMouseMove(event) {
      this.mouseX = event.clientX - window.innerWidth / 2;
      this.mouseY = event.clientY - window.innerHeight / 2;
      
    },

    // 触摸开始事件处理
    onDocumentTouchStart(event) {
      if (event.touches.length === 1) {
        event.preventDefault();
        this.mouseX = event.touches[0].pageX - window.innerWidth / 2;
        this.mouseY = event.touches[0].pageY - window.innerHeight / 2;
      }
    },

    // 触摸移动事件处理
    onDocumentTouchMove(event) {
      if (event.touches.length === 1) {
        event.preventDefault();
        this.mouseX = event.touches[0].pageX - window.innerWidth / 2;
        this.mouseY = event.touches[0].pageY - window.innerHeight / 2;
      }
    }
  }
};
</script>

<style scoped>
body {
  padding: 0;
  margin: 0;
  background-color: transparent;
  font-family: "微软雅黑";
  overflow: hidden;
}

.webgl {
  position: absolute;
  bottom: 0;
  left: 0;
  /* height: 100%; */
  background-color: transparent;
  width: 100%;
}
</style>
