Velocity.jsでテクスチャ付き立方体を回転させる


# はじめに
CSSアニメーションエンジンの"[Velocity.js](http://julian.com/research/velocity/)"を使ってテクスチャ付き立方体を表示してみました。
ずいぶん前にネイティヴなCSS 3Dを触ってみたことがあるのですが、一般的な3Dと作法があまりに違うので投げ出してしまいました。
Velocity.jsを使えば最小限のコーディングで直感的に3D表示ができるようです。
[ [動作デモ](http://kurino.xii.jp/Gallery/Computer/VelocityJs/rotcube.html) ]
![スクリーンショット 2015-11-15 18.13.41.png](https://qiita-image-store.s3.amazonaws.com/0/98965/632057f1-068e-3536-162e-82d094095140.png)
## HTMLを記述する

HTMLはpers, container, earth, planeの４層構造にしました。
立方体を作るだけならば１階層だけで済んでしまうのですが、CSSは３Ｄ移動量の扱いが独特なためこのような構造になりました。

1. div "plane"クラス
 - ６枚の正方形（平面）
1. div earthクラス
 - 立方体オブジェクト。６枚の平面を１つの立方体として扱う。
1. div containerクラス
 - 奥行きオブジェクト。これの説明は難しいですね。一般的な3Dでは「回転＞平行移動」と「平行移動＞回転」は異なる結果になるのですが、CSSアニメでは変形の順番を変えても原点中心でしか回転できないようです（要調査）。このため、回転後に平行移動するためのオブジェクトを一つ作りました。
1. div persクラス
 - パースペクティブ指定オブジェクト。すべての射影変換はこのオブジェクトを基準に適用されます

```html:rotcube.html
<div class="pers">
	<div class="container">
		<div class="earth">
			<div class="b1 plane"></div>
			<div class="b2 plane"></div>
			<div class="b3 plane"></div>
			<div class="b4 plane"></div>
			<div class="b5 plane"></div>
			<div class="b6 plane"></div>
		</div>
	</div>
</div>
```

## CSSを記述する

1. div "plane"クラス
 - 6枚の平面に地道に回転・移動量を適用します(transform）。
 - 立方体に貼り付ける絵は海外の[サイト](http://www.randelshofer.ch/rubik/virtualcubes/rubik/globes/images/EarthCube_1024.png)から拝借しました。
 - ６枚の画像を用意するのではなく、大きな画像の一部を貼り付けるCSSスプライトという技法を使っています(background-positionで指定）
 - 元画像は1024x1024で3x3構成という割り切れないサイズです。そこで正方形一つが200x200[px]になるようにテクスチャをスケーリングしました(background-size)

```css:rotcube.html
div.plane{
	position:absolute;
	width:200px;
	height:200px;

	background-image:url(cubic/EarthCube_1024.png);
	overflow:hidden;
	background-size:609px 609px;
	overflow:hidden;
	opacity:1.0;
}
div.b1{ transform:                  translateZ(100px); }
div.b2{ transform: rotateX( 90deg)  translateZ(100px); }
div.b3{ transform: rotateY( 90deg)  translateZ(100px); }
div.b4{ transform: rotateY(-90deg)  translateZ(100px); }
div.b5{ transform: rotateX(-90deg)  translateZ(100px); }
div.b6{ transform: rotateY(-180deg) translateZ(100px); }

div.b1{background-position:-200px -200px;}
div.b2{background-position:-200px    0px;}
div.b3{background-position:-400px -200px;}
div.b4{background-position:   0px -200px;}
div.b5{background-position:-200px -400px;}
div.b6{background-position:-400px -400px;}
```
2.div earthクラス
６枚の平面を１つの立方体として扱うクラスです。立方体の回転はこのクラスに適用することになります。
"-webkit-transform-style: preserve-3d;"この中でもオブジェクトを3Dとして扱う指定です。この行を削除すると、立方体が平面にツブれて表示されます。
"margin:0 auto"は立方体を中央に表示させる指定です。この行を削除すると立方体は極端なパースで表示されます。

```css:rotcube.html
div.earth{
	pointer-events: none;
	margin:0 auto;
	width:	200px;
	height:	200px;
	-webkit-transform-style: preserve-3d;
}
```

3.div containerクラス
earthクラスで描かれた立方体は、立方体の中心が原点にあり、回転中心も原点です。
このため、幅200pxのdiv要素は100px手前に飛び出すことになり、親のdiv要素をはみ出してしまいます。
これを防ぐために奥行き方向に200px移動させています。

```css:rotcube.html
div.container{
	-webkit-transform-style:preserve-3d;transform:translateZ(-200px);
}
```

4.div persクラス
射影変換のためのクラスです。
遠近感を強めに出したかったので、立方体の一片200pxに対してperspectiveが400pxとカメラが近い設定になっています。
div persの中心を射影変換中心にさせるため、"transform-origin: 50% 50%;"と"perspective-origin:50% 50%;"を設定しています。

```css:rotcube.html
div.pers{
	height:250px;
	margin:5px 0;
	border:solid 1px #ccc;
	position:relative;
	perspective: 400px;
	-webkit-perspective: 400px;
	-moz-perspective: 400px;
	-ms-perspective: 400px;
	
	transform-origin: 50% 50%;
	-webkit-transform-origin: 50% 50%;
	-moz-transform-origin: 50% 50%;
	-ms-transform-origin: 50% 50%;

	perspective-origin:50% 50%;
}
```
## Javascriptを記述する
CSSアニメーションはJavascriptを使わなくても記述できるのですが、Velocity.jsを使うと3D関連部だけを効率的に操作できます。

"rotateX"が上下の首振り。"rotateY"が立方体の自転。
rotateX:[a, b]という表記はこの二値の間を変化させる（ここでは上下動）記述。
rotateY:360は、初期状態（指定していないので0度）から360度まで変化させる記述です。

duration:8000 は８秒で一回転。
loop:trueは無限に繰り返す設定。
easing:"easeInOutQuad"は自転速度に変化をつけるパラメータ。詳しくは[早見表](http://easings.net/ja)参照。

```js:rotcube.html
<script>
jQuery(function($){
	$(".earth").velocity(
		{"rotateX":[40, -40], "rotateY":360},
		{"duration":8000, "loop":true, "easing":"easeInOutQuad"}
	);
});
</script>
```