【问题标题】:Can't open a pointed url of selected objects无法打开选定对象的指向 url
【发布时间】:2020-02-03 06:05:04
【问题描述】:

当我使用 raycaster 点击相关行星时,我正在尝试导航到相关链接。相反,当单击画布的任何部分时,它会将我带到最后一个行星的 URL(此处称为类别)。我正在使用一个函数来与 init() 分开创建行星和补间。如何构建 raycaster 以仅单击行星以导航到其相关 URL。感谢您的宝贵时间。

代码如下:

class App extends Component{

  componentDidMount() {
    var scene, camera, renderer;
    var controls;
    var category, orbit, orbitContainer

    init();
    animate();

    function createSubCategory(){}

    function createCategory(name, radius, distance, tilt, color, speed, link) {
      orbitContainer = new THREE.Object3D();
      orbitContainer.rotation.x = tilt;
      //  orbitContainer.rotation.x = 700;

         var id = name

        orbit = new THREE.Object3D();

        var geometry = new THREE.CircleGeometry(distance, 100);
        geometry.vertices.shift();
        var line = new THREE.Line(
          geometry,
           new THREE.LineBasicMaterial({color: 'aqua'})
        );

        //ring movement
        line.rotation.x = Math.PI * 0.5;

        category = new THREE.Mesh(
          new THREE.SphereGeometry(radius, 0, 0),
            //new THREE.MeshPhongMaterial({color:color,wireframe: true})
            new THREE.MeshBasicMaterial({color:color,wireframe: true})
        );
        orbitContainer.userData.URL= link
        // initial position
        // distance away from the center

        //change initial position

        category.position.set(distance, 0.0, 0.0);

        //orbit.add(line);
        orbit.add(category);

        new TWEEN.Tween(orbit.rotation,{
          loop: true,

          //useTicks: true,
          //css: true,
          //ignoreGlobalPause: true
      }).to({y:  //'+' or '-' for rotation direction
        '+' + (Math.PI * 2)}, 4000 / speed);





        orbitContainer.add(orbit);
        scene.add(orbitContainer);


    }

    function init() {

        scene = new THREE.Scene();
        scene.background = new THREE.Color(0x202020);

        camera = new THREE.PerspectiveCamera(60, 4 / 3, 0.1, 10000.0);
        camera.position.set(20.0, 20.0, 20.0);
        camera.lookAt(new THREE.Vector3(0, 0, 0));

        renderer = new THREE.WebGLRenderer({antialias: false});
       document.addEventListener('mousedown', onDocumentMouseDown, false);
        controls = new OrbitControls(camera, renderer.domElement);

        var ambientLight = new THREE.AmbientLight(0xffffff, 0.1);
        scene.add(ambientLight);

//light emission will be the icon with a line connecting to the logo (sun) and will light up the line and icon when selected 

        var solar = new THREE.Mesh(
            new THREE.SphereGeometry(2.5, 32, 32),
            new THREE.MeshBasicMaterial({emissive: 0xff5800, emissiveIntensity: 0.5, wireframe: true, color:'silver'})
        );

        var pointLight = new THREE.PointLight(0xffffff, 1.0, 300.0);
        solar.add(pointLight);
        scene.add(solar);

        createCategory('B',1.35, 7.2, 0.0, 'yellow', 0.4, "http://google.com" );
        createCategory('A',1.35, 11.0, 0.0, 'red', 0.3, "http://yahoo.com");
        createCategory('D Print', 1.35, 14.0, 0.0, 'blue', 0.2, "http://msn.com");
        createCategory('C Design', 1.35, 17.3, 0.0, 'green', 0.1, "http://facebook.com");
        createCategory('N', 1.35, 12.2, 5.0, 'pink', 0.4, "http://stackoverflow.com");

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

        document.body.appendChild(renderer.domElement);
    }
    function onDocumentMouseDown(event) {
      event.preventDefault();


          var raycaster = new THREE.Raycaster(); // create once
          var mouse = new THREE.Vector2(); // create once
          mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
          mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;
          raycaster.setFromCamera( mouse, camera );

          var intersects = raycaster.intersectObjects(orbitContainer);
      if (intersects.length === 0) {
          window.open(orbitContainer.userData.URL);
      }
  }
    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {

        controls.update();

        renderer.render(scene, camera);
        requestAnimationFrame(animate);
    }

  }

【问题讨论】:

    标签: javascript three.js raycasting tween


    【解决方案1】:

    您的代码有 2 个问题:

    问题一:

    它带我到最后一个星球的 URL

    这是因为您使用相同的全局变量 orbitContainer 创建 5 个类别。每次你调用createCategory,URL 都会被覆盖,所以当你调用window.open(orbitContainer.userData.URL); 时,它会打开你分配的最后一个。发生的事情是这样的:

    orbitContainer.userData.URL = "http://google.com";
    orbitContainer.userData.URL = "http://yahoo.com";
    orbitContainer.userData.URL = "http://msn.com";
    orbitContainer.userData.URL = "http://facebook.com";
    orbitContainer.userData.URL = "http://stackoverflow.com";
    
    window.open(orbitContainer.userData.URL); // <- this opens stackoverflow
    
    

    解决方案:您应该从光线投射器的结果中获取 URL:

    intersects = raycaster.intersectObjects( scene.children );
    
    if (intersects.length > 0) {
        window.open(intersects[0].object.userData.URL);
    }
    

    问题2:

    当点击画布的任何部分时

    这是因为您在执行此操作时明确检查零交叉点:

    if (intersects.length === 0) {
        window.open(orbitContainer.userData.URL);
    }
    

    您应该使用if (intersects.length &gt; 0) 检查拦截,如上述解决方案所示。

    另外,请确保您正在使用场景的孩子执行光线投射:raycaster.intersectObjects( scene.children ); 而不是 orbitContainer,因为正如我所说,您每次创建新类别时都会覆盖它,它不会拥有所有里面的对象。

    【讨论】:

    • 嘿marquizzo,谢谢你的回答,我明天一定会回复你,当我回到这个问题时,我尝试了确切的解决方案,它在点击太阳能时会打开一个空白页面,但那是它。我想我会在有时间的时候更深入地研究它并回复你
    • 不幸的是,您的解决方案不起作用,它只允许您单击太阳能物体并打开一个空白选项卡。没有类别响应点击,也没有打开任何 URL。如果可以的话,您介意我们使用 Skype 或 Teamviewer 来解决这个问题吗?
    • 不,我对使用 Skype 进行个人咨询不感兴趣。为什么不直接使用console.log(intersects) 并开始在控制台中挖掘数组?在那里你会找到你点击的对象的所有信息,包括你创建的userData。祝你好运!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 2015-12-14
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2016-10-16
    • 1970-01-01
    相关资源
    最近更新 更多