(R84利用)
Processingでよくやる手抜きモーションブラー的なやつがthree.jsで若干つまづいた+意外と情報がなかったのでメモ。まず呼び方がわからない。
こういうやつ。
この描画量で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にするのではなくautoClearColor
をfalse
にする
この辺を間違えると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;
も不要。
あとは適当にラインを置いて加算合成しつつ回したものが最初に貼った画像になります。
描画結果
最小構成コード(js)
https://gist.github.com/nanonum/99fa67c6bef13a8d60fc55bd82e4c883
メモ
processingのだいぶ古い本で当たり前のように書いてあった気がするテクニックのため、検索ワードが完全に間違っているだけでこれをやるためのクラスが普通に用意されている可能性も捨てきれていない。