three.js:在场景中添加和替换对象

4
我正在使用three.js尝试以下内容,其中我有两个形状:“正方形”和“球”。
每个对象都有一个关联的按钮。如果用户点击一个按钮,相应的形状将被添加到场景中,但是,在任何时候场景中只能有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>
1个回答

4
考虑在您的<button>点击处理程序作用域之外跟踪“当前方块”形状,以确保从场景函数添加和删除这些形状的逻辑按预期进行。具体来说,您将希望使用当前方块形状(如果存在)调用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个正方形... - JamesKwon
不客气:-) 为了澄清一下 - 您将无法将相同的对象实例添加到场景中,但是如果您加载多个正方形副本,则可以将这些副本添加到场景中。 如果存在太多正方形,最终您的应用程序将变慢,但是100个正方形应该是相当可管理的。 希望这样说得清楚 :-) - Dacre Denny
啊,我想我明白了。由于加载程序只会“调用”一次,因此无论我点击多少次,每个对象只会有一个实例。在这种情况下,如果我点击了100次,场景中仍然只有1个square1.glb。 - JamesKwon
是的,你懂了 :-) - Dacre Denny

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接