canvas #001 WebRTC

こんにちは。今日は東京でも雪が降っています。
ゲレンデ好きでも、日常の雪は勘弁して欲しいところ。

前回、Flashでカメラ映像にDisplacementMapフィルターを適用する記事を書きました。
今回は同様の表現をcanvasで実装していきます。
js.do.itにアップしている上のデモはPCのChromeで見て下さい。(v.24.0以降)
また、再生の際にカメラへのアクセス許可が求められるので、許可してください。(ページ上部)

ながれ

  1. WebRTCでカメラにアクセス
  2. マップ用canvasの用意
  3. レイヤー配置
  4. レンダリング

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で実装したいと思います。