【问题标题】:three.js: Adding and replacing objects in scenethree.js:在场景中添加和替换对象
【发布时间】:2019-02-05 22:57:44
【问题描述】:

我正在使用 three.js 尝试以下操作,其中有 2 个形状:“正方形”和“球体”。

每个对象都有一个与之关联的按钮。如果用户点击一个按钮,相应的形状将被添加到场景中,但是,任何时候一个场景中只能有 1 个正方形和 1 个球体。

如果用户添加一个新方块,它应该替换旧方块。尽管使用下面的代码,我似乎无法实现这一点。目前,我可以成功添加正方形和球体对象,但是,当我单击添加另一个正方形时,当​​前正方形不会被替换。

请指教,谢谢!

<html>
  <head>
    <title>My second three.js app</title>
    <style>
      body { margin: 0; }
      canvas { width: 100%; height: 100% }
    </style>
  </head>
  <body>
    <button id="button1">Square1</button>
    <button id="button2">Square2</button>
    <button id="button3">Sphere</button>
    <script src="js/three.js"></script>
    <script>
  var scene = new THREE.Scene();
  var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

  var renderer = new THREE.WebGLRenderer();
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  loader.load( ‘square1.glb’, function ( geometry ) {

    geometry.scene.traverse( function ( node ) {

        if ( node.isMesh ){
            square = node;
            square.material.map.anisotropy = maxAnisotropy;
        }

    document.getElementById("button1").addEventListener("click", function(){
      scene.remove(square);
      scene.add(square);

    });

  });

  loader.load( ‘square2.glb’, function ( geometry ) {

    geometry.scene.traverse( function ( node ) {

      if ( node.isMesh ){
          square = node;
          square.material.map.anisotropy = maxAnisotropy;
      }

    document.getElementById("button2").addEventListener("click", function(){
      scene.remove(square);
      scene.add(square);

    });

  });

  loader.load( ‘sphere.glb’, function ( geometry ) {

    geometry.scene.traverse( function ( node ) {

      if ( node.isMesh ){
          sphere = node;
          sphere.material.map.anisotropy = maxAnisotropy;
      }

    document.getElementById("button3").addEventListener("click", function(){

    scene.add(sphere);

    });

  });

  var animate = function () {
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
  };

  animate();
</script>
  </body>
</html>

【问题讨论】:

    标签: javascript three.js


    【解决方案1】:

    考虑在&lt;button&gt; 点击处理程序范围之外跟踪“当前正方形”形状,以确保在scene 中添加和删除这些形状的逻辑按预期运行。

    具体来说,您需要使用当前方形(如果存在)调用scene.remove(),而不是使用随后调用scene.add() 的形状对象调用它:

    /* Current code */
    document.getElementById("button1").addEventListener("click", function(){
    
      scene.remove(square); /* You're removing the square object here, */
    
      scene.add(square); /* and then adding the same square object to the scene */
    });
    

    您可能会发现如下调整脚本很有用:

    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
    
    var renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
    
    /*
    Not sure where you get your loader object from
    */
    var loader = ''; // ??
    
    /* 
    Add this to track current shapes
    */
    var currentSquare = '';
    var currentSphere = '';
    
    /*
    Define a general, reusable method for loading geometry
    */
    function loadShape(filename, onLoaded) {
    
      loader.load( filename, function ( geometry ) {
    
            var foundMesh = '';
    
            geometry.scene.traverse( function ( node ) {
                if ( node.isMesh ){
                    foundMesh = node;
                    foundMesh.material.map.anisotropy = maxAnisotropy;
                }
            });
    
            if(foundMesh) {
                onLoaded(foundMesh)
            }
        }
    }
    
    /*
    Use the general loader method defined above
    */
    loadShape('square1.glb', function(nextSquare) {
    
        document.getElementById("button1").addEventListener("click", function(){
    
            /*
            If current square exists, remove it
            */
            if(currentSquare) {
                scene.remove(currentSquare);
            }
    
            /*
            Add the square for the button just clicked 
            and update currentSquare
            */
            scene.add(nextSquare);  
            currentSquare = nextSquare;
        });
    })
    
    loadShape('square2.glb', function(nextSquare) {
    
        document.getElementById("button2").addEventListener("click", function(){
    
            if(currentSquare) {
                scene.remove(currentSquare);
            }
    
            scene.add(nextSquare);  
            currentSquare = nextSquare;
        });
    })
    
    loadShape('sphere.glb', function(nextSphere) {
    
        document.getElementById("button3").addEventListener("click", function(){
    
            if(currentSphere) {
                scene.remove(currentSphere);
            }
    
            scene.add(nextSphere);  
            currentSphere = nextSphere;
        });
    })
    
    var animate = function () {
      requestAnimationFrame( animate );
      renderer.render( scene, camera );
    };
    
    animate();
    

    希望这会有所帮助!

    【讨论】:

    • 太棒了!我真的很喜欢通用的可重用功能,使调试变得容易得多。另一个问题是:如果我不断将相同的对象添加到场景中,会不会出现性能问题?例如,如果我很高兴,我会点击 button1 并添加 100 个方块...
    • 不客气 :-) 。澄清一下 - 您将无法将对象的相同 instance 添加到场景中,但是如果您加载正方形的多个副本,则可以将它们添加到场景中。如果存在太多方块,最终您的应用程序会变慢,但是 100 个方块应该是可以管理的。希望这是有道理的:-)
    • 啊,我想我明白了。由于加载器只“调用”一次,因此无论我点击多少次,每个对象都只会有一个实例。在这种情况下,如果我点击 100 次,场景中仍然只有 1 个 square1.glb。
    • 是的,你明白了 :-)
    猜你喜欢
    • 1970-01-01
    • 2016-02-03
    • 2015-03-12
    • 2015-11-21
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多