对象网格在渲染图像的相反方向上运行

Object Mesh Orbiting Opposite Direction of Rendered Image

我正在尝试使用 Three.JS 重新创建一个 Flash 网站,但在尝试创建某些功能时遇到了 运行 障碍。

应该发生的是我想让一些按钮图像围绕屏幕中心旋转。如果鼠标悬停在它们上面然后单击以打开网站上的不同位置,它们应该能够停止。

我已经完成了所有工作,直到要求当鼠标悬停在按钮上时按钮停止。我正在尝试使用光线投射来实现这一点,但是当我在场景中移动鼠标时,似乎网格与渲染纹理不在同一位置。事实上,网格和渲染图像几乎看起来是在彼此相反的方向上运行。

这是我的代码,我将 link 您转到我网站上的一个页面,我正在该页面上测试此改版,以便您获得真实世界的示例:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Untitled Document</title>
    <style type="text/css">
        body { margin: 0;}
        canvas { display: block;}
    </style>        
</head>

<body>
    <script>
        //var THREE = new THREE();
        var renderer,scene,camera,nucleus;
        
        var width = window.innerWidth;
        var height = window.innerHeight;
        var fov = 60;
        var near = 1;
        var far = 10000;
        var min = 0;
        var max = 10;
        var insObjSpeed = 0;
        
        var buttons = [];
        var numOfBtns = 1;
        
        var projector, mouse = { x: 0, y: 0 }, INTERSECTED;
        
        //var mouse;
        
        function populateScene(){
            var geom = new THREE.CircleGeometry(3,50);
            var matTx = new THREE.TextureLoader().load('imgs/buttons/logo.png');
            var mat = new THREE.MeshBasicMaterial({map:matTx});
            nucleus = new THREE.Mesh(geom, mat);
            nucleus.position.set(0,0,0);
            scene.add(nucleus);
            
            var btn = null;
            var btnMat = null;
            var plane = new THREE.Plane();
            var point = new THREE.Vector3();
            
            var btnMats = [new THREE.TextureLoader().load('imgs/buttons/georo.png'),
                           new THREE.TextureLoader().load('imgs/buttons/wiki.png'),
                           new THREE.TextureLoader().load('imgs/buttons/port.png'),
                           new THREE.TextureLoader().load('imgs/buttons/yt.png'),
                           new THREE.TextureLoader().load('imgs/buttons/l2r.png'),
                           new THREE.TextureLoader().load('imgs/buttons/ci.png'),
                           new THREE.TextureLoader().load('imgs/buttons/ov.png'),
                           new THREE.TextureLoader().load('imgs/buttons/ttv.png'),
                           new THREE.TextureLoader().load('imgs/buttons/tw.png'),
                           new THREE.TextureLoader().load('imgs/buttons/ffs.png')];
                           
            var usedMats = [];
                            
            for (var i1 = 0; i1 < numOfBtns; i1++){
                var matIdx = Math.floor(Math.random() * (max - min + 1)) + min;
                var matTx = btnMats[matIdx];
                
                if (usedMats.includes(matTx)){
                    while (usedMats.includes(matTx)){
                        matIdx = Math.floor(Math.random() * (max - min + 1)) + min;
                        matTx = btnMats[matIdx];
                    }
                }
                
                usedMats.push(matTx);
                //var matTx = new THREE.TextureLoader().load('imgs/buttons/georo.png')
                var geom2 = new THREE.CircleGeometry(3,50);         
                var mat = new THREE.MeshBasicMaterial({map:matTx});
                btn = new THREE.Mesh(geom2, mat);                   
                btn.angle = new THREE.Vector3(Math.random(),
                                              Math.random(),
                                              Math.random()).normalize();
                btn.orbitSpeed = 0.0045; //Math.random() * 0.05) * 0.5;
                
                
                plane.normal.copy(btn.angle);
                point.set(Math.random(),Math.random(),Math.random());
                plane.projectPoint(point, btn.position);
                
                if (Math.random() > 0.5) { btn.orbitSpeed *= -1; }
                btn.position.setLength(Math.floor(Math.random() * 20) + 15);
                btn.position.applyAxisAngle(btn.angle, Math.random() / 10);
                btn.position.add(nucleus.position);

                buttons.push(btn);      
                scene.add(btn);             
            }
        }
            
        function updateBtns() {
            var obj = null;
            
            for (var i1 = 0; i1 < numOfBtns; i1++){
                obj = buttons[i1];
                
                obj.position.sub(nucleus.position);
                obj.position.applyAxisAngle(obj.angle,obj.orbitSpeed);
                obj.position.add(nucleus.position);
                
                //if (i1 == 0){ console.log(obj.position); }
            }
        }
            
        function init() {
            document.body.style.backgroundColor = "#333333";
            
            renderer = new THREE.WebGLRenderer({
                antialias: true,
                alpha: true
            });
            
            mouse = new THREE.Vector2();
            
            renderer.shadowMap.enabled = true;
            renderer.shadowMap.type = THREE.PCFSoftShadowMap;
            
            document.body.appendChild(renderer.domElement);
            document.body.style.overflow = "hidden";
            document.body.style.margin = "0";
            document.body.style.padding = "0";
            
            scene = new THREE.Scene();
            camera = new THREE.PerspectiveCamera(fov, width/height, near, far);
            camera.position.z = 100;
            scene.add(camera);
            
            //controls = new THREE.TrackballControls(camera, renderer.domElement);
            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
            projector = new THREE.Projector();
            
            resize();
            window.onresize = resize;
            populateScene();
            animate();
        }
        
        function onDocumentMouseMove( event ) 
        {
            // the following line would stop any other event handler from firing
            // (such as the mouse's TrackballControls)
            event.preventDefault();
            
            // update the mouse variable
            mouse.x = ( event.clientX / renderer.domElement.clientWidth) * 2 - 1;
            mouse.y = -( event.clientY / renderer.domElement.clientHeight) * 2 + 1;
            
            console.log("mouse pos: " + mouse.x + ", " + mouse.y);
            
        }
            
        function resize(){
            width = window.innerWidth;
            height = window.innerHeight;
            
            if (renderer && camera){
                renderer.setSize(width, height);
                camera.aspect = width / height;
                camera.updateProjectionMatrix();    
            }
        }
            
        function render(){
            renderer.render(scene, camera); 
        }
        
        function animate(){             
            checkMouse();
            requestAnimationFrame(animate);
            updateBtns();
            render();
            //checkMouseHover();
            
        }
        
        function checkMouse(){
            var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
            console.log("ray vec: " + vector.x + ", " + vector.y);
            projector.unprojectVector( vector, camera );
            var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
        
            // create an array containing all objects in the scene with which the ray intersects
            var intersects = ray.intersectObjects( scene.children, true );
        
            // INTERSECTED = the object in the scene currently closest to the camera 
            //      and intersected by the Ray projected from the mouse position    
            
            // if there is one (or more) intersections
            if ( intersects.length > 0 ) {
                // if the closest object intersected is not the currently stored intersection object
                if ( intersects[ 0 ].object != INTERSECTED && intersects[0].object !== nucleus) {
                    // restore previous intersection object (if it exists) to its original color
                    if ( INTERSECTED ) {
                        console.log("Intersection detected at: " + intersects[0].point);
                        INTERSECTED = intersects[0].object;
                        INTERSECTED.material.color.setHex( INTERSECTED.currentHex );
                        // store reference to closest object as current intersection object
                        
                        // store color of closest object (for later restoration)
                        INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
                        // set a new color for closest object
                        INTERSECTED.material.color.setHex( 0xffff00 );
                    }
                }
            } 
            else { // there are no intersections
                // restore previous intersection object (if it exists) to its original color
                if ( INTERSECTED ) { INTERSECTED.material.color.setHex( INTERSECTED.currentHex ); }
                // remove previous intersection object reference
                //     by setting current intersection object to "nothing"
                INTERSECTED = null; 
            }
        }
        
        function onMouseOver(ev){
            insObjSpeed = ev.object.orbitSpeed;
            //ev.object.orbitSpeed = 0.0;
        }
        
        function onMouseOut(ev) { ev.object.orbitSpeed = insObjSpeed; }         
        function THREEReady() { init(); }           
        function onMouseMove(event){
            mouse.x = (event.clientX/width)*2-1;    
            mouse.y = (event.clientY/height)*2-1;
        }
        
        (function() {
            window.addEventListener('mousemove',onMouseMove,false);
            
            function addScript(url, callback){
                callback = callback || function() {};
                
                var script = document.createElement("script");
                
                script.addEventListener("load", callback);
                script.setAttribute("src", url);
                document.head.appendChild(script);  
            }
            
            addScript("./js/ThreeJS_0.119.1.js",function() {
                addScript("./js/ThreeJS_0.119.1_Projector.js",function(){
                THREEReady();
            })});
        })();
    </script>
</body>

Live Demo

首先,您的 mouseMove() 在 y-value 计算之前缺少负号。这意味着您的 y-value 被翻转了(它应该是 +1 时是 -1)它应该如下所示:

mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

其次,我不确定您为什么要在每一帧上创建一个新的 Vector3,而您只能使用现有的 mouse Vector2,如 outlined in the docs

// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );

// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );

无需执行 unprojectVector 然后减去相机位置,或者如果您使用 setFromCamera().

编辑:只要意识到您还有两个相互覆盖的侦听器(onMouseMoveonDocumentMouseMove),其中一个的计算公式错误 mouse.y,这就是原因你得到一个倒置的 y 值。