经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » WebGL » 查看文章
WebGL之物体选择
来源:cnblogs  作者:Jeff.Zhong  时间:2019/5/30 8:50:24  对本文有异议

原文地址: WebGL之物体选择
使用WebGL将图形绘制到画布后,如何与外部进行交互?这其中最关键的就是如何实现物体的选择。比如鼠标点击后判断是否选中了某个图形或图形的某个部分。

本节实现的效果: WebGL选中物体
WebGL选中物体

如何实现选中物体

颜色区分法

《WebGL编程指南》中提出了一个原理很简单的解决方案,步骤如下:

  1. 鼠标按下时物体重绘为红色或其他能区分的颜色

  2. 读取鼠标点击处像素的颜色

    1. gl.readPixels(x,y,width,height,format,type,pixels)
  3. 使用物体原来的颜色进行重绘,以恢复物体本来颜色

  4. 判断第2步读取到的颜色是否与预设的颜色值相等,相等则表示点击中物体

可以说这是个非常容易实现的方案,不过要为每个物体分别设置不同的区分颜色却是个隐患,同时也不够友好。

光线投射法

这是使用最广泛也最精确的一种方案了,Three.js 中的光线投射器 (Raycaster) 就实现了这种方案,可以看里面的源代码。
光线投射
它的基本原理: 从视点出发的光线首先投射到近截面,最后投射到远截面,结合鼠标点击的位置 (x, y) 和视图投影矩阵 (viewProjection)。可以得出由近截面坐标 (x1, y1, z1) 和远截面坐标 (x2, y2, z2) 组成的光线向量。然后我们就可以将物体坐标构成的面逐个与这个光线向量进行对比。首先对比盒子边界,再对比三角形面,这中间涉及到法向量,点积,叉积的计算,那叫一个复杂。

投影坐标判断法

目前对光线投射的具体实现理解地不是很透彻,那我就只能通过自己的理解来实现个简单版的方案。基本原理就是,用视图投影模型矩阵 (mvp) 对图形坐标进行变换,得到在屏幕中的绘制坐标(xyz)。然后遍历每个坐标得出一个由最大最小xy坐标 (xmax, xmin, ymax, ymin) 构成的二维平面盒子。最后与鼠标位置 (x, y) 进行比较,如果鼠标xy坐标处于盒子边界之内,那么就可判断选中了该物体。核心代码如下:

  1. canvas.addEventListener('mousemove', function(e) {
  2. //坐标转换为webgl表示区间
  3. const pos = util.windowToWebgl(tCanvas,e.clientX,e.clientY);
  4. const ps = [];
  5. Polygons.forEach((p,i)=>{
  6. //重置状态
  7. p.select = false;
  8. //mvp矩阵
  9. const matrix = m4.translate(viewProjection, p.pos);
  10. let xmax, ymax, xmin, ymin;//盒子的边界
  11. //遍历顶点获取盒子的边界
  12. for(let j = 0; j < p.position.length; j = j+3){
  13. //对坐标进行矩阵转换
  14. const s = m4.transformPoint(matrix, p.position.slice(j,j+3));
  15. if(j == 0){
  16. xmax = s[0];
  17. xmin = s[0];
  18. ymax = s[1];
  19. ymin = s[1];
  20. continue;
  21. }
  22. if(s[0]>xmax) xmax = s[0];
  23. if(s[0]<xmin) xmin = s[0];
  24. if(s[1]>ymax) ymax = s[1];
  25. if(s[1]<ymin) ymin = s[1];
  26. }
  27. // 位于盒子边界内
  28. if(pos.x >= xmin && pos.x <= xmax && pos.y >= ymin && pos.y <= ymax){
  29. ps.push(p);
  30. }
  31. });
  32. if(!ps.length) return;
  33. let sel;
  34. //获取最靠近视点的图形
  35. if(ps.length == 1) {
  36. sel = ps[0];
  37. } else {
  38. sel = ps.sort((a,b)=> {
  39. const az = m4.transformPoint(a.matrix,[0,0,0])[2];
  40. const bz = m4.transformPoint(b.matrix,[0,0,0])[2];
  41. return az - bz;
  42. })[0];
  43. }
  44. //设置该图形为选中
  45. Polygons[sel.index].select = true;
  46. },false);

目前实现的功能在 选择不规则的物体时,判断地不是很精准,毕竟不是所有的图形都是类似矩形。

那么解决方案就是:我们知道WebGL图形是由三角形构成的,如果进一步判断鼠标位置是否在构成该图形的三角形面当中,那就会更加精确了,这个功能留给读者去实现。

原文链接:http://www.cnblogs.com/edwardloveyou/p/10943102.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号