Javascript 在 THREE.js 中检测点击的对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7956442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Detect clicked object in THREE.js
提问by Andrea
I have a THREE.js scene where a lot of elements appear, and I need to detect what object the user is clicking on.
我有一个 THREE.js 场景,其中出现了很多元素,我需要检测用户单击的对象。
What I have done so far is the following. The camera does not move to much - it only changes the vertical position by a limited amount, always looking towards the same point. My approximate method is the following:
到目前为止,我所做的如下。相机不会移动太多 - 它只会以有限的量改变垂直位置,始终看向同一点。我的大致方法如下:
- I take the coordinates if the click relative to the canvas
- I translate them into horizontal and vertical coordinates in the webGL scene by means of a simple rescaling, and add a Z coordinate which is sufficiently far away.
- I take a horizontal ray starting from the point above, constructed by THREE.Ray()
- I use ray.intersectObjects() to find the first element along the ray.
- 如果点击相对于画布,我会获取坐标
- 我通过简单的重新缩放将它们转换为 webGL 场景中的水平和垂直坐标,并添加一个足够远的 Z 坐标。
- 我从上面的点开始拍摄水平光线,由 THREE.Ray() 构建
- 我使用 ray.intersectObjects() 来查找沿射线的第一个元素。
This method approximately works, but it is sometimes a few pixels away from the actual point.
这种方法大致有效,但有时与实际点相差几个像素。
Is there a more reliable technique to find out the object where a user has clicked?
是否有更可靠的技术来找出用户单击的对象?
回答by Luca Davanzo
Depends on what kind of camera are you using.
取决于你使用的是什么类型的相机。
1) PerspectiveCamera: is ok link that Mr.doobprovides.
2) OrthographicCamera: is quite different:
1) PerspectiveCamera:是 ok 的链接,由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);
}
}
回答by user3394964
Check out this one:
看看这个:
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
}
}
回答by BlindElephants
回答by Evertvdw
I ran into problems trying to implement this for a canvas which does not take up the entire width and height of the screen. Here is the solution I found works quite well.
我在尝试为不占据屏幕的整个宽度和高度的画布实现此功能时遇到了问题。这是我发现效果很好的解决方案。
Initialize everything on an existing canvas:
初始化现有画布上的所有内容:
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),
}
Add an event listener to the canvas:
将事件侦听器添加到画布:
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)
Or for a 'touchstart' event, change the lines calculating the mouse.x and mouse.y into:
或者对于“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;