requestAnimationFrame仅被调用一次

16
我正在尝试在我的Ionic 2应用中使用ThreeJS实现一个非常基本的动画。基本上是试图旋转一个立方体。但是,由于render循环中只执行了一次requestAnimationFrame,所以立方体没有旋转。
我只能看到这个:enter image description here没有旋转动画。我在下面分享了我的代码。 home.html
<ion-header>
  <ion-navbar>
    <ion-title>
      Ionic Blank
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content>
  <div #webgloutput></div>
</ion-content>

home.ts

import { Component, ViewChild, ElementRef } from '@angular/core';
import { NavController } from 'ionic-angular';

import * as THREE from 'three';


@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  @ViewChild('webgloutput') webgloutput: ElementRef;


  private renderer: any;
  private scene: any;
  private camera: any;
  private cube: any;

  constructor(public navCtrl: NavController) {
  }

  ngOnInit() {
    this.initThree();
  }

  initThree() {
    this.scene = new THREE.Scene();
    this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setSize( window.innerWidth, window.innerHeight );
    this.webgloutput.nativeElement.appendChild(this.renderer.domElement);

    let geometry = new THREE.BoxGeometry(1, 1, 1);

    let material = new THREE.MeshBasicMaterial({ color: 0x00ff00});
    this.cube = new THREE.Mesh(geometry, material);
    this.scene.add(this.cube);
    this.camera.position.z = 5;

    this.render();
  }


  render() {
    console.log("render called");
    requestAnimationFrame(() => this.render);

    this.cube.rotation.x += 0.5;
    this.cube.rotation.y += 0.5;
    this.renderer.render(this.scene, this.camera);
  }

}

尝试一下...当你调用this.render()时,将其放入setInterval(function(){that.render}, 50)中? - getbuckts
2个回答

41
问题在于你没有正确调用requestAnimationFrame。你没有直接传递render函数,而是传递了一个返回render函数的箭头函数。
将代码行requestAnimationFrame(() => this.render);改为requestAnimationFrame(this.render); 然而,当将类方法用作回调函数(作为参数)时,它将不再以相同的this引用调用。在你的情况下,当在requestAnimationFrame中调用render方法时,render方法中的this将变为undefined,导致错误消息TypeError: Cannot read property 'render' of undefined。有多种方法可以避免这种行为,但我认为最简单的方法是将render方法显式绑定到正确的this上。
requestAnimationFrame(this.render.bind(this));

是的,我在第一时间就尝试过了。但是这样做编译器会抛出 TypeError: 无法读取未定义的属性 'render' 的错误。它无法识别 render 是该方法。可能是由于上下文中的 this 出了问题。 - somnathbm
3
@somnathbm 问:requestAnimationFrame(this.render.bind(this)); 是否有效? - micnil
@somnathbm 我更新了我的答案,请标记为正确,如果您觉得有用的话 :)。 - micnil
为什么它会减慢我的机器?这是正确的方法吗?还是有任何取消animationframes的方法? - Umesh Patadiya
@micnil的第二部分帮了我不少。我读了你提供的博客文章,但是读完之后我反而比以前更困惑了。我能否使用除了ES2015以外的其他类使得JavaScript的行为表现正常?因为与其他编程语言相比,目前的行为对我来说没有意义。 - suchoss
1
@suchoss 我认为现在我应该重新表述一下,只说“类”。没有其他变体。我理解你的困惑来自其他语言,但这不是同一件事。在其他语言中,类方法总是属于创建的实例,this始终相同。在JavaScript中,该方法在所有实例之间共享。当调用时,this将是附加到该方法的任何内容。在ES2015之前,声明类要冗长得多,但它是相同的东西。如果您要继续开发JS,我建议您阅读更多关于JS类和原型链的内容。 - micnil

1
requestAnimationFrame的目的不是做动画,它的目的是在下一帧调用提供的函数,因此基本上我们在每一帧都调用相同的函数。
requestAnimationFrame(justNameofFun);

例如

const clock = new THREE.Clock();
const tick = () => {
  const elapsedTime = clock.getElapsedTime()
  cube1.rotation.y = elapsedTime * Math.PI * 1;
  renderer.render(scene, camera);
  window.requestAnimationFrame(tick);
};

// 至少调用一次以执行requestanimationframe

tick();

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