在WebGL中给页面绑定点击事件,可以通过为WebGL的绘图上下文所在的<canvas>元素添加事件监听器来实现点击事件的处理。
1. 画布添加点击事件
javascript">const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')ctx.onclick = function (e) {// 给canvas添加点击事件
}
2. 获取坐标位置
getBoundingClientRect的top和left,等同于offsetTop和offsetLeft,即canvas边框到屏幕的距离
javascript">const domPosition = e.target.getBoundingClientRect();
3. 将画布的宽高转换成坐标
javascript">// 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. 根据坐标在画布上绘制点
javascript">// 两个坐标点就用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) // 两个坐标点就用vertexAttrib2fgl.drawArrays(gl.POINTS, 0, 1);});}</script>
</body></html>