three.jsをもっと手軽にするユーティリティパッケージ「ore-three」

###更新
- 2019/06/20　v.0.2.1更新

# 概要
three.jsむちゃくちゃ便利ですよね...
もう僕はこれなしにWebGLを動かすなんて無理です（甘え)
なのですが、three.jsですら何個もプロジェクトを作っていると、シーンとかレンダラーとかリサイズとかマウスとか.... まあまあめんどくさいですよね。

そんなめんどっちい事を全て忘れられるパッケージを作ったので紹介します。
名付けて`ore-three` です。 ~~ネーミングセンスを疑います。~~

npm : [ore-three-ts](https://www.npmjs.com/package/ore-three-ts)
GitHub : [ore-three-ts](https://github.com/ukonpower/ore-three-ts)

名前からもわかる通り、TypeScriptで作ってます。多分jsでも動かせると思います。

# 使い方

## 1. `ore-three`をゲットする

```
$ npm install ore-three-ts
```

これだけ！

npmを使いたくない人はこいつをどうぞ。
[github: ore-three-ts (build)](https://github.com/ukonpower/ore-three-ts/blob/master/build/ore-three.js)

## 2.インポート
ore-threeをインポートします。
ビルド版を使う場合は多分`ORE`オブジェクトが使えるようになっていると思います。

```typescript
import * as ORE from 'ore-three-ts';
```

## 4. シーンを作成
`THREE.Camera`や`THREE.Scene`、タッチイベントなどを保持する`ORE.BaseScene`を継承したクラスを作成します。
コンストラクタには後でつくる、`ORE.Controller`からの`THREE.WebGLRenderer`を渡します。

```javascript:MainScene.js
import * as ORE from 'ore-three-ts';
import * as THREE from 'three';

export default class MainScene extends ORE.BaseScene{
	constructor(renderer){
		super(renderer);
		this.camera.position.set(0, 1.5, 3);
		this.camera.lookAt(0, 0, 0);
		
		let geo = new THREE.BoxGeometry(1,1,1);
		let mat = new THREE.MeshNormalMaterial();
		this.box = new THREE.Mesh(geo,mat);
		this.scene.add(this.box);
	}

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

	onResize(width,height){
		super.onResize(width, height);
	}

	onTouchStart(e) {
	}

	onTouchMove(e) {
	}

	onTouchEnd(e) {
	}

	onWheel(e) {
	}
}
```

`onTouch~~`や`onWheel`は画面クリック、タッチ、マウスホイール時に呼ばれるメソッドです。

## 3.`ORE.Controller`を作成、シーンをセット
レンダラーの作成・保持、リサイズ、アニメーションループをしてくれる、`ORE.Controller`を作成します。 `Controller`のコンストラクタに渡すパラメータは`THREE.WebGLRenderer`のパラメータを継承したもので、追加項目としてretina解像度に対応させるための`retina: bool`があります。

```javascript:index.js
import * as ORE from '../../src/';
import OREScene from './scenes/MainScene';

class APP {

	constructor() {
		
		this.controller = new ORE.Controller( {

			canvas: document.querySelector( "#canvas" ),
			retina: false,
			alpha: false,

		} );
	
		this.controller.setScene( OREScene );

	}

}

window.addEventListener( 'load', ()=>{

	let app = new APP();

} );

```

最小構成は以上です。これだけで、こんな絵が出ます。

<img width="948" alt="スクリーンショット 2019-05-20 23.21.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280075/913cf2bc-22b3-3501-dd88-9e962341a76c.png">


# まだまだいっぱいあるよ、ユーティリティ
`ore-three`には自分的に需要のあるクラスをどしどし詰め込んでいるのでいくつかご紹介します。
サンプルコードはGitにもあげています。
[Github: ore-three-ts (examples)](https://github.com/ukonpower/ore-three-ts/tree/master/examples/js/scenes)

## `ORE.PostProcessing`
ポストプロセシングです。three.js公式のものより手軽さを重視しました。
[GitHub: PostProcessingScene](https://github.com/ukonpower/ore-three-ts/blob/master/examples/js/scenes/PostProcessingScene.js)

### 使い方

1. `ORE.PostProcess`を生成
	複数のポストプロセスを一気にかけられるようになっています。
	一つのポストプロセスは以下のオブジェクトで定義されます。

	```javascript
	{
		fragmentShader: /* ポストプロセス用のフラグメントシェーダ */,
		uniforms: /* フラグメントシェーダーに渡すuniform変数 */
	}
	```

	これを配列にしてコンストラクタに渡します。

	```javascript
	this.ppParam = [
		{
			fragmentShader: ppFrag,
			uniforms:{
				time:{
					value: 0
				}
			}
		}
	]

	this.pp = new ORE.PostProcessing(this.renderer,this.ppParam);
	```

	フラグメントシェーダーにはuvがvarying変数`vUv`、一つ前のレンダリング結果がuniform変数`backbuffer`として入力されます。

	```glsl:ppFrag.fs
	varying vec2 vUv;
	uniform sampler2D backbuffer;

	uniform float time;

	float random (vec2 st) {
		return fract(sin(dot(st.xy, vec2(12.9898,78.233)))* 43758.5453123);
	}

	void main(void){
		vec3 c = texture2D(backbuffer,vUv).xyz;
		c += random(vUv + time);
		gl_FragColor = vec4(c,1.0);
	}
	```

2. `render`メソッドでレンダリング

	```javascript
	this.pp.render(this.scene,this.camera);
	```

	`render`メソッドはレンダリングソースとして`Scene`と`Camera`を渡す以外にも、**テクスチャを渡すこともできます**。
	また、最後の引数ではオフスクリーンレンダリングをするかのフラグを渡すこともできます。  
	オフスクリーンレンダリングをした場合、レンダリング結果は`getResultTexture`メソッドで取得できます。

	```javascript
	//シーンとカメラをソースに、オフスクリーンレンダリング
	this.postprocess1.render(this.scene,this.camera,true);

	//postprocess1のレンダリング結果をテクスチャとして取得
	let pp1_Result = this.postprocess1.getResultTexture();

	//postprocess1のレンダリング結果をソースとしてpostprocess2をディスプレイに出力
	this.postprocess2.render(pp1_Result,false);
	```

## `ORE.DomGLSL`
僕的にとても便利なクラスです。
**HTMLの要素を渡せばそのサイズに合わせた長方形のメッシュが生成**されます。
独自のフラグメントシェーダーを渡し、特定HTML要素の背景で好きなシェーダーを描画することができます。

### 使い方

1. コンストラクタに渡すパラメータは以下のようになっています。

	```javascript
	{
		dom: /* DOM要素 */,
		fragmentShader: /* フラグメントシェーダー */,
		uniforms: /* uniform変数 */
	}
	```

	これをコンストラクタに渡します。
	`THREE.Object3D`を継承しているのでそのまま`THREE.Scene`に`add`することができます。

	```javascript
	this.param = {
		dom: document.querySelector('.dom-glsl'),
		fragmentShader: frag,
		uniforms: {
			time:{ value : 0 } 
		}
	}

	this.domglsl = new ORE.DomGLSL(this.param);
	this.scene.add(this.domglsl);
	```

2. DOMの形や位置が変わったタイミングで`updateDom`メソッドを実行します。

	```javascript
	this.domglsl.updateDom();
	```

こんな感じでDOMに合わせたメッシュが生成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280075/2d0d76ba-d26d-2a9c-4767-4c01c0a276cd.png)

## `ORE.MouseRotator`
`MouseRotator`はマウスやタッチ操作で簡単にオブジェクトをくるくる回すことができるクラスです。
こんな感じの動きになります。
[Ore-GL: Ring](https://oregl.ukon.dev/gl/24/)

### 使い方

1. `ORE.MouseRotator`を作成

	回転を加えたいオブジェクトを渡します。

	```javascript
	let boxGeo = new THREE.BoxGeometry(1, 1, 1);
	let boXMat = new THREE.MeshNormalMaterial();
	this.box = new THREE.Mesh(boxGeo, boXMat);
	this.scene.add(this.box);

	this.rotator = new ORE.MouseRotator(this.box);
	```
1. マウスの移動量を渡す

	`BaseScene`が持っている`cursor`からマウスの移動量`deltaX`と`deltaY`が取得できるのでそれを`THREE.Vector2`型にして渡します。

	```javascript
	onTouchMove(e) {
		this.rotator.addVelocity(new THREE.Vector2(this.cursor.deltaX,this.cursor.deltaY));
	}
	```

1. 毎フレームおきに`update`をかける

	```javascript
	this.rotator.update()
	```

## `ORE.TransformAnimator`
オブジェクトの移動と回転の簡単な補完をしてくれます。

### 使い方
1. `TransformAnimator`を作成
	コントロールしたいオブジェクトをコンストラクタに渡します。

	```javascript
	this.transformAnimator = new ORE.TransformAnimator(this.box);
	```

1. `TransformAnimator`を毎フレーム更新します。　　
	引数に`deltaTime`を渡すと、フレームレートが落ちた場合でも移動速度が落ちなくなります。

	```javascript
	animate(){
		this.transformAnimator.update(this.deltaTime);
	}
	```

3. `move`メソッドを実行し、オブジェクトを移動
	引数は `位置`,`回転`,`移動時間`,`移動完了時のコールバック`になっています。

	```javascript
	let nextPos = new THREE.Vector3(10,0,0);
	let nextRot = new THREE.Euler(0,Math.PI * 2,0);

	this.transformAnimator.move(nextPos,nextRot,1,callBack);
	```

回転が`THREE.Euler`での指定なので、２軸以上指定するのは結構厳しいです。  　
`THREE.Quaternion`への変更を検討中です。

## 最後に

長々とオレオレライブラリを解説しましたが、これらはすべて、three.jsを使った追加機能みたいなものなので、例えば**`ORE.Controller`は使わないで、`ORE.PostProcessing`だけ使う**みたいなこともできるので、よかったらインストールしてみてください。

また、開発はゆるふわに行なっています。
**気まぐれでクラス名の変更とかしちゃったり**するので、**遊びや参考程度に使うようお願いします**。