2011-10-31 46 views
18

我有一个THREE.js场景,其中出现了很多元素,我需要检测用户点击的是什么对象。检测THREE.js中的点击对象

我到目前为止所做的是以下几点。相机不会移动太多 - 它只会将垂直位置改变一个有限的数值,始终朝向相同的位置。我的近似方法如下:

  • 我拿的坐标,如果相对于画布点击
  • 我用一个简单的缩放的方式将其转化为在WebGL的场景水平和垂直坐标,并添加为Z坐标距离足够远。
  • 我从上面的点开始,由THREE.Ray()构造的水平射线
  • 我使用ray.intersectObjects()来查找射线上的第一个元素。

该方法大致起作用,但它有时距离实际点几个像素。

是否有更可靠的技术来找出用户点击的对象?

+0

保证金和填充可能导致您的坐标有点偏移。你有没有解释它? – Prusse

+0

目前在演示中没有保证金和填充,但我描述的技术并不是确切的。 – Andrea

+4

看看[这个例子](http://mrdoob.github.com/three.js/examples/canvas_interactive_cubes.html)。 –

回答

7

取决于您使用的是哪种相机。

1)PerspectiveCamera:是确定链接Mr.doob提供。
2)OrthographicCamera:是完全不同的:

var init = function() { 
    camera = new THREE.OrthographicCamera(SCREEN_WIDTH/- 2, SCREEN_WIDTH/2, SCREEN_HEIGHT/2, SCREEN_HEIGHT/- 2, NEAR, FAR); 
    document.addEventListener('mousedown', onDocumentMouseDown, false); 
} 

function onDocumentMouseDown(e) { 
    e.preventDefault(); 
    var mouseVector = new THREE.Vector3(); 
    mouseVector.x = 2 * (e.clientX/SCREEN_WIDTH) - 1; 
    mouseVector.y = 1 - 2 * (e.clientY/SCREEN_HEIGHT); 
    var raycaster = projector.pickingRay(mouseVector.clone(), camera); 
    var intersects = raycaster.intersectObject(TARGET); 
    for(var i = 0; i < intersects.length; i++) { 
    var intersection = intersects[ i ], 
    obj = intersection.object; 
    console.log("Intersected object", obj); 
    } 
} 
+0

“projector.pickingRay”被删除? –

+2

这里是一个替代解决方案https://github.com/mrdoob/three.js/issues/5587 –

3

退房这一个:

var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 5000); 
var object; //your object 

document.addEventListener('mousedown', onMouseDown, false); 

function onMouseDown(e) { 
    var vectorMouse = new THREE.Vector3(//vector from camera to mouse 
     -(window.innerWidth/2-e.clientX)*2/window.innerWidth, 
     (window.innerHeight/2-e.clientY)*2/window.innerHeight, 
     -1/Math.tan(22.5*Math.PI/180)); //22.5 is half of camera frustum angle 45 degree 
    vectorMouse.applyQuaternion(camera.quaternion); 
    vectorMouse.normalize();   

    var vectorObject = new THREE.Vector3(); //vector from camera to object 
    vectorObject.set(object.x - camera.position.x, 
        object.y - camera.position.y, 
        object.z - camera.position.z); 
    vectorObject.normalize(); 
    if (vectorMouse.angleTo(vectorObject)*180/Math.PI < 1) { 
     //mouse's position is near object's position 

    } 
} 
+0

这是一个非常不错的解决方案,并且可以防止CPU密集型raycast,但只会看到鼠标是否靠近对象的枢轴点击。优点是没有网格的对象可以这样工作。缺点是通告“热点”。 – Hacky

2

检查为鼠标的交集和任何多维数据集的3D空间中,并改变它的颜色。也许this帮助你。

+3

欢迎来到Stack Overflow!花一分钟阅读[如何回答](http://stackoverflow.com/questions/how-to-answer) - 这看起来很有帮助,但它会受益于代码的一些解释,考虑[编辑]( http://stackoverflow.com/posts/41385887/edit) - 在那? –

0

我遇到了一些问题,试图实现这个画布不占用整个屏幕的宽度和高度。这是我找到的解决方案非常好的解决方案。

在现有的帆布初始化一切:

var init = function() { 
    var canvas_model = document.getElementById('model') 
    var viewSize = 50 // Depending on object size, canvas size etc. 
    var camera = new THREE.OrthographicCamera(-canvas_model.clientWidth/viewSize, canvas_model.clientWidth/viewSize, canvas_model.clientHeight/viewSize, -canvas_model.clientHeight/viewSize, 0.01, 2000), 
} 

添加事件侦听到画布:

canvas_model.addEventListener('click', function(event){ 
    var bounds = canvas_model.getBoundingClientRect() 
    mouse.x = ((event.clientX - bounds.left)/canvas_model.clientWidth) * 2 - 1; 
    mouse.y = - ((event.clientY - bounds.top)/canvas_model.clientHeight) * 2 + 1; 
    raycaster.setFromCamera(mouse, camera); 
    var intersects = raycaster.intersectObjects(scene.children, true); 
    if (intersects.length > 0) { 
    // Do stuff 
    } 
}, false) 

还是一个“touchstart”事件,改变线计算mouse.x和mouse.y导入:

mouse.x = ((event.touches[0].clientX - bounds.left)/canvas_model.clientWidth) * 2 - 1; 
mouse.y = - ((event.touches[0].clientY - bounds.top)/canvas_model.clientHeight) * 2 + 1;