鼠标交互
鼠标控制物体旋转
简单实现思路
一句话:根据鼠标移动情况更新作用于物体顶点旋转矩阵。
这是当鼠标左键按下时会发生的一些操作:
- 记录鼠标左键 初始坐标
- 鼠标移动时获取 当前坐标
- 当前坐标减去初始坐标获得 鼠标位移
- 根据位移计算 旋转矩阵
- 根据旋转矩阵 更新顶点位置
RotateObject Code
1 | let VSHADER_SOURCE = ` |
1 | function main() { |
1 | let g_MvpMatrix = new Matrix4(); |
1 | function initVertexBuffers(gl) { |
1 | function initTextures(gl) { |
1 | function initEventHandlers(canvas,currentAngle) { |
选中物体
思考一下:如何使用数学过程来计算鼠标是否悬浮在某个图形上?
简单实现思路
一句话:魔术把戏,利用超出人眼反应速度的刷新帧数来对物体进行切换。
- 鼠标左键按下时:将立方体重绘为 单色 (假设红色)
- 读取鼠标点击处的 像素颜色
- 如果读取的颜色是 红色 ,就判断物体被选中
- 将纯色立方体 复原重绘 成原来的纹理
PickObject Code
1 | let VSHADER_SOURCE = ` |
1 | function main() { |
1 | function check(gl, n, x, y, currentAngle, u_Clicked, vpMatrix, u_MvpMatrix) { |
1 | let g_MvpMatrix = new Matrix4(); |
1 | function initVertexBuffers(gl) { |
程序分析
readPixels读取点击处像素颜色
- 读取来源是 颜色缓冲区
- 读取位置由 x、y 确定
- 读取大小由 width、height 确定
- 读取结果存放在 pixels 中
- pixels 必须是 Uint8Array 类型的数组
注意:
对于绑定在 gl.FRAMEBUFFER 上的 帧缓冲区对象,
readPixels读取的是 帧缓冲区 ,而非颜色缓冲区。
通过阻塞代码运行观察重绘前的立方体
通过指定颜色判断是否选中物体方法的局限
如果场景中有很多的物体,可以 为每个物体分配一个唯一的颜色值。
颜色缓冲区中:RGBA 每个分量都是8bit。
那么RGBA一共就可以表示 32bit,
也就是可以区分 2^32 种物体。
其他判断物体选中的方法
- 使用简化的模型
- 缩小绘图区域
- 使用帧缓冲区对象
选中一个表面
实际上使用的是和PickObject同样的方法
与PickObject不同的地方在
用户点击鼠标重绘立方体时,
将 每个像素属于哪个面 的信息写入到 颜色缓冲区 的 α分量 中。
即鼠标点击事件被触发之后,不是将物体颜色进行重写,
而是使用指定值对颜色透明度通道进行重写,
当然也可以对其它通道进行与立方体面序号绑定的重写。
PickFace Code
1 | let VSHADER_SOURCE = ` |
1 | function main() { |
为什么在着色器中需要对a_Face进行强制转换?
1 | attribute float a_Face; |
答: 因为 attribute 类型的变量不支持 int 类型,并且需要与 int类型 的 u_PickedFace 进行比较。
1 | uniform int u_PickedFace; |
注意:在之后计算 α通道数值 的时候使用的是 未经转换的a_Face 。
1 | v_Color = vec4( color, a_Face/255.0); |