Solufaを使って簡単にWebで3Dを扱ってみる(入門)

More than 3 years have passed since last update.

Qiita初投稿です。  

最近公開されたSolufaを使ってWebで3Dを簡単に扱います。  

SolufaはVirtual DOMという概念を採用しています。

いろいろ説明すると長くなってしまうので端折ります。


導入

まずはSolufa.ioに行きます。

ページの一番下に行きPlayGroundをクリックします。  

スクリーンショット 2016-06-08 22.09.10.png

開くと綺麗に並んだ大量のキューブが一度に回転する画面とエディタが表示されます。  

スクリーンショット 2016-06-08 22.10.23.png

割と初見殺しなのでエディタ部分を全消しし、下記のコードをペーストします。

S(function(m) {

var App = {
controller: function() {
return {
geo: {
type: "Box",
value: [ 1, 1, 1 ]
},
mtl: {
type: "MeshPhong",
value: {
color: "#00f",
specular: "#999"
}
}
};
},
view: function( ctrl ) {
return <scene>
<obj>
<mesh geo={ ctrl.geo } mtl={ ctrl.mtl } style={{ rotate: [ 30*Math.PI/180, 45*Math.PI/180, 0 ] }}/>
</obj>
<cam id="cam" style={{ posZ: 5 }}/>
<light init={{ type: "Dir" }} style={{ pos: [ 0, 2, 0 ] }}/>
<light init={{ type: "Amb" }}/>
</scene>;
}
};
m.mount( S.document.body, App );
m.render( S.document.head, <rdr init={{ frame: "#solufa", antialias: true, preserveDrawingBuffer: true }}>
<OrbitVp cam="#cam"/>
</rdr> );
});

右側のi◯honeの画面に青いキューブが現れます。


スクリーンショット 2016-06-08 22.19.54.png


ソースの説明  

S(function(m) {

適当に言うとSolufaを使うよ!!とMithrilを使うよ!!ってことです。おまじないだと思ってください。  

var App = {

App内にViewとControllerを書いていきます。

まとめておくことで後でmountするときに楽です。

ここからMithrilを使ってViewとControllerを書いていきます。


コントローラ

controller: function() {

ここには、オブジェクトやマテリルの定義、アニメーションやタッチ(クリック)の判定を書いていきます。


オブジェクトの定義

geo: {

type: "Box", //箱
value: [ 1, 1, 1 ]
}

このように定義すると1x1x1のBoxが描画されます。  

type、valueを変えていくことで様々なオブジェクトが描画できます。


(1例)

geo: {

type: "Cylinder", //筒
value: [ 1, 1, 2 ] //上面の半径、下面の半径、高さ
}

geo: {

type: "Plane", //板
value: [ 1, 1 ] //横幅、縦幅
}

geo: {

type: "Sphere", //球
value: [ 1, 32, 32 ] //半径、垂直方向の分割数、平行方向の分割数
}

是非書き換えて試してみてください。


他にも大量のオブジェクトがデフォルトで用意されています。(...トーラスノットとか胸熱  

http://solufa.io/document/?category=object&article=geometry  


マテリアルの定義  

mtl: {

type: "MeshPhong",
value: {
color: "#00f",
specular: "#999"
}
}

このようにしてマテリアルを定義します。

valueの中にはいろいろ定義できて、Phongマテリアルでもこんなにパラメーターがあります。

value: {

color: colorValue,
emissive: colorValue,
map: texture,
wireframe: boolean,
wireframeLinewidth: number,
wireframeLinecap: "round", "butt" or "square",
wireframeLinejoin: "round", "bevel" or "miter",
}

マテリアルも標準でLambert(光沢のないサーフェス)やStandard(物理ベース)などいくつか用意されているのでいろいろ試してみましょう。

http://solufa.io/document/?category=object&article=material


これで描画の準備ができました。


ビュー

Controllerが完成したのでそれを描画するViewを作っていきます。

view: function( ctrl ) {

ここから書いていきますctrlは引数なので自分の分かりやすい名前にしてOKです。

まずはシーンを定義します。

return <scene></scene>;

returnはViewのsceneタグで囲まれた部分を返すよ!!ってことです。


オブジェクトの描画

return <scene>

<obj>
<mesh geo={ ctrl.geo } mtl={ ctrl.mtl } style={{ rotate: [ 30*Math.PI/180, 45*Math.PI/180, 0 ] }}/>
</obj>
</scene>;

objタグで囲っているのは後々使うアニメーションなどで便利です。

meshタグが複数あるときにグループ化できます。

<mesh geo={ ctrl.geo } mtl={ ctrl.mtl } style={{ rotate: [ 30*Math.PI/180, 45*Math.PI/180, 0 ] }}/>

meshタグ内でgeo={コントローラで定義したgeo} mtl={コントローラで定義したマテリアル}を指定することでそれを描画します。

またstyle内にはpos(位置)やrotate(回転)などのTransform情報を指定できます。

今回はstyle={{ rotate: [ 30*Math.PI/180, 45*Math.PI/180, 0 ] }}と指定しています。

rotateの引数はラジアンなので45度回転したい!って時は

45度*円周率/180

でラジアンに変換できます。


カメラの設定

<cam/>

これだけでカメラが設置できます。神

しかしレンダリングするときにidかclassがないと取ってこれないので指定します。

また、デフォルトだと(0,0,0)の座標に設置されるのでどこかの軸を適当に動かします。

<cam id="cam" style={{ posZ: 5 }}/>


ライトの設定

<light init={{ type: "Dir" }} style={{ pos: [ 0, 2, 0 ]  }}/>

<light init={{ type: "Amb" }}/>

Dirはディレクショナルライトの略で、平行に進む光です。

Ambはアンビエントライトの略で均一な光を放ちます。

これでViewが完成しました。


初期化

Mithrilは

m.mount( S.document.body, App );

で初期化します。

S.document.bodyのDOMの中でAppをレンダリングに使用するよ!って意味だと思います。

レンダリングが1回の場合必要ないのですが、アニメーションを利用したりする場合など再描画が必要な時が多いので書いておきましょう。


レンダリング

このままでは何も表示されません。

Mithrilではm.renderメソッドを呼ぶことでレンダリングができます。

さらに3Dもレンダリングが必要なのでrdr要素を用いてレンダリングします。

<rdr init={{ frame: "#solufa", antialias: true, preserveDrawingBuffer: true }}>

frameは描画する要素のidです。Playground内では#solufaと指定しているそうです。

スクリーンショット 2016-06-08 23.49.32.png

antialiasはギザギザを滑らかに処理してくれます。

preserveDrawingBufferは描画後のバッファを保存するかどうかなのですが、割愛します。

そしてrdrタグで囲まれた部分に使用するカメラを指定します。

<vp cam="#cam"/>

本来ならこれでいいのですが、スワイプ(ドラッグ)でぐるぐる動かしたいので

<OrbitVp cam="#cam"/>

とします。

多分ですがthree.jsのOrbitControl的なのが内包されてるんだと思います。(ドキュメントに載ってない...)

m.render( S.document.head, <rdr init={{ frame: "#solufa", antialias: true, preserveDrawingBuffer: true }}>

<OrbitVp cam="#cam"/>
</rdr> );

これで立方体が描画できました。


最後に

いろいろ端折って書きましたが、ここまで簡単に3Dが扱えるライブラリが出たのは驚きました。

WebGLも難易度高いし、Three.jsはちょっとさわっただけ、、、って人にオススメです。

今後、particleやobjなどの読み込み(もしかしたら既にできるのかも?)なども追加されていき、誰でも3Dが扱える優しい世界に発展していくことを願っています。

暇なときにアニメーションの記事とか作っていきたいと思います。


Solufaを使う理由

スクリーンショット 2016-06-09 0.29.52.png

最近話題になったA-Frameよりも速いです。

まだSolufaがWebVRとして活用できないので断定はできませんが、WebVRとしての地位を築くと思って期待を込めて使用しています。