在WebGL中给页面绑定点击事件,可以通过为WebGL的绘图上下文所在的<canvas>元素添加事件监听器来实现点击事件的处理。
1. 画布添加点击事件
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
ctx.onclick = function (e) {
// 给canvas添加点击事件
}
2. 获取坐标位置
getBoundingClientRect的top和left,等同于offsetTop和offsetLeft,即canvas边框到屏幕的距离
const domPosition = e.target.getBoundingClientRect();
3. 将画布的宽高转换成坐标
// 1.获取鼠标相对于浏览器的坐标
const x = e.clientX;
const y = e.clientY;
// 2.获取画布边框到浏览器的距离
const domPosition = e.target.getBoundingClientRect();
// 3.鼠标点击位置到canvas边框的距离
const domx = x - domPosition.left;
const domy = y - domPosition.top;
// 4.转换坐标的公式:
// 水平坐标=当前鼠标点击的坐标x-当前画布的一半,再除以当前画布的一半
// 垂直坐标=当前画布的一半-当前鼠标点击的坐标y,再除以当前画布的一半
const halfWidth = ctx.offsetWidth / 2;
const halfHeigth = ctx.offsetHeight / 2;
const clickX = (domx - halfWidth) / halfWidth;
const clickY = (halfHeigth - domy) / halfHeigth;
4. 根据坐标在画布上绘制点
// 两个坐标点就用vertexAttrib2f
gl.vertexAttrib2f(aPosition, clickX, clickY)
gl.drawArrays(gl.POINTS, 0, 1);
5. 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
}
canvas {
margin: 50px auto;
display: block;
background: pink;
}
</style>
<title>webgl三维坐标系</title>
</head>
<body>
<canvas id="canvas" width="400" height="400">
此浏览器不支持canvas
</canvas>
<script>
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 顶点着色器源码
const vertexShaderSource = `
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
gl_PointSize = 5.0;
}`
// 片源着色器源码
const fragmentShaderSource = `
void main() {
gl_FragColor = vec4(0.0,0.0,0.0,1.0); // r, g, b, a
}`
// 设置着色器封装后,直接使用
const program = initShader(gl, vertexShaderSource, fragmentShaderSource)
// 返回变量的存储地址
const aPosition = gl.getAttribLocation(program, 'aPosition');
// 着色器方法
function 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 points = [];
// 1.给canvas添加点击事件
ctx.onclick = function (e) {
// 2.获取坐标位置
const x = e.clientX;
const y = e.clientY;
// getBoundingClientRect的x和y,等同于offsetTop和offsetLeft,即canvas边框到屏幕的距离
const domPosition = e.target.getBoundingClientRect();
console.log(domPosition, ctx.offsetTop, ctx.offsetLeft)
console.log(x, y)
// 鼠标点击位置到canvas边框的距离
const domx = x - domPosition.left;
const domy = y - domPosition.top;
// 3.将获取当前画布的宽(0,200,400)转换成坐标(-1,0,1);画布的高(0,200,400)转换成坐标(1,0,-1);
// 首先:获取画布宽高,除以2,得到原点到边框的距离,也就是一半的宽和高。
// 其次:获取点击后得到的宽 减去 一半的宽,再除以一半的宽。
// 最后:一半的高 减去 获取点击后得到的高,再除以一半的高。
const halfWidth = ctx.offsetWidth / 2;
const halfHeigth = ctx.offsetHeight / 2;
const clickX = (domx - halfWidth) / halfWidth;
const clickY = (halfHeigth - domy) / halfHeigth;
console.log(clickX, clickY);
// 4.使用坐标在画布上绘制点
// gl.vertexAttrib2f(aPosition, clickX, clickY) // 两个坐标点就用vertexAttrib2f
// gl.drawArrays(gl.POINTS, 0, 1);
// 5.绘制多的点
points.push({ clickX, clickY })
points.forEach(element => {
gl.vertexAttrib2f(aPosition, element.clickX, element.clickY) // 两个坐标点就用vertexAttrib2f
gl.drawArrays(gl.POINTS, 0, 1);
});
}
</script>
</body>
</html>