|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div>
|
|
|
|
|
|
|
+ <div class="canvas-backend" aria-hidden="true">
|
|
|
<canvas ref="webgl" class="webgl"></canvas>
|
|
<canvas ref="webgl" class="webgl"></canvas>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
@@ -8,226 +8,196 @@
|
|
|
import * as THREE from 'three'
|
|
import * as THREE from 'three'
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
|
- name: "WebGLComponent",
|
|
|
|
|
|
|
+ name: 'WebGLComponent',
|
|
|
data() {
|
|
data() {
|
|
|
return {
|
|
return {
|
|
|
- mouseX: 0, // 鼠标的X坐标,用于追踪鼠标移动
|
|
|
|
|
- mouseY: 0 // 鼠标的Y坐标
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ mouseX: 0,
|
|
|
|
|
+ mouseY: 0
|
|
|
|
|
+ }
|
|
|
},
|
|
},
|
|
|
mounted() {
|
|
mounted() {
|
|
|
- this.initWebGL(); // 组件加载完成后,初始化WebGL
|
|
|
|
|
|
|
+ this.initWebGL()
|
|
|
|
|
+ },
|
|
|
|
|
+ beforeUnmount() {
|
|
|
|
|
+ document.removeEventListener('mousemove', this.onDocumentMouseMove, false)
|
|
|
|
|
+ document.removeEventListener('touchstart', this.onDocumentTouchStart, false)
|
|
|
|
|
+ document.removeEventListener('touchmove', this.onDocumentTouchMove, false)
|
|
|
},
|
|
},
|
|
|
methods: {
|
|
methods: {
|
|
|
- // 初始化WebGL的方法
|
|
|
|
|
initWebGL() {
|
|
initWebGL() {
|
|
|
- const canvas = this.$refs.webgl; // 获取canvas元素
|
|
|
|
|
- canvas.width = window.innerWidth; // 设置canvas的宽度为窗口宽度
|
|
|
|
|
- canvas.height = window.innerHeight; // 设置canvas的高度为窗口高度
|
|
|
|
|
|
|
+ const canvas = this.$refs.webgl
|
|
|
|
|
+ if (!canvas) return
|
|
|
|
|
+
|
|
|
|
|
+ canvas.width = window.innerWidth
|
|
|
|
|
+ canvas.height = window.innerHeight
|
|
|
|
|
|
|
|
- const gl = canvas.getContext("webgl"); // 获取WebGL上下文
|
|
|
|
|
|
|
+ const gl = canvas.getContext('webgl')
|
|
|
|
|
+ if (!gl) return
|
|
|
|
|
|
|
|
- // 顶点着色器源代码
|
|
|
|
|
const vertexShaderSource = `
|
|
const vertexShaderSource = `
|
|
|
- attribute vec4 position; // 顶点位置
|
|
|
|
|
- attribute float scale; // 顶点大小
|
|
|
|
|
- uniform mat4 modelViewMatrix; // 视图矩阵
|
|
|
|
|
- uniform mat4 projectionMatrix; // 投影矩阵
|
|
|
|
|
|
|
+ attribute vec4 position;
|
|
|
|
|
+ attribute float scale;
|
|
|
|
|
+ uniform mat4 modelViewMatrix;
|
|
|
|
|
+ uniform mat4 projectionMatrix;
|
|
|
void main() {
|
|
void main() {
|
|
|
- vec4 mvPosition = modelViewMatrix * position; // 计算模型视图变换后的顶点位置
|
|
|
|
|
- gl_PointSize = scale * 1.0 * (200.0 / - mvPosition.z); // 根据深度调整点的大小
|
|
|
|
|
- gl_Position = projectionMatrix * mvPosition; // 最终的顶点位置
|
|
|
|
|
|
|
+ vec4 mvPosition = modelViewMatrix * position;
|
|
|
|
|
+ gl_PointSize = scale * 1.0 * (200.0 / - mvPosition.z);
|
|
|
|
|
+ gl_Position = projectionMatrix * mvPosition;
|
|
|
}
|
|
}
|
|
|
- `;
|
|
|
|
|
|
|
+ `
|
|
|
|
|
|
|
|
- // 片段着色器源代码
|
|
|
|
|
const fragShaderSource = `
|
|
const fragShaderSource = `
|
|
|
void main() {
|
|
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); // 设置点的颜色
|
|
|
|
|
|
|
+ if (length(gl_PointCoord - vec2(0.5, 0.5)) > 0.49) discard;
|
|
|
|
|
+ gl_FragColor = vec4(0.32, 0.72, 0.47, 0.35);
|
|
|
}
|
|
}
|
|
|
- `;
|
|
|
|
|
|
|
+ `
|
|
|
|
|
|
|
|
- // 初始化着色器程序
|
|
|
|
|
- const program = this.initShader(gl, vertexShaderSource, fragShaderSource);
|
|
|
|
|
|
|
+ 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 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 SEPARATION = 100
|
|
|
|
|
+ const AMOUNTX = 50
|
|
|
|
|
+ const AMOUNTY = 50
|
|
|
|
|
|
|
|
- // 存储粒子的位置和大小
|
|
|
|
|
- const positions = new Float32Array(numParticles * 3);
|
|
|
|
|
- const scales = new Float32Array(numParticles);
|
|
|
|
|
|
|
+ const positions = new Float32Array(AMOUNTX * AMOUNTY * 3)
|
|
|
|
|
+ const scales = new Float32Array(AMOUNTX * AMOUNTY)
|
|
|
|
|
|
|
|
- let i = 0, j = 0;
|
|
|
|
|
- // 初始化粒子的位置和大小
|
|
|
|
|
|
|
+ let i = 0
|
|
|
|
|
+ let j = 0
|
|
|
for (let ix = 0; ix < AMOUNTX; ix++) {
|
|
for (let ix = 0; ix < AMOUNTX; ix++) {
|
|
|
for (let iy = 0; iy < AMOUNTY; iy++) {
|
|
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++;
|
|
|
|
|
|
|
+ positions[i] = ix * SEPARATION - (AMOUNTX * SEPARATION) / 2
|
|
|
|
|
+ positions[i + 1] = 0
|
|
|
|
|
+ positions[i + 2] = iy * SEPARATION - (AMOUNTY * SEPARATION) / 2
|
|
|
|
|
+ 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 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)
|
|
|
|
|
+
|
|
|
|
|
+ const mat4 = new THREE.Matrix4()
|
|
|
|
|
+ mat4.copy(camera.projectionMatrix)
|
|
|
|
|
+ gl.uniformMatrix4fv(projectionMatrixLoc, false, new Float32Array(mat4.elements))
|
|
|
|
|
+
|
|
|
|
|
+ const mat4y = new THREE.Matrix4()
|
|
|
|
|
+ mat4y.copy(camera.matrixWorldInverse)
|
|
|
|
|
+ gl.uniformMatrix4fv(modelViewMatrixLoc, false, new Float32Array(mat4y.elements))
|
|
|
|
|
+
|
|
|
|
|
+ let count = 0
|
|
|
|
|
+ let rafId = null
|
|
|
|
|
+
|
|
|
const draw = () => {
|
|
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;
|
|
|
|
|
|
|
+ camera.position.x += (this.mouseX - camera.position.x) * 0.01
|
|
|
|
|
+ camera.updateMatrixWorld(true)
|
|
|
|
|
+ mat4y.copy(camera.matrixWorldInverse)
|
|
|
|
|
+ gl.uniformMatrix4fv(modelViewMatrixLoc, false, new Float32Array(mat4y.elements))
|
|
|
|
|
+
|
|
|
|
|
+ let pi = 0
|
|
|
|
|
+ let pj = 0
|
|
|
for (let ix = 0; ix < AMOUNTX; ix++) {
|
|
for (let ix = 0; ix < AMOUNTX; ix++) {
|
|
|
for (let iy = 0; iy < AMOUNTY; iy++) {
|
|
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++;
|
|
|
|
|
|
|
+ positions[pi + 1] =
|
|
|
|
|
+ Math.sin((ix + count) * 0.3) * 50 + Math.sin((iy + count) * 0.5) * 50
|
|
|
|
|
+ scales[pj] =
|
|
|
|
|
+ (Math.sin((ix + count) * 0.3) + 1.3) * 8 + (Math.sin((iy + count) * 0.5) + 1.3) * 8
|
|
|
|
|
+ pi += 3
|
|
|
|
|
+ pj++
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- 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);
|
|
|
|
|
- };
|
|
|
|
|
|
|
+ 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)
|
|
|
|
|
+
|
|
|
|
|
+ rafId = requestAnimationFrame(draw)
|
|
|
|
|
+ gl.drawArrays(gl.POINTS, 0, AMOUNTX * AMOUNTY)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ draw()
|
|
|
|
|
+
|
|
|
|
|
+ this._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)
|
|
|
|
|
+ gl.uniformMatrix4fv(projectionMatrixLoc, false, new Float32Array(mat4.elements))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ window.addEventListener('resize', this._onResize)
|
|
|
|
|
+ document.addEventListener('mousemove', this.onDocumentMouseMove, false)
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
- // 初始化着色器的方法
|
|
|
|
|
initShader(gl, vertexShaderSource, fragmentShaderSource) {
|
|
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;
|
|
|
|
|
|
|
+ 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) {
|
|
onDocumentMouseMove(event) {
|
|
|
- this.mouseX = event.clientX - window.innerWidth / 2;
|
|
|
|
|
- this.mouseY = event.clientY - window.innerHeight / 2;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ 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;
|
|
|
|
|
- }
|
|
|
|
|
- },
|
|
|
|
|
|
|
+ onDocumentTouchStart() {},
|
|
|
|
|
|
|
|
- // 触摸移动事件处理
|
|
|
|
|
- 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;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ onDocumentTouchMove() {}
|
|
|
}
|
|
}
|
|
|
-};
|
|
|
|
|
|
|
+}
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
|
-body {
|
|
|
|
|
- padding: 0;
|
|
|
|
|
- margin: 0;
|
|
|
|
|
- background-color: transparent;
|
|
|
|
|
- font-family: "微软雅黑";
|
|
|
|
|
|
|
+.canvas-backend {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ inset: 0;
|
|
|
|
|
+ z-index: 0;
|
|
|
|
|
+ pointer-events: none;
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.webgl {
|
|
.webgl {
|
|
|
- position: absolute;
|
|
|
|
|
- bottom: 0;
|
|
|
|
|
- left: 0;
|
|
|
|
|
- /* height: 100%; */
|
|
|
|
|
- background-color: transparent;
|
|
|
|
|
|
|
+ display: block;
|
|
|
width: 100%;
|
|
width: 100%;
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ pointer-events: none;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|