| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- <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>
|