LoginSignup
21
21

More than 5 years have passed since last update.

three.jsで簡易残像表示

Last updated at Posted at 2017-05-19

(R84利用)

Processingでよくやる手抜きモーションブラー的なやつがthree.jsで若干つまづいた+意外と情報がなかったのでメモ。まず呼び方がわからない。

こういうやつ。

スクリーンショット 2017-05-17 20.14.45.png

この描画量でTHREE.Line30本で済むのでエコ。

Processingの場合どうやっていたのか

// メインループ
void draw(){
  // 通常特定の色でクリアするところを
  // background(0);

  // 半透明のrectでちょっとずつフェードアウト
  noStroke();
  fill(0, 20);
  rect(0, 0, width, height);

  // なんらかの描画処理
  // ...
}

同じことをしようとしてthree.jsでつまづいた点

  • 普通に書くときっちりクリアされてしまう
  • 背景も回ってしまう
  • renderer.autoClear = false;ではないっぽい
  • 軌跡表示まではできたのに半透明処理がおかしくなる

ということで色々検索したり検索したりしながら最終的に動いたコードの中から必須な箇所をピックアップ。

Three.jsコード

レンダラー設定

THREE.WebGLRendererでpreserveDrawingBufferを有効にする。

var renderer = new THREE.WebGLRenderer({
  preserveDrawingBuffer: true //これが重要
});
renderer.autoClearColor = false; //  これも必須
// renderer.autoClear = false; //これは不要

autoClearをfalseにするのではなくautoClearColorfalseにする
この辺を間違えるとpreserveDrawingBuffer: trueの状態だと背景オブジェクトに重なった部分が一切描画されないという状態になり困る。

描画を少しずつ消していくため半透明のplaneオブジェクトを追加

描画したいオブジェクトと同じシーンを使うとカメラを回した時に同じように回ってしてしまうので、planeオブジェクトのみを扱うシーンとカメラを追加する。この場合のカメラはTHREE.OrthographicCameraを使うと便利(WIDTH, HEIGHTは別途定義したcanvasサイズ定数)

var scene_bg = new THREE.Scene();
var camera_bg = new THREE.OrthographicCamera(0, WIDTH, HEIGHT, 0, 0, 1000);
var bg_geometry = new THREE.PlaneGeometry(WIDTH, HEIGHT, 10, 10);
var bg_material = new THREE.MeshBasicMaterial({
  color: 0x000000,
  transparent: true,
  opacity: .04,
});
var bg = new THREE.Mesh(bg_geometry, bg_material);

//位置調整して追加
bg.position.x = WIDTH/2;
bg.position.y = HEIGHT/2;
scene_bg.add(bg);

transparent: trueがないと半透明にならないので忘れないようにして、opacityの値で減衰速度を調整。

残像表示するメインのオブジェクトを追加

描画するオブジェクトは適当なものを適当に追加して動かす。動かさないと何も起こらない。
またマテリアルによってはライト追加するまで出来ているのか判断しづらいので一旦wireframe状態で行うとわかりやすい。

var box = new THREE.BoxGeometry(2, 2, 2);
var mat = new THREE.MeshBasicMaterial({
  color: 0xffffff,
  wireframe: true    // wireframeである必要はないが効果が確認しやすい
});
var mesh = new THREE.Mesh(box, mat);
scene.add(mesh);

他Line系のTHREEオブジェクトやモデリングデータをwireframe表示したものもそれっぽくなりやすい。

レンダーループ(requestAnimationFrame内部)

// boxgeometryを回す。
mesh.rotation.x+=.01;
mesh.rotation.y+=.02;

// レンダー
renderer.render( scene_bg, camera_bg );
renderer.render( scene, camera );

背景>メインの順でレンダリングする。

カリングなどの全面・背面の描画周りには特に触れる必要がなかった。
renderPassなど使うときのようなrenderer.autoClear = false;も不要。
あとは適当にラインを置いて加算合成しつつ回したものが最初に貼った画像になります。

描画結果

スクリーンショット 2017-05-20 3.32.58.png

最小構成コード(js)
https://gist.github.com/nanonum/99fa67c6bef13a8d60fc55bd82e4c883

メモ

processingのだいぶ古い本で当たり前のように書いてあった気がするテクニックのため、検索ワードが完全に間違っているだけでこれをやるためのクラスが普通に用意されている可能性も捨てきれていない。

21
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21