Help us understand the problem. What is going on with this article?

three.js超入門 第2回 アニメーションと時間ベースでの制御

More than 1 year has passed since last update.

概要

この記事では「three.js超入門」と題して、three.jsの基礎からシェーダーの利用までをやっていきます。
ターゲットは主に「canvas表現を触ったことがないフロントエンドエンジニア」を想定しているので、jsの構文などの説明は省略しています。
three.jsのバージョンは執筆時点で最新のr98を使用します。

three.js超入門 第0回 3Dコンピュータグラフィックスの基礎
three.js超入門 第1回 レンダリングまでの流れ
three.js超入門 第2回 アニメーションと時間ベースでの制御
three.js超入門 第3回 マウスやスクロールでのインタラクション
three.js超入門 第4回 getBoundingClientRect()を使ったDOM要素との連携
three.js超入門 第5回 シェーダー(GLSL)の基礎
three.js超入門 第6回 ShaderMaterialでメッシュを変形、着色する
three.js超入門 第7回 シェーダーに変数を渡す
three.js超入門 第8回 シェーダーをインタラクティブに動かす
three.js超入門 第9回 シェーダーでテクスチャにエフェクトをかける

リポジトリ

前回は3Dオブジェクトを静止画にレンダリングするところまでやりました。
今回はレンダリングのループ処理を作って3Dオブジェクトをアニメーションさせてみます。

アニメーション

javascriptでアニメーションを実装するには、window.requestAnimationFrame()を使用して描画ループを作成し、その中で数値を動かします。

描画ループを作る

Canvasクラスに描画ループ用のrender関数を作成します。
render関数内のrequestAnimationFrameで次のフレームにもrender関数が呼ばれるようにすることで、ループ処理を作っています。

src/00_empty/Canvas/index.js
// ~ 省略 ~

export default class Canvas {
  constructor() {
    // ~ 省略 ~

    // 画面に表示
    // this.renderer.render(this.scene, this.camera);

    // 描画ループ開始
    this.render();
  }

  render() {
    // 次のフレームを要求
    requestAnimationFrame(() => { this.render(); });

    // 画面に表示
    this.renderer.render(this.scene, this.camera);
  }
};

まだループの中でモデルを動かしていないので見た目には変化はありませんが、chromeの検証ツールでRendering > Paint flashingRendering > FPS meterにチェックを入れると、60fpsで再描画されていることがわかります。
box-fps.png

数値を動かす

それでは、描画ループ内で数値を動かして、アニメーションさせてみましょう。
render関数が1秒間に約60回呼ばれるので、1フレーム分の処理では小さい数値を足します。

src/00_empty/Canvas/index.js
render() {
  // 次のフレームを要求
  requestAnimationFrame(() => { this.render(); });

  // ちょっとずつ回転させる
  this.mesh.rotation.x += 0.01;
  this.mesh.rotation.y += 0.01;

  // 画面に表示
  this.renderer.render(this.scene, this.camera);
}

box-rotate.gif

ここで、ひとつ問題があります。
requestAnimationFrameは実行するブラウザによって処理の間隔が違うのです。
上記のコードは60fpsの環境では1秒間に0.6まで動きますが、30fpsの環境では1秒間に0.3までしかいきません。これではせっかく数値を調整しても違うブラウザで見た時に「思ってたんと違う、、😢」となってしまいます。
これを解決するには時間を元にパラメーターの数値を制御する必要があります。

時間ベースのアニメーション

時間の取得にはperformance.now()を使用します。
performance.now()はページ表示時からの経過時間がミリ秒で返ってくるため、1 / 1000にして単位を秒にすると数値の計算がしやすくなります。

src/00_empty/Canvas/index.js
render() {
  // 次のフレームを要求
  requestAnimationFrame(() => { this.render(); });

  // ミリ秒から秒に変換
  const sec = performance.now() / 1000;

  // 1秒で45°回転する
  this.mesh.rotation.x = sec * (Math.PI / 4);
  this.mesh.rotation.y = sec * (Math.PI / 4);

  // 画面に表示
  this.renderer.render(this.scene, this.camera);
}

これでブラウザ間でのfpsの差異に影響されないようになりました。

rotationだけでなく、positionscaleもアニメーションさせてみましょう!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした