基本上所有三维应用都需要用户能够交互地操纵三维物体,要这样做首先得允许用户选中物体。我们今天就来学习下在三维场景中如何实现选中物体。
Webgl最终呈现出来的只有一张纹理图显示在canvas容器内,我们如何利用这张纹理图片来分别是否选中呢?这里需要我们进行特殊处理,在《WebGL编程指南》教程中这样判断:
http://s2/mw690/006pZnPwzy7pdDU21RT61&690
相信所有webgl三维引擎都是这个核心思想吧。下面我们基于教程的示例,绘制三个点,点击判断是否选中点。
主要流程:
//注册点击事件
canvas.onmousedown = function (ev) {
var x = ev.clientX, y = ev.clientY;
var rect = ev.target.getBoundingClientRect();
if (rect.left <= x && x < rect.right &&
rect.top <= y && y < rect.bottom) {
var x_in_canvas = x - rect.left, y_in_canvas = rect.bottom -
y;
Draw(gl, n, vertices, colorsPicked);
var pixels = getFixels(gl, x_in_canvas, y_in_canvas);
var pickedObj = check([p1, p2, p3], pixels);
if (pickedObj) alert('The cube was selected! ' +
pickedObj.id);
Draw(gl, n, vertices, colors);
}
}
监听鼠标事件,在鼠标事件中做成一下逻辑:
1判断点击再canvas区域
2使用pickcolor重新绘制
3获取点击处当前像素值
4判断是否选中物体
5使用正常颜色重绘
判断点击再canvas区域
var x
= ev.clientX, y = ev.clientY;
var rect = ev.target.getBoundingClientRect();
if (rect.left <= x && x <
rect.right && rect.top <= y && y <
rect.bottom)
使用pickcolor重新绘制
我们在定义顶点对象时,添加点击颜色这一属性:
function PickedPoint(options)
{
this.id = parseInt(Math.random() * 1000);
this.position = defaultValue(options.position, [Math.random(),
Math.random()]);
this.pickColor = defaultValue(options.pickColor,
[parseInt(Math.random() * 255.0), parseInt(Math.random() * 255.0),
parseInt(Math.random() * 255.0)]);
this.color = defaultValue(options.color, [parseInt(Math.random() *
255.0), parseInt(Math.random() * 255.0), parseInt(Math.random() *
255.0)]);
}
当鼠标处于点击状态时,用此颜色重绘,这里每个颜色有rgba四个分量,每个分量取值0-255,因此我们可以用rgba区分256*256*256*256个对象,这足够使用了。
获取点击处当前像素值
function getFixels(gl, x, y)
{
//
var pixels = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE,
pixels);
return pixels;
}
gl.readPixels解释:
http://s9/mw690/006pZnPwzy7pdDVASs8f8&690
示例中我们返回1*1大小,即一个像素的rgba值。
判断是否选中物体
function check(ps, pixels)
{
for (var i = 0; i < ps.length; i++) {
var r = ps[i].pickColor[0];
var g = ps[i].pickColor[1];
var b = ps[i].pickColor[2];
if (r == pixels[0] && g == pixels[1] && b ==
pixels[2]) {
return ps[i];
}
}
return null;
}
将像素值与所有点对象匹配,如果rgb(这里我们没有使用a值)相同则说明选中改对象。
使用正常颜色重绘
Draw(gl, n, vertices,
colors);
使用正常颜色重绘。
下面试效果:
http://s10/mw690/006pZnPwzy7pdDWNVPP69&690
示例源码:github源码
我的学习公众号也开通,感兴趣的小伙伴们可以加关注:giserYZ2SS
http://s11/small/006pZnPwzy7pdE0O7MK1a&690
加载中,请稍候......