动画更新时无法旋转每个网格

时间:2018-06-25 12:30:12

标签: three.js

我对Three.js很陌生,并且一直在尝试熟悉它。

我正在做此练习,在场景中添加了35个二十面体。我希望每个人在调用requestAnimationFrame时都旋转。

我认为,通过循环到每个组子元素(每个网格)并将值添加到x和y旋转,可以使网格旋转。为什么不是这样?任何帮助都非常感谢。谢谢。

这是我的方法

    var camera, scene, renderer;

    var geometry, material, mesh;

    var edgesGeometry, edgesMaterial, edges;

    var group;

    var mouseX = 0, mouseY = 0;

    var windowHalfX = window.innerWidth / 2;
    var windowHalfY = window.innerHeight / 2;

    init()
    animate()

    function init() {

      camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
      camera.position.z = 1500;

      scene = new THREE.Scene();

      group = new THREE.Group();

      for ( var i = 0; i < 35; i ++ ) {

        var randomSize = Math.floor( Math.random() * (150 - 20) + 20 )

        geometry = new THREE.IcosahedronGeometry( randomSize, 1 );
        material = new THREE.MeshBasicMaterial({ color: 0x000000 });

        mesh = new THREE.Mesh( geometry, material );

        mesh.position.x = Math.random() * 2000 - 1000;
        mesh.position.y = Math.random() * 2000 - 1000;
        mesh.position.z = Math.random() * 2000 - 1000;

        mesh.rotation.x = Math.random() * 2 * Math.PI;
        mesh.rotation.y = Math.random() * 2 * Math.PI;

        edgesGeometry = new THREE.EdgesGeometry( mesh.geometry )
        edgesMaterial = new THREE.LineBasicMaterial( { color: 0x63E260, linewidth: 2 } )
        edges = new THREE.LineSegments( edgesGeometry, edgesMaterial )
        mesh.add( edges )

        mesh.matrixAutoUpdate = false;
        mesh.updateMatrix();

        group.add( mesh );

      }

      scene.add( group );

      //

      renderer = new THREE.WebGLRenderer( { antialias: true } );
      renderer.setPixelRatio( window.devicePixelRatio );
      renderer.setSize( window.innerWidth, window.innerHeight );
      document.body.appendChild( renderer.domElement );

      //

      document.addEventListener( 'mousemove', onDocumentMouseMove, false );

      //

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

    }

    function onWindowResize() {

      windowHalfX = window.innerWidth / 2;
      windowHalfY = window.innerHeight / 2;
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize( window.innerWidth, window.innerHeight );

    }

    function onDocumentMouseMove( event ) {

      mouseX = ( event.clientX - windowHalfX ) * 0.25;
      mouseY = ( event.clientY - windowHalfY ) * 0.25;

    }

    function animate() {

      requestAnimationFrame( animate );

      for ( var i = 0; i < group.children.length; i ++ ) {

        group.children[i].rotation.x += 0.001;
        group.children[i].rotation.y += 0.001;

      }

      render();

    }

    function render() {

      camera.position.x += ( mouseX - camera.position.x ) * 0.05;
      camera.position.y += ( - mouseY - camera.position.y ) * 0.05

      camera.lookAt( scene.position );

      renderer.render( scene, camera );

    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.js"></script>

1 个答案:

答案 0 :(得分:2)

以扩展@ prisoner849的评论:

three.js渲染场景时,它将解析整个场景以寻找可渲染项(可见的,在视锥中的视图等)。该过程的一部分包括将转换矩阵相乘以填充每个可渲染项目的世界矩阵(matrixWorld)。可以想象,这可能是一个过程,因此您还可以关闭该自动更新。

您似乎已经了解了,因为您的代码行mesh.matrixAutoUpdate = false;确实做到了这一点,因此您可以通过手动更新网格的矩阵来进行后续操作。这在大多数情况下是正确的,但是您还需要针对每个帧执行

对于像您这样的简单/浅景深,@ prisoner849的方法是正确的-只需让three.js通过删除提到的行来自动更新矩阵即可。但是,如果您的场景更加复杂,并且想要对其进行更好的控制,则需要对要渲染的每一帧都施加这种控制。

在下面的示例中,我采用了您的原始代码并将其编码为仅使第二个二十面体旋转。这是通过将它们收集到一个数组中,然后仅更新该数组中对象的矩阵来完成的。 (还要注意,我关闭了整个场景而不是单个对象的矩阵自动更新。)

var camera, scene, renderer;

var geometry, material, mesh;

var edgesGeometry, edgesMaterial, edges;

var group;

var mouseX = 0,
  mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

var updatableObjects = [];

init()
animate()

function init() {

  camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = 1500;

  scene = new THREE.Scene();
  scene.autoUpdateMatrix = false; // turn off automatic matrix computation

  group = new THREE.Group();

  for (var i = 0; i < 35; i++) {

    var randomSize = Math.floor(Math.random() * (150 - 20) + 20)

    geometry = new THREE.IcosahedronGeometry(randomSize, 1);
    material = new THREE.MeshBasicMaterial({
      color: 0x000000
    });

    mesh = new THREE.Mesh(geometry, material);

    mesh.position.x = Math.random() * 2000 - 1000;
    mesh.position.y = Math.random() * 2000 - 1000;
    mesh.position.z = Math.random() * 2000 - 1000;

    mesh.rotation.x = Math.random() * 2 * Math.PI;
    mesh.rotation.y = Math.random() * 2 * Math.PI;

    edgesGeometry = new THREE.EdgesGeometry(mesh.geometry)
    edgesMaterial = new THREE.LineBasicMaterial({
      color: 0x63E260,
      linewidth: 2
    })
    edges = new THREE.LineSegments(edgesGeometry, edgesMaterial)
    mesh.add(edges)

    if (i % 2) {
      updatableObjects.push(mesh);
    }

    group.add(mesh);

  }

  scene.add(group);

  //

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  //

  document.addEventListener('mousemove', onDocumentMouseMove, false);

  //

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

}

function onWindowResize() {

  windowHalfX = window.innerWidth / 2;
  windowHalfY = window.innerHeight / 2;
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);

}

function onDocumentMouseMove(event) {

  mouseX = (event.clientX - windowHalfX) * 0.25;
  mouseY = (event.clientY - windowHalfY) * 0.25;

}

function updateMeshes(mesh) {
  mesh.rotation.x += 0.01;
  mesh.rotation.y += 0.01;
  mesh.updateMatrix();
}

function animate() {

  requestAnimationFrame(animate);

  updatableObjects.forEach(updateMeshes);

  render();

}

function render() {

  camera.position.x += (mouseX - camera.position.x) * 0.05;
  camera.position.y += (-mouseY - camera.position.y) * 0.05

  camera.lookAt(scene.position);

  renderer.render(scene, camera);

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/93/three.js"></script>