在Three.js中制作几何可点击的超链接(WebGl渲染器)

时间:2015-11-07 23:27:33

标签: javascript html three.js

所以我一直在尝试使用three.js制作一个球形360全景图,它实现了可点击的对象,目前我想制作超链接。我已经阅读过许多以前的光线投射示例等等,但没有运气让对象实际上将我重定向到网站。如果有人能告诉我代码中哪些地方出错,我会非常感激。

我感觉轨道/平移功能在" onDocumentMouseDown"正在干扰光线投射?我还是新手并想出来。

<div id="container"></div>
    <script src="three.min.js"></script>
    <script>
        var container, stats;
        var camera, controls, scene, renderer;
        var objects = [], plane;

        var raycaster = new THREE.Raycaster();
        var mouse = new THREE.Vector2(),
        offset = new THREE.Vector3();

        var fov = 70,
        texture_placeholder,
        isUserInteracting = false,
        onMouseDownMouseX = 0, onMouseDownMouseY = 0,
        lon = 0, onMouseDownLon = 0,
        lat = 0, onMouseDownLat = 0,
        phi = 0, theta = 0;

        init();
        animate();

        function init() {
            var container, mesh1, sphere1, cube1;

            container = document.getElementById( 'container' );

            camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1100 );
            camera.target = new THREE.Vector3( 0, 0, 0 );

            scene = new THREE.Scene();

            mesh1 = new THREE.Mesh( new THREE.SphereGeometry( 500, 60, 40 ), new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'spherical_map_small.jpg' ), transparent: true} ) );
            mesh1.scale.x = -1;
            scene.add( mesh1 );

            meshMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff});

            var sphere1 = new THREE.Mesh( new THREE.SphereGeometry( 2.5,20,20 ), meshMaterial );
            sphere1.position.set( 50, 10, 0 );
            scene.add( sphere1 );

            sphere1.userData = { URL:"http://www.google.com"};

            renderer = new THREE.WebGLRenderer();
            renderer.setSize( window.innerWidth, window.innerHeight );

            container.appendChild( renderer.domElement );

            document.addEventListener( 'mousedown', onDocumentMouseDown, false );
            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
            document.addEventListener( 'mouseup', onDocumentMouseUp, false );
            document.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
            document.addEventListener( 'DOMMouseScroll', onDocumentMouseWheel, false);

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

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

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

        function onDocumentMouseDown( event ) {
            event.preventDefault();
            isUserInteracting = true;

            onPointerDownPointerX = event.clientX;
            onPointerDownPointerY = event.clientY;

            onPointerDownLon = lon;
            onPointerDownLat = lat;

            raycaster.setFromCamera( mouse, camera );

            var intersects = raycaster.intersectObjects( sphere1 );

            if ( intersects.length > 0 ) {
                controls.enabled = true;

                SELECTED = intersects[ 0 ].sphere1;

                var intersects = raycaster.intersectObject( sphere1 );
                if ( intersects.length > 0 ) {
                    window.open(intersects[0].object.userData.URL);
                }
            }   
        }

        function onDocumentMouseMove( event ) {
            if ( isUserInteracting ) {
                lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
                lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
            }
        }

        function onDocumentMouseUp( event ) {
            isUserInteracting = false;
        }

        function onDocumentMouseWheel( event ) {
            isUserInteracting = false;
        }

        function animate() {
            requestAnimationFrame( animate );
            render();
        }

        function render() {
            lat = Math.max( - 85, Math.min( 85, lat ) );
            phi = THREE.Math.degToRad( 90 - lat );
            theta = THREE.Math.degToRad( lon );

            camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
            camera.target.y = 500 * Math.cos( phi );
            camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );

            camera.lookAt( camera.target );

            renderer.render( scene, camera );
        }
    </script>

1 个答案:

答案 0 :(得分:0)

查看您的代码我注意到您创建了var mouse = new THREE.Vector2(),然后您不会在提供的代码中的任何位置设置其值。然后在onDocumentMouseDown()中,您使用未定义的鼠标坐标raycaster.setFromCamera( mouse, camera );将光线投射到场景中由于尚未设置var mouse,因此您很可能不会导航到启动。

你需要做的是获取鼠标的标准化屏幕坐标并将其传递到raycaster.setFromCamera如果屏幕是一个或两个单位但是像

那么我无法理解
mouse.x = (event.clientX / window.innerWidth);  // normalise the mouse screen pos
mouse.y = (event.clientY / window.innerHeight); // same

mouse.x *= 2; // 0 is the center. -1 is left and 1 is right
mouse.y -= 1;  // center 

mouse.y *= -2; // Think this is upside down If it does not work try positive 2
mouse.y += 1;  // center

如果它不起作用,请尝试切换鼠标。反过来;

mouse.y *= 2; //  remove the -2 and put in 2
mouse.y -= 1;  // remove the += and put in -=

当我在3D中搞乱时,我发现非常方便的是在场景中有一个备用的调试对象。像盒子或球体一样简单的东西。用它来显示raycaster射线上的一个点。

这样的东西
// creat a box
var box... blah blah box creation code/
boxP = new vector3(); // position of debug object
// position it halfway in the raycasters range
boxP.x = camera.x + rayCaster.ray.x* ((rayCaster.near+rayCaster.far)/2);
boxP.y = camera.y + rayCaster.ray.y* ((rayCaster.near+rayCaster.far)/2);
boxP.z = camera.z + rayCaster.ray.z* ((rayCaster.near+rayCaster.far)/2);
box.position.set(boxP.x,boxP.y,boxP.z);

现在运气好的话,你应该看到你点击的地方。

此外,我不确定,但如果你从内部看球体,你可能需要将材料设置为doubleSided(我在你的代码中看不到它),因为raycaster会忽略法线指向的面孔。或者尝试反转每个多边形的方向。

这就是我现在所能提出的所有建议。希望你能找到问题。