こんにちは。今日は東京でも雪が降っています。
ゲレンデ好きでも、日常の雪は勘弁して欲しいところ。
前回、Flashでカメラ映像にDisplacementMapフィルターを適用する記事を書きました。
今回は同様の表現をcanvasで実装していきます。
js.do.itにアップしている上のデモはPCのChromeで見て下さい。(v.24.0以降)
また、再生の際にカメラへのアクセス許可が求められるので、許可してください。(ページ上部)
ながれ
- WebRTCでカメラにアクセス
- マップ用canvasの用意
- レイヤー配置
- レンダリング
1.WebRTCでカメラにアクセス
設定無しに、ウェブカメラにアクセス出来るメジャーブラウザはいまのところChromeのみなので、
Chrome閲覧を想定したコードになっています。(2013.2.19現在)
WebRTCはマイクからの音声も拾えるようになっています。
Main.js
function setCamera(){ if(navigator.webkitGetUserMedia) { navigator.webkitGetUserMedia( {video:true}, succeedUseCamera, failedUseCamera ); }else{ browserError(); } }
2.マップ用canvasの用意
前回同様、マップ画像はスクリプト上で生成します。
グラデーションの書き方はActionScriptとは違うので調べてみてください。
レンズにはまる様、サイズ調整などしています。見辛くてすみません。
Main.js
function setMap(){ map = document.createElement('canvas'); map.width = WIDTH; map.height = HEIGHT; map_ctx = map.getContext('2d'); map_ctx.beginPath(); var grad = map_ctx.createRadialGradient(WIDTH*0.5*offset,HEIGHT*0.5*offset,0,WIDTH*0.5*offset,HEIGHT*0.5*offset,WIDTH*0.5*offset); grad.addColorStop(0,'red'); grad.addColorStop(1,'blue'); map_ctx.fillStyle = grad; map_ctx.rect(0,50, WIDTH*offset,HEIGHT*offset); map_ctx.fill(); }
3.レイヤー配置
必要なレイヤーを順番に配置していきます。
カメラ映像の映写が始まるまで、レンズが外れたような見た目にならないよう、リソースの画像も敷いています。
マップ用canvasとvideoタグは配置する必要はありません。
Main.js
function setCanvas(){ lens = new Image(); lens.src = "http://jsrun.it/assets/1/Y/a/h/1Yahi.png"; frame = new Image(); frame.src = "http://jsrun.it/assets/n/P/B/W/nPBWU.png"; mirror = document.createElement('canvas'); mirror_ctx = mirror.getContext('2d'); c = document.createElement('canvas'); ctx = c.getContext('2d'); lens.width = mirror.width = frame.width = c.width = WIDTH; lens.height = mirror.height = frame.height = c.height = HEIGHT; var objBody = document.getElementsByTagName("body").item(0); objBody.appendChild(lens); objBody.appendChild(c); objBody.appendChild(frame); }
4.レンダリング
ActionScriptと違い、現状ではcanvasのAPIやCSSでブレンドモードの設定は出来ません。
ここで、以下のライブラリを利用させていただきました。
context-blender.js @Author Phrogz
また、DisplacementMapFilterもcanvasのAPIにはないため、こちらも外部ライブラリに頼りです。
displacement.js @Author Romuald
Main.js
function draw(){ ctx.clearRect(0, 0, WIDTH, HEIGHT); ctx.drawImage(lens, 0, 0, WIDTH, HEIGHT); mirror_ctx.drawImage(video, 0, 0, WIDTH, HEIGHT); mirror_ctx.setTransform(-offset, 0, 0, offset, WIDTH*offset, 50); var filter = new filters.DisplacementMap( mirror, map, mirror, new filters.Point(0,30), 0, -30, filters.ColorChannel.RED, filters.ColorChannel.RED); filter.draw(); mirror_ctx.blendOnto( ctx, 'overlay'); }
結果として、かなり重い実装になってしまいました。
DisplacementMapFilterの処理に時間がかかっているので、次回のjavascript関連投稿は
この処理をホヤホヤのCSS Shadersで実装したいと思います。