「这是我参与2022首次更文挑战的第29天,活动详情查看:2022首次更文挑战」
在开始绘制之前,得先知道基本的坐标转换。体验链接
坐标转换
1. 2dcanvas坐标系,也是dom坐标系.
原点: 左上角。 当画布的左上角和window的左上角重合时其坐标就是pageX,pageY,
x轴水平向右,一个单位分量是1px 逻辑像素
y轴竖直向下, 一个单位分量是1px 逻辑像素
2 webgl 剪裁空间
原点: 画布中心。
x轴水平向右,一个单位分量是二分之一画布的宽。
y轴竖直向上, 一个单位分量是画布高的一半 。
z轴垂直屏幕朝里, 也就是说z值越大点位越在下面,其单位分量不明
开始转换
坐标转换,已知条件单位都是px。
已知左上角(x1,y1) 画布高2H,宽2W, 鼠标点位(x,y), 求其在裁剪空间中的xy坐标
2d坐标中, 坐标原点就是(x1+W, y1+ H ), 鼠标点相对坐标原点的向量就是 (x-x1-w, y- y1-H),这是2d坐标系中的向量,
然后我们需要, 翻转Y轴,所以就变为 (x-x1-w, y1+H-y),
单位换算, 所以就变为 ((x-x1-w)/w, (y1+H-y)/H )
细心的同学可能发现这并不是他熟悉的右手坐标系,因为我们平常所使用的坐标系,都需要经过投影变换为剪裁坐标系。所以我们还是使用右手坐标系。
开始绘制
绘制的逻辑就相对简单了,一般来说画布尺寸是不会超出浏览器可视区域的,因为不便操作。 我们基本逻辑就是,监听鼠标点击事件,然后把事件里的坐标转换为webgl坐标。 然后就把这个点追加到我们连续绘图的数据里。
连续绘图绘制线段,也就是一次绘制多点,必须使用缓冲区。source是点位数据
gl.bindBuffer(gl.ARRAY_BUFFER, sourceBuffer) gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(source), gl.STATIC_DRAW)
每次,添加数据之后都要重新 gl.vertexAttribPointer(index, size, type, normalized, stride, offset)。 唯一变化的就是绘制点位数量。 gl.drawArrays(gl.LINE_STRIP, 0, n) .
这个n就是点位数量。
后续优化, 还可以加上结束绘制的逻辑,用右键结束绘制。因此需要一个状态,表示当前是否处于绘制状态。
还可以加上一个已经绘制的点的逻辑,当新绘制的点和已绘制的点十分接近就采用之前的点位数据。 还可以加上是否开启多种绘制模式。目前只能绘制直线,而且斜直线会有锯齿,如果想绘制曲线,大致思路是采用控制点,用贝塞尔曲线把全部组需要的点位计算出来,然后进行绘制。