THREE.jsをサンプルのまま作るとCPU使用率が半端じゃない件

最初に、ここで使っているのはTHREE.jsのRev.49なのでそのつもりで。
バージョン違いの場合はまた別の解があるかもです。


THREE.jsをサンプルのまま作ると、デュアルCPUであろうと最大限にCPUを使ってくれて常時100%近い。
ちなみにグラフィックボードをちゃんと搭載しているPCなら別として、ビジネス向けノートPCなどソフトウェアでがんばってる場合ね。


Webサイト表示してCPU100%なんて、正直いやだよねと。
CPU時間なんて最近そんな気になるもんでもないけど、ノートは熱くなるし、バッテリの消費も早いし、どっちにしろ使用率は少ないに越したことないだろと。


サンプルでよく見るのはこういう処理。

function animate() {
	requestAnimationFrame(animate);
	render();
}
function render() {
	renderer.render( scene, camera );
}

requestAnimationFrameは中身setTimeoutとほぼ等価なことが多いので、大したことない。
この程度じゃCPU使用率なんて知れてる。

setTimeout(animate, 1);

上記処理のどこが食っているかというと、renderer.render。
ゲームみたいに常時状況が変わるようなサイトでなければ、呼び出し続ける必要はない。
描画結果はCanvasに描かれるので、常時書いてないとVRAMが上書きされて出力内容を失ってしまうなんて事もないし、状況が変わった時にだけ書き直せばいい。


こうするだけでいい。

function animate() {
	requestAnimationFrame(animate);
	var is_update = false;
	//なんか更新処理。更新した場合is_update=true;
	if (is_update)  {
		render();
	}
}
function render() {
	renderer.render( scene, camera );
}

WebGLミニゲームとか作っても、CPU100%じゃすぐに廃れると思うので、Webページの一角に表示して遊ぶようなブログパーツとしてのWebゲームだったらちゃんと更新判定入れてほしいなと。




で、上記の更新判定入れれば実用には十分だけど、ここからもうちょっと掘り下げた話。
THREE.jsのWebGLRendererにはいくつかのプロパティがある。
パフォーマンスに影響しそうなのはこの辺。

  1. autoClear
  2. autoUpdateObjects
  3. autoUpdateScene
  4. sortObjects


どうもこの辺をいじれば落とせるんじゃないかな?と思って、sortObjects以外を全部をfalseにしてみると、当然何も描画されず、CPU使用率も低い。
こちらで認識している画面更新のタイミングで、それぞれの処理、つまり以下を実行すれば描画はされる。

renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
scene.updateMatrixWorld();
renderer.initWebGLObjects( scene );

これで画面更新のタイミング以外は全部自動系の処理が必要なくなったので、CPUもそんなに使わんだろーと思うと否。
これでもばっちり100%使ってくれる。


どうも描画対象オブジェクトをinitWebGLObjectsを使って登録した時点で、各オブジェクトに対するmatrixの更新処理とかが動いてしまうようで、こうなってしまうともう最後renderを呼び出しながらCPU利用率を落とす手段は無い模様。
こっちの手元だとWebGLRendererの3371行目から3411行目にあるfor文。これがあかん。
で、このfor文内の処理を軽くする方法はおそらく無い。


ということで、更新フラグで管理するしかないんじゃない、というのが結論です。