明日もデザインで食べていこう![22]HTML5 canvas要素でimg要素をぐにゃぐにゃ曲げるスクリプトを作ってみる
── 秋葉秀樹 ──

投稿:  著者:


以前HTML5案件で作ったもので、canvasで下の図のようなことができるJavaScriptファイルなんですが、これをライブラリ化(っぽく)スクリプトファイルにしてみました。まだ欠陥が多いしAPI仕様もまとまってないのですが、ひとまずこんな表現が可能です。

< http://akibahideki.com/blog/2011/09/29/trianglejs_demo >

ソースはここにあげときました。(使い方よくわかんないけど)
< https://github.com/Hidetaro7/trianglerJS
>

ActionScript 3.0には、GraphicsクラスにdrawTriangles() ってメソッドがあります。何をするかって言うと、ビットマップ画像をテクスチャマッピングすることが目的です。

これにより一枚の静止画をユラユラ布のように揺らしたり、3Dでは遠近感をつけたりと、画像を自由に変形することが可能になるコンピュータ・グラフィックスの手法です。

FlashPlayerやActionScript 3.0が素晴らしいと思うのが、こういったマッピング処理の数学的な難しい処理を、すでにAPIとして実装してくれていいるところです。僕達は、頂点座標を指定して、それをどう動かすか? に専念したらいいんです。

ところが、HTML5の新要素、canvasとかでこれを表現し、アプリなどに乗せてしまうようなお仕事が来た時、「iPadだったらHTML5で出来ますよ」なんて言ってしまったらさあ大変! そんな機能はネイティブで搭載されていません。



つまり、「ないものは作る」or「仕様を満たすライブラリを探す」or「出来ません、と謝る」という選択に迫られます。

実は色んなライブラリがもう既に出まわっていますが、いざ案件でHTMLによるテクスチャマッピングを実装するには、可能な限り自分で内容を知っておきたいという気持ちがあったので、これに挑戦してみました。

多分、こういった仕様のアプリ開発となると、今まで見たライブラリではなかなか要件を満たせないと思うし、「どうやったら画像が変形するのか」というロジックという部分を理解しないといけない場合があると思うんです。

案件ベースで仕様どおりに実装できないと話にならないのですが、こういった場合を想定しましょう。ユーザがブラウザ上でお絵かきなどをして作った画像を、例えば円錐状の立体物に貼るステッカーのようなものを作るWebアプリが必要だったとしましょう。

ユーザは長方形に好きにデザインをするわけですが、実際には円錐状の立体物に貼るには、長方形じゃなくて、「扇形」にしないときれいに貼ることができません。

この場合、ユーザが長方形上で描いたデザインを、アプリ側で扇形に変形する必要があるのです。このテクスチャマッピングの技術がここで役に立ちます。

さて、この(まだ不十分ですが)スクリプトファイルを使ったら、ポリゴンの頂点座標のx座標やy座標をずらすと、画像もその頂点にあわせて変形できます。頂点座標の取得はgetMesh()で、頂点オブジェクトが配列で返ってくるので、例えば(一部紹介すると)

インスタンス.getMesh()[41].x += 40; // ------------- 頂点座標の移動
インスタンス.draw(); // ------------- 再描画実行

とかにすると、左上の頂点から41頂点目のX座標を40px右にずらします、最後にdraw()メソッドで再描画すると、図のように表示されるというものです。

< http://akibahideki.com/blog/2011/09/29/getmesh >

実際デモを見ましょう。(GitHubそのままDLしたらわかりやすいと思います)このスクリプトを使うときに、はじめに下記のように記述して呼び出すようにします。

【呼び出す方法】
new Triangler("canvasのID名","画像のパス", 画像描画開始のX座標, 画像描画開始のY座標, メッシュ分割数, 画像がロードし終わったときの処理);

【関連ファイル】
・index.html (上記のソースが書いてあるファイル)
・js/triangler.js (このスクリプトファイル)
・img/chibikoro.jpg (読み込む画像ファイル)
のみです。

例えばHTMLファイルでは以下のように書いています。

【head要素内 JavaScript】
<script type="text/javascript" src="js/triangler.js"></script>
<script>
window.onload = function () {
var seg = 20; //--------ポリゴン分割数
var m = new Triangler("cvs","img/chibikoro.jpg", 80, 40, seg, function (e){
//m.stroke(true);/*これをするとメッシュが表示される*/
var r = 30/seg, cr = 0;
for (var i=0, l=m.getMesh().length; i<l; i++) {
var p = m.getMesh()[i]; //--------頂点1つずつ揺らすように移動させる
p.x += parseInt(Math.cos(cr*r*Math.PI/180)*40);
cr++;
}
m.draw(); //--------ここで変形後、描画を実行
});
}
</script>


【HTML】
<body>
<canvas id="cvs" width="800" height="800"></canvas>
</body>


●メッシュの表示、非表示

あくまで、今出ている黒い線(メッシュ)は、制作者が分かりやすいように引いているガイド線のようなものなので、案件で納品するときは消さないといけないケースがあります。以下のようにstroke()メソッドを用意したので、引数にtrue / falseを与えてください。

【JavaScript】
インスタンス.stroke(false);

これで再度draw()すると、メッシュは表示されなくなります。(今回のデモ図版では、わざとtrueに設定しましたが、デフォルトはfalseです。)

GitHubに置いた、今回のサンプルは波のように揺らしてますが、これは三角関数を使って、X座標を行ったり来たりさせてます。メッシュ非表示にするためにstroke(false)にしたときの結果、こんな感じになります。

< http://akibahideki.com/blog/assets_c/2011/09/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%EF%BC%882011-09-29%2016.58.16%EF%BC%89-thumb-740x533-66 >

欠点として、一部、ポリゴンの隙間が出来ることもあるということや、ふちはジャギーが出て汚い、ということです。アニメーションで見せる場合、そこまで気がつかずごまかせることもあるけど、かなりパフォーマンスが低下するので、注意が必要です。

何か案件で使えそうな時は自己責任でお使いください。

【あきば・ひでき】
hidetaro7@gmail.com
< http://www.akibahideki.com/blog/
>

テクニカルディレクター・デザイナー。DTP黎明期からグラフィックデザインを学び、東京都営団地下鉄など交通広告を多数手がける。同時に音楽活動も活発に行い、西日本半全国ツアーなどを展開、某専門学校のテーマソングを作詞作曲、編曲から楽器全てを演奏してレコーディングするなど、マルチなクリエイティブ活動も。最近では東京と大阪の教育施設などで講師業をも務める。HTML CSS JavaScript Flash ActionScript 3DCG Movie DTP GraphicDesign...多種スキルを持つ。Web標準技術だけに執着せず、全てのメディアで説得力のある表現にチカラを注ぎたい、そんな仕事をしたい。