【问题标题】:Why cubes do not always animate with three.js为什么立方体并不总是使用 three.js 进行动画处理
【发布时间】:2019-12-30 17:30:49
【问题描述】:

在下面的代码中,立方体有时会随着动画移动,有时则不会。我该如何解决?

另外,我应该如何设置旋转速度?

new Vue({
  el: '#app',
  data () {
    return {
      camera: null,
      scene: null,
      renderer: null,
      cube: null,
      angle: null
    }
  },
  methods: {
    init: function () {

      this.camera = new THREE.PerspectiveCamera(1, 1);
      this.camera.position.z = 200;

      // Make a scene
      this.scene = new THREE.Scene();

      this.clock = new THREE.Clock();

      //
      this.renderer = new THREE.WebGLRenderer({
        antialias: true,
        alpha: true
      });
      let container = document.getElementById('container')
      this.renderer.setSize(container.offsetWidth, container.offsetHeight);
      container.appendChild(this.renderer.domElement);

      let cube2 = this.createCube()
      cube2.name = "cube2"
      //       cube2.position = new THREE.Vector3(1, 0)
      this.scene.add(cube2);

    },
    createCube: function () {

      // GEOMETRY

      // 1. Start with empty geometry
      let geometry = new THREE.Geometry();

      // 2. Add vertices to geometry
      geometry.vertices.push(
        // verts [0-3] are in in +z
        new THREE.Vector3(-1, 1, 1),
        new THREE.Vector3(-1, -1, 1),
        new THREE.Vector3(1, -1, 1),
        new THREE.Vector3(1, 1, 1),
        // verts [4-7] in -z
        new THREE.Vector3(-1, 1, -1),
        new THREE.Vector3(-1, -1, -1),
        new THREE.Vector3(1, -1, -1),
        new THREE.Vector3(1, 1, -1),
      );

      // 3. Connect vertices in desired order to make faces
      let b = 0x1db0ec
      let y = 0xffef3a
      let r = 0xea353d
      let w = 0xffffff

      // Set half faces
      geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
      geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
      geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
      geometry.faces.push(new THREE.Face3(6, 4, 7)); // red

      // Set whole faces
      geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
      geometry.faces.push(new THREE.Face3(5, 0, 4));
      geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
      geometry.faces.push(new THREE.Face3(5, 6, 2));
      geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
      geometry.faces.push(new THREE.Face3(3, 6, 7));
      geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
      geometry.faces.push(new THREE.Face3(3, 7, 4));

      // Set faces colors
      geometry.faces[0].color.setHex(b); // Half face
      geometry.faces[1].color.setHex(y);
      geometry.faces[2].color.setHex(w);
      geometry.faces[3].color.setHex(r);
      geometry.faces[4].color.setHex(b); // Whole face
      geometry.faces[5].color.setHex(b);
      geometry.faces[6].color.setHex(w);
      geometry.faces[7].color.setHex(w);
      geometry.faces[8].color.setHex(r);
      geometry.faces[9].color.setHex(r);
      geometry.faces[10].color.setHex(y);
      geometry.faces[11].color.setHex(y);

      // MATERIAL

      // Make a material
      let material = new THREE.MeshBasicMaterial({
        // color: 0x00FF00,
        vertexColors: THREE.FaceColors,
        wireframe: false,
      });

      // MESH

      let cube = new THREE.Mesh(geometry, material);
      return cube
    },
    rotateTo: function (face) {

      if (face == 'yellow')
        this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
      else if (face == 'red')
        this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
      else if (face == 'blue')
        this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, - Math.PI / 2));
      else if (face == 'white')
        this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(- Math.PI / 2, Math.PI / 2, 0));
      else if (face == 'yb')
        this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
      else if (face == 'rw')
        this.angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));

      this.animate()

    },
    animate: function () {

      let id = requestAnimationFrame(this.animate);

      let delta = this.clock.getDelta();
      this.scene.children[0].quaternion.rotateTowards(this.angle, Math.PI * delta);

      this.renderer.render(this.scene, this.camera);

      if (this.scene.children[0].quaternion.equals(this.angle)) {
        cancelAnimationFrame(id)
      }

    }
  },
  mounted () {
    this.init();
    this.renderer.render(this.scene, this.camera);
  }
})
#container {
  background-color: #aaa;
  width: 20em;
  height: 20em;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://threejs.org/build/three.min.js"></script>

<div id="app">
    <div>
      <button v-on:click="rotateTo('yellow')">yellow</button>
      <button v-on:click="rotateTo('red')">red</button>
      <button v-on:click="rotateTo('blue')">blue</button>
      <button v-on:click="rotateTo('white')">white</button>
      <button v-on:click="rotateTo('yb')">yellow/blue</button>
      <button v-on:click="rotateTo('rw')">red/white</button>
    </div>

    <div id="container"></div>
</div>

更新

代码只隔离到threejs部分。

var camera = null;
var scene = null;
var renderer = null;
var cube = null;
var angle = null;

init();
renderer.render(scene, camera);

function init() {

	camera = new THREE.PerspectiveCamera(1, 1);
	camera.position.z = 200;

	// Make a scene
	scene = new THREE.Scene();

	clock = new THREE.Clock();

	//
	renderer = new THREE.WebGLRenderer({
		antialias: true,
		alpha: true
	});
	let container = document.getElementById('container');
	renderer.setSize(container.offsetWidth, container.offsetHeight);
	container.appendChild(renderer.domElement);

	let cube2 = createCube();
	cube2.name = "cube2";
	//       cube2.position = new THREE.Vector3(1, 0)
	scene.add(cube2);

}

function createCube() {

	// GEOMETRY

	// 1. Start with empty geometry
	let geometry = new THREE.Geometry();

	// 2. Add vertices to geometry
	geometry.vertices.push(
		// verts [0-3] are in in +z
		new THREE.Vector3(-1, 1, 1),
		new THREE.Vector3(-1, -1, 1),
		new THREE.Vector3(1, -1, 1),
		new THREE.Vector3(1, 1, 1),
		// verts [4-7] in -z
		new THREE.Vector3(-1, 1, -1),
		new THREE.Vector3(-1, -1, -1),
		new THREE.Vector3(1, -1, -1),
		new THREE.Vector3(1, 1, -1),
	);

	// 3. Connect vertices in desired order to make faces
	let b = 0x1db0ec;
	let y = 0xffef3a;
	let r = 0xea353d;
	let w = 0xffffff;

	// Set half faces
	geometry.faces.push(new THREE.Face3(0, 1, 2)); // blue
	geometry.faces.push(new THREE.Face3(0, 2, 3)); // yellow
	geometry.faces.push(new THREE.Face3(5, 4, 6)); // white
	geometry.faces.push(new THREE.Face3(6, 4, 7)); // red

	// Set whole faces
	geometry.faces.push(new THREE.Face3(1, 0, 5)); // blue
	geometry.faces.push(new THREE.Face3(5, 0, 4));
	geometry.faces.push(new THREE.Face3(1, 5, 2)); // white
	geometry.faces.push(new THREE.Face3(5, 6, 2));
	geometry.faces.push(new THREE.Face3(2, 6, 3)); // red
	geometry.faces.push(new THREE.Face3(3, 6, 7));
	geometry.faces.push(new THREE.Face3(0, 3, 4)); // yellow
	geometry.faces.push(new THREE.Face3(3, 7, 4));

	// Set faces colors
	geometry.faces[0].color.setHex(b); // Half face
	geometry.faces[1].color.setHex(y);
	geometry.faces[2].color.setHex(w);
	geometry.faces[3].color.setHex(r);
	geometry.faces[4].color.setHex(b); // Whole face
	geometry.faces[5].color.setHex(b);
	geometry.faces[6].color.setHex(w);
	geometry.faces[7].color.setHex(w);
	geometry.faces[8].color.setHex(r);
	geometry.faces[9].color.setHex(r);
	geometry.faces[10].color.setHex(y);
	geometry.faces[11].color.setHex(y);

	// MATERIAL

	// Make a material
	let material = new THREE.MeshBasicMaterial({
		// color: 0x00FF00,
		vertexColors: THREE.FaceColors,
		wireframe: false,
	});

	// MESH

	let cube = new THREE.Mesh(geometry, material);
	return cube;
}

function rotateTo(face) {

	if (face == 'yellow')
		angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, Math.PI / 2, Math.PI / 2));
	else if (face == 'red')
		angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, Math.PI / 2));
	else if (face == 'blue')
		angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI / 2, 0, -Math.PI / 2));
	else if (face == 'white')
		angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, Math.PI / 2, 0));
	else if (face == 'yb')
		angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
	else if (face == 'rw')
		angle = new THREE.Quaternion().setFromEuler(new THREE.Euler(Math.PI, 0, 0));

	animate();

}

function animate() {

	let id = requestAnimationFrame(animate);

	let delta = clock.getDelta();
	scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta);

	renderer.render(scene, camera);

	if (scene.children[0].quaternion.equals(angle)) {
		cancelAnimationFrame(id);
	}

}
#container {
      background-color: #aaa;
      width: 20em;
      height: 20em;
    }
<script src="https://threejs.org/build/three.min.js"></script>

        <div>
          <button onclick="rotateTo('yellow')">yellow</button>
          <button onclick="rotateTo('red')">red</button>
          <button onclick="rotateTo('blue')">blue</button>
          <button onclick="rotateTo('white')">white</button>
          <button onclick="rotateTo('yb')">yellow/blue</button>
          <button onclick="rotateTo('rw')">red/white</button>
        </div>

        <div id="container"></div>

【问题讨论】:

  • 你能把代码隔离到只有threejs部分吗?好像有很多vue相关的东西。
  • @pailhead 我刚刚通过在第二个 sn-p 中删除所有与 vue 相关的东西来更新我的代码。

标签: three.js


【解决方案1】:

动画没有播放的原因是因为当你cancelAnimationFrame时时钟还在运行,所以下次你调用rotateTo时,delta太高以至于动画立即结束。

您可以通过使用cancelAnimationFrame 停止时钟来避免这种情况,并在调用rotateTo 时重新启动它,如下所示:

function rotateTo(face) {
  clock.start()
  ...
}
function animate() {
    ...
    if (scene.children[0].quaternion.equals(angle)) {
        cancelAnimationFrame(id);
        clock.stop()
    }
}

至于旋转速度,rotateTowards 的第二个参数是 step,它决定了它到达那里的速度。所以如果给它加一个修饰符var,就可以控制速度了。

let rotSpeedMotifier = 0.2 // the higher the faster
scene.children[0].quaternion.rotateTowards(angle, Math.PI * delta * rotSpeedMotifier );

【讨论】:

    猜你喜欢
    • 2015-01-28
    • 1970-01-01
    • 2013-02-16
    • 2014-08-13
    • 1970-01-01
    • 2012-01-22
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    相关资源
    最近更新 更多