【问题标题】:requestAnimationFrame is being called only oncerequestAnimationFrame 只被调用一次
【发布时间】:2017-09-13 22:37:12
【问题描述】:

我试图在我的 Ionic 2 应用程序中使用 ThreeJS 实现一个非常基本的动画。基本上试图旋转一个立方体。但是立方体没有旋转,因为 requestAnimationFrame 在渲染循环中只被执行一次。

我只能看到这个。

没有旋转动画。我在下面分享我的代码。

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)?

标签: angular three.js ionic2 requestanimationframe


【解决方案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();

【讨论】:

    【解决方案2】:

    问题是您没有正确调用 requestAnimationFrame。您不是直接将渲染函数传递给它,而是将一个返回渲染函数的 lambda 函数传递给它。

    requestAnimationFrame(() =&gt; this.render);这一行改为requestAnimationFrame(this.render);

    编辑:

    像您一样使用 ES2015 类时,请务必记住,类方法是声明为对象属性的函数。上下文 (this) 将是该方法附加到的对象。所以当将方法传递给requestAnimationFrame(...) 方法时,将不再使用相同的对象引用来调用它。正因为如此,我们需要在将渲染方法的上下文传递给requestAnimationFrame(...)之前绑定它:

    requestAnimationFrame(this.render.bind(this));
    

    这在this blog post 中得到了很好的解释。 (不要介意它专注于 React,原理和示例都是 ES2015 特定的)。

    【讨论】:

    • 是的,我首先尝试过这个。但是这样做编译器会抛出此错误 TypeError: Cannot read property 'render' of undefined。它无法识别 render 是方法。可能在这里以某种方式 this 上下文搞砸了。
    • @somnathbm requestAnimationFrame(this.render.bind(this)); 工作吗?
    • @somnathbm 更新了我的答案,如果你觉得有用,请标记为正确:)。
    • 为什么它会减慢我的机器速度?这是正确的方法吗?或者有什么办法可以取消动画帧?
    • @suchoss 我想现在我应该改写为“类”。没有其他变体。我理解你的困惑来自其他语言,这不是一回事。在其他语言中,类方法始终属于创建的实例,this 将始终相同。在 JavaScript 中,该方法在所有实例之间共享。 this 将是调用时附加的任何方法。在 ES2015 之前,声明类要冗长得多,但都是一样的。如果您要继续开发 JS,我建议您阅读有关 JS 类和原型链的更多信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多