以相机为原点的Three.js Raycasting

时间:2014-07-29 20:08:19

标签: three.js raycasting

我试图确定空间中的某个点是对相机可见还是隐藏在场景中的其他对象后面。我是通过将光线从相机的位置投射到太空中的那个点并测试该光线是否被一组可交叉的物体相交来做到这一点。

我的问题是,在相机位置本身与可交叉对象集合中的一个对象相交之前,不会发生交叉。

我创建了一个jsfiddle,其中,如果检测到交叉点,则从摄像机位置到空间位置绘制一条线,以测试可见性。目前我相信,该线仅在相机位置与可交叉对象集相交的特定点处绘制。

如何让交叉点按原样注册,而不必让相机位置与可交叉对象集中的对象相交?

代码:

    var container;
    var camera, controls, scene, renderer;

    init();
    animate();

    function init() {

        camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
        camera.position.z = 1000;

        controls = new THREE.OrbitControls(camera);

        controls.rotateSpeed = 1.0;
        controls.zoomSpeed = 1.2;
        controls.panSpeed = 0.8;

        controls.noZoom = false;
        controls.noPan = false;

        controls.staticMoving = true;
        controls.dynamicDampingFactor = 0.3;

        controls.keys = [65, 83, 68];

        controls.addEventListener('change', render);

        // world

        scene = new THREE.Scene();

        var testObject_G = new THREE.CubeGeometry(100, 100, 5);
        var testObject_M = new THREE.MeshBasicMaterial({
            color: 0xBBBBBB
        });
        var testObject_Mesh = new THREE.Mesh(testObject_G, testObject_M);
        testObject_Mesh.position.x = -150;
        scene.add(testObject_Mesh);
        var testObject_Mesh2 = new THREE.Mesh(testObject_G, testObject_M);
        testObject_Mesh2.position.x = 0;
        scene.add(testObject_Mesh2);
        var testObject_Mesh3 = new THREE.Mesh(testObject_G, testObject_M);
        testObject_Mesh3.position.x = 150;
        scene.add(testObject_Mesh3);


        scene2 = new THREE.Object3D();

        // renderer

        renderer = new THREE.WebGLRenderer({
            antialias: true
        });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0xffffff, 1);
        container = document.getElementById('container');
        container.appendChild(renderer.domElement);



        //

        window.addEventListener('resize', onWindowResize, false);

    }

    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);

        controls.handleResize();

        render();

    }

    function animate() {

        requestAnimationFrame(animate);
        controls.update();

    }

    function render() {

        renderer.render(scene, camera);
        castRays();

    }

    function castRays() {

        // rays

        var direction = new THREE.Vector3(0, 200, -200);

        var startPoint = camera.position.clone();

        var ray = new THREE.Raycaster(startPoint, direction);

        scene.updateMatrixWorld(); // required, since you haven't rendered yet

        var rayIntersects = ray.intersectObjects(scene.children, true);

        if (rayIntersects[0]) {
            console.log(rayIntersects[0]);

            var material = new THREE.LineBasicMaterial({
              color: 0x0000ff
            });
            var geometry = new THREE.Geometry();
            geometry.vertices.push(new THREE.Vector3(ray.ray.origin.x, ray.ray.origin.y, ray.ray.origin.z));
            geometry.vertices.push(new THREE.Vector3(ray.ray.direction.x, ray.ray.direction.y, ray.ray.direction.z));
            var line = new THREE.Line(geometry, material);
            scene2.add( line );

        }

        scene.add(scene2);

    }

谢谢

2 个答案:

答案 0 :(得分:2)

对于目前看到此帖子的任何人,THREE.Projector已被替换。

Three.js THREE.Projector has been moved to

下面的代码处理3D矢量。如果你转到上面的链接,第一个评论者提供了2D矢量的代码。

var vector = new THREE.Vector3();
var raycaster = new THREE.Raycaster();
var dir = new THREE.Vector3();

...

if ( camera instanceof THREE.OrthographicCamera ) {

    vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, - 1 ); // z = - 1 important!

    vector.unproject( camera );

    dir.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );

    raycaster.set( vector, dir );

} else if ( camera instanceof THREE.PerspectiveCamera ) {

   vector.set( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 ); // z = 0.5 important!

   vector.unproject( camera );

   raycaster.set( camera.position, vector.sub( camera.position ).normalize());

}

var intersects = raycaster.intersectObjects( objects, recursiveFlag );`

答案 1 :(得分:1)

您投射光线的想法很好,但raycasting中的three.js已经这样做了:

 mouse.x = ( ( event.clientX - renderer.domElement.offsetLeft ) / renderer.domElement.width ) * 2 - 1;
 mouse.y = - ( ( event.clientY - renderer.domElement.offsetTop ) / renderer.domElement.height ) * 2 + 1;

此公式将像素坐标从屏幕空间映射到标准化设备坐标(NDC)空间中的点。

projector.unprojectVector( vector, camera );

将一个点从NDC空间映射到世界空间中的一个点

然后,Raycaster会通过该世界点从相机位置创建一条光线。

这是你的working Fiddle,我改变了你场景中的光线投射方式,这项工作正常,你现在所要​​做的就是用我提供给你的正确坐标创建一条光线。

r.68