Three.js射线投射仅在非常接近的情况下有效

6

我正在跟随mrdoobs关于如何使用射线碰撞处理可点击对象的示例。我还查看了所有类似的问题并尝试了无数种方法。 如果距离小于1,射线碰撞可以正常工作。

射线碰撞器被设置为近0和远无穷大(默认值)。 我没有看到任何设置距离的代码示例。

我希望能得到另一双眼睛的帮助。

// snippet
glow.clickables = [];
var cubeGeo = new THREE.CubeGeometry(2, 2, 2);
cubeGeo.computeFaceNormals();
var cube = new THREE.Mesh(cubeGeo, redmat);
cube.position.y = 10;
cube.position.x = 0;
cube.position.z = -12;
cube.overdraw = true;
glow.Vis.scene.add(cube);
glow.clickables.push(cube);
onclick_();

var onclick_ = function() {
    $('#world').on('mousedown', function(e){
        var mouseX = (event.offsetX / $('#world').width()) * 2 - 1;
        var mouseY =  - ( event.offsetY / $('#world').height()) * 2 + 1;
        var vector = new THREE.Vector3(mouseX, mouseY,  0.1); //what should z be set to?
        //console.info(vector); // A vector between -1,1 for both x and y. Z is whatever is set on the line above
        projector.unprojectVector(vector, glow.Vis.camera);
        var conts = glow.Vis.controls.getObject().position; // control 3dObject which the camera is added to.
        var clickRay = new THREE.Raycaster(conts, vector.sub(conts).normalize());
        var intersects = clickRay.intersectObjects(glow.clickables);
        console.info(intersects.length);
        if(intersects.length > 0) {
            alert("Click detected!");
        }
    });
}

不是很确定,但我认为向量Z应该设置为1.0,如果小于这个值可能会导致无法检测到远处的交点,这种情况似乎很有道理。 - yaku
谢谢!将设置为1解决了我的问题。 - Matt Gardner
3个回答

9

使用这种方式设置鼠标位置更加准确。

        var rect = renderer.domElement.getBoundingClientRect();
        mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1;
        mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1;

2
对于鼠标检测(无论是远还是近!),请按照以下步骤进行操作:
将以下内容放入您的全局变量中:
var pointerDetectRay, projector, mouse2D;  

将此内容放置在您的init()函数中:
pointerDetectRay = new THREE.Raycaster();
pointerDetectRay.ray.direction.set(0, -1, 0);
projector = new THREE.Projector();
mouse2D = new THREE.Vector3(0, 0, 0);

将以下代码添加到您的render()循环函数中:

pointerDetectRay = projector.pickingRay(mouse2D.clone(), camera);

这是您的鼠标事件:

function onDocumentMouseMove(event) {
    event.preventDefault();
    mouse2D.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse2D.y = -(event.clientY / window.innerHeight) * 2 + 1;
}

现在,无论您想在哪里检测鼠标指针下的对象,请使用以下内容:
var intersects = pointerDetectRay.intersectObjects(scene.children);
if (intersects.length > 0) {
    var intersect = intersects[0];
    // intersect is the object under your mouse!
    // do what ever you want!
}

有趣的是,在Chrome中,这似乎在高分辨率下会“漂移”:http://stackoverflow.com/questions/21919580/threejs-mouse-interaction-with-large-resolutions示例:http://jsfiddle.net/lookitscook/3FSxj/ - Matthew Cook
很遗憾,这个答案在最新的ThreeJS中已经不再适用。 - James Heald

0

我使用以下代码,对于较大的距离来说非常有效:

    var projector = new THREE.Projector();
    function onDocumentMouseDown( event ) {

        event.preventDefault();

        var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
        projector.unprojectVector(vector,camera);

        var raycaster = new THREE.Raycaster(camera.position,vector.sub(camera.position).normalize() );
        var intersects = raycaster.intersectObjects( [sphere,cylinder,cube] );

        if ( intersects.length > 0 ) {
            intersects[ 0 ].object.material.transparent=true;
            intersects[ 0 ].object.material.opacity=0.1;
            console.log(intersects[0]);
        }
    }

这只是将第一个选定的对象设置为半透明。完整示例请参见:https://github.com/josdirksen/learning-threejs/blob/master/chapter-09/02-selecting-objects.html


嗯,我没有看到任何明显的区别。我的射线投射器确实是有效的。不幸的是,我需要非常接近对象才可以使用。 - Matt Gardner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接