draw3DLine : 3D drawing on 2D canvas (Processing.js)

最近、3Dになったユニバ社のロゴ
3Dの描画機能だけを切り出してみたので、皆さん使ってね。

ユニバの新ロゴはcanvas+Processing.jsで作られていますが、Processingの3D系の命令は使っていません(WebGLに対応しているブラウザがまだ少ないので…)。3Dのオブジェクトをスクリーン(canvas)に投影する計算を行って、2D系の命令だけで描画しています。
その描画系を切り出したのが以下の関数です。

使い方

draw3DLine(x1, y1, z1, x2, y2, z2, xRotate, yRotate, zRotate)

6つの引数(XYZ座標を2つと、XYZ軸の回転角度)を渡すと、canvasに2座標を結ぶ線を描画します。原点は画面の中央です。
カメラはZ軸上に固定です。カメラの視野角(radS)、カメラの位置(camZ)、スクリーン位置(scZ)だけ、変更することができます。線の太さ、色はweight、strokeH、strokeS、strokeBで持っていますが、2Dで線を描画するパラメータなので、太い線ではパース感の矛盾がよりはっきり見えてきます。細い線でも厳密に言えば奥行き感ゼロ。そこは見せ方でがんばってね。

サンプルでは、線を12本引き、XYZ軸それぞれを1度ずつ回転させて、直方体が回転するアニメーションを作っています。
http://hascanvas.com/draw3DLine

//透視変換用の変数
//視野角θ
float radS = TWO_PI/360*35;
//カメラの原点からの距離
float camZ = -4500;
//スクリーンの原点からの距離
float scZ = -1000;
//回転
float xRotate = 0;
float yRotate = 0;
float zRotate = 0;

//描画用の変数
//線の太さ
float weight = 0.5;
//線の色
int strokeH = 0;
int strokeS = 0;
int strokeB = 0;

//頂点座標を格納する配列 : x1, y1, z1, x2, y2, z2
int[][] va = {
  {-200,-200,-20, 200,-200,-20},
  { 200,-200,-20, 200, 200,-20},
  { 200, 200,-20,-200, 200,-20},
  {-200, 200,-20,-200,-200,-20},
  {-200,-200, 20, 200,-200, 20},
  { 200,-200, 20, 200, 200, 20},
  { 200, 200, 20,-200, 200, 20},
  {-200, 200, 20,-200,-200, 20},
  {-200,-200,-20,-200,-200, 20},
  { 200,-200,-20, 200,-200, 20},
  { 200, 200,-20, 200, 200, 20},
  {-200, 200,-20,-200, 200, 20}
};

//初期化
void setup()
{
  size(300, 300);
  frameRate(30);
  colorMode(HSB);
  noSmooth();
  noFill();
  background(255);
}

//メインループ
void draw()
{
  background(255);
  //描画ループ
  for(int i=0; i<va.length; i++) {
    //描画
    //x1, y1, z1, x2, y2, z2, rotateX, rotateY, rotateZ
    draw3DLine(va[i][0],va[i][1],va[i][2],va[i][3],va[i][4],va[i][5], xRotate, yRotate, zRotate);
  }
  //回転
  xRotate += TWO_PI/360;
  yRotate += TWO_PI/360;
  zRotate += TWO_PI/360;
}

//透視変換 x1, y1, z1, x2, y2, z2, rotateX, rotateY, rotateZ
void draw3DLine(float x1,float y1, float z1, float x2, float y2, float z2, float rx, float ry, float rz)
{
  //Y軸の回転量を反映
  float z1cash = z1;
  float z2cash = z2;
  z1 = x1 * sin(ry) - z1cash * cos(ry);
  z2 = x2 * sin(ry) - z2cash * cos(ry);
  x1 = x1 * cos(ry) + z1cash * sin(ry);
  x2 = x2 * cos(ry) + z2cash * sin(ry);
  //X軸の回転量を反映
  z1cash = z1;
  z2cash = z2;
  z1 = y1 * sin(rx) - z1cash * cos(rx);
  z2 = y2 * sin(rx) - z2cash * cos(rx);
  y1 = y1 * cos(rx) + z1cash * sin(rx);
  y2 = y2 * cos(rx) + z2cash * sin(rx);
  //Z軸の回転量を反映
  float x1cash = x1;
  float x2cash = x2;
  float y1cash = y1;
  float y2cash = y2;
  x1 = x1 * sin(rz) + y1cash * cos(rz);
  x2 = x2 * sin(rz) + y2cash * cos(rz);
  y1 = y1 * sin(rz) - x1cash * cos(rz);
  y2 = y2 * sin(rz) - x2cash * cos(rz);
  //透視変換
  float x1b = width/2  + x1 * (camZ + z1) * tan(radS/2) / (scZ + z1) * tan(radS/2);
  float y1b = height/2 + y1 * (camZ + z1) * tan(radS/2) / (scZ + z1) * tan(radS/2);
  float x2b = width/2  + x2 * (camZ + z2) * tan(radS/2) / (scZ + z2) * tan(radS/2);
  float y2b = height/2 + y2 * (camZ + z2) * tan(radS/2) / (scZ + z2) * tan(radS/2);
  //描画開始位置を初期化
  translate(0,0);
  //線の色・太さ
  stroke(strokeH, strokeS, strokeB);
  strokeWeight(weight);
  //描画
  line(x1b,y1b,x2b,y2b);
}

iOS 4.3 で使えるようになったthird-party appからのAirPlay呼び出しを試してみる

iOS 4.3の目玉機能の一つ、third party appからのAirPlay利用について、コードを書いてテストしてみました。

といっても、難しいプログラミングが必要な訳ではなく、今まで動画を再生するのに使っていた MPMoviePlayerConntroller に追加された allowsAirPlay というプロパティをYESに設定するだけ。
これで、動画再生のコントローラの並びにあのAirPlayボタンが追加され、それをクリックすると出力先のリストが表示されるようになります。

今回はとりあえず試してみようということで、以下のようなコードを、ViewControllerのloadViewのところに直接書いてみます。

- (void)loadView {
CGRect bounds = [[UIScreen mainScreen] applicationFrame];

NSURL* url=[NSURL URLWithString:@"http://dev.uniba.jp/~jun/apt/test.m4v"];

MPMoviePlayerController *movie=[[MPMoviePlayerController alloc] initWithContentURL:url];

movie.scalingMode=MPMovieScalingModeAspectFit;
movie.allowsAirPlay = YES;

[movie.view setFrame:bounds];
self.view = movie.view;

[movie play];
}

これでビルドしてSimulatorで実行してみましたが、AirPlayボタンが出てきません。どうやら、SimulartorはAirPlayに対応していないようです。(リファレンスにも対応したDeviceで、と書かれています)

気を取り直して、実機をUSBでつないで今度はターゲットをDeviceにしてビルド。しばらく待った後に、実機でアプリが起動し、プレイヤーが起動、AirPlayボタンが表示されました。

AirPlayボタンをクリックして、AppleTVを選択してみましたが今度は「Cannot play video on “Apple TV”」というアラートが表示されます。もしやと思って確認してみると、Apple TV側でソフトウェアアップデートのガイダンスが表示されています。Apple TV側のソフトウェアバージョンが4.1系だったのですが、こちらも最新のバージョンにアップデートする必要がありました。

Apple TV側のソフトウェアをアップデートすると、ちゃんと先ほどのコードで、映像を飛ばすことができました。

アプリからのAirPlayの呼び出しは、MPMoviePlayerController のプロパティということで、今のところAirPlay経由で飛ばせるのは、MPMoviePlayerControllerがサポートしている動画ファイルということになるようです。AirPlayのプロトコルは、静止画もサポートしているようですが、こちらはAPIとして利用できる状態にないようです。

Music Boxel : Naked-eye 3D Display and Web Socket based multi user interaction

aircord社との協同プロジェクト Music Boxel のデモムービー(1分34秒)です。

Music Boxel from aircord on Vimeo.

関連記事
2011年1月17日 Music Boxel (裸眼3Dディスプレイ x WebSocketインターフェイス)
2011年2月7日 Music Boxel Prototype (Processing+PeasyCam)
2011年2月8日 Music Boxel@CreativeApplications.Net

Naked-eye 3D Display and Web Socket based multi user interaction.
Adding a voxel to make a trigger on roop timeline of virtual music box.

Display/Audio-Visual Program by aircord inc. made with : openFrameworks, SuperCollider
Server/Mobile Interface by Uniba Inc. made with : node.js, CSS3/HTML5

aircord.co.jp/​
aircord.co.jp/​labo
uniba.jp/​

Music Boxel@CreativeApplications.Net

CreativeApplications.Net 14879 February 7, 2011
Music Boxel [iPhone, iPad, openFrameworks]
http://www.creativeapplications.net/iphone/music-boxel-iphone-ipad/

取り上げていただきました!
ありがとございます!

Music Boxel (裸眼3Dディスプレイ x WebSocketインターフェイス)

aircord社とユニバの協同プロジェクト「Music Boxel」のご紹介です。

MusicBoxelは、aircord社が開発したN-3Dという裸眼立体視ディスプレイと、スマートフォン・携帯電話用のリアルタイム通信を組み合わせた、実験プロジェクトです。手元のモバイル端末から、ウェブページ経由でディスプレイの中を回転する「オルゴール(Music Box)」の音を増やしたり、減らしたりするリアルタイム操作を実現しています。

紹介ムービーを準備しているのですが、そちらは近日公開予定。
また、各パートを担当したスタッフから技術紹介の記事をアップしていきます。

Music Boxel
Music Boxel
Music Boxel

Music Boxel

Naked-eye 3D Display and Web Socket based multi user interaction.
Adding a voxel to make a trigger on roop timeline of virtual music box.

Display/Audio-Visual Program by aircord inc. made with : openFrameworks, SuperCollider
Server/Mobile Interface by Uniba Inc. made with : node.js, CSS3/HTML5

iPad の Safari で動作するマルチタッチ対応お絵描きソフトを作ってみた

はいこんにちはー。お久しぶりです。珍しくフロントエンド側のネタで記事を書いてみます。

今回は革新的で魔法のようなデバイスであるところの iPad を使って、マルチタッチ対応お絵描きソフトを作ってみました。 iPad を持っていない人でも見れるように YouTube にビデオをアップロードしてみました。

実際のデモ (PC ブラウザでは動作しません。 Android でも動くかも?)

ソースコード

<!doctype html>
<html>
<head>
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;" />
	<title>touch!</title>

	<style type="text/css">
		#console
		{
			position: absolute;
			top: 0px;
			left: 0px;
			width: 100%;
			height: 100%;
		}
	</style>
	<script>
	document.addEventListener("DOMContentLoaded", function()
	{
		var canvas = document.getElementById("console");
		var ctx = canvas.getContext("2d");

		document.addEventListener("touchstart", draw, false);	// タップ
		document.addEventListener("touchmove", draw, false); // シングルタッチ
		document.addEventListener("gesturemove", draw, false);	// マルチタッチ

		function draw(e)
		{
			// マルチタッチ処理のキモ?
			// e.touches にタッチした数ぶんの座標が配列で格納される

			for (var i = 0; i < e.touches.length; i++)
			{
				// ランダムに色を作る
				ctx.strokeStyle = getRandomColor();
				ctx.fillStyle = getRandomColor();

				var x = e.touches[i].pageX;
				var y = e.touches[i].pageY;

				// page の座標系を canvas の座標系に変換
				x = 640 * (x / window.innerWidth);
				y = 480 * (y / window.innerHeight);

				// 丸を描く
				ctx.beginPath();
				ctx.arc(x, y, 10, 0, Math.PI * 2, false);
				ctx.fill();
			}

			// イベントの伝播をしないようにしてスクロールを防ぐ
			e.preventDefault();
		}

		function getRandomColor()
		{
			var color = [];

			for (var i = 0; i < 3; i++)
			{
				color.push(Math.floor(Math.random() * 256));
			}

			return 'rgb(' + color.join(',') + ')';
		}
	});
	</script>
</head>
<body>
	<canvas id="console" width="640" height="480"></canvas>
</body>
</html>

やっていることは単純で、画面いっぱいに canvas を配置してタッチイベント (touchmove とか gesturemove) で座標を拾って画面に反映しています。何気に jQuery を使わないの初めてですが WebKit だけで動けば良いので気が楽でした。

アプリではないとマルチタッチの検知ができないのかなと思い込んでいたのですが、HTML (JavaScript) でも検知できることがわかったので、応用すればブラウザでもアプリっぽいことが色々できそうな感じですね。

今後 YouTube のビデオも充実させていきたいなと思いつつ、iPhone/iPad はもちろん、スマートフォン全般に取り組んでいけたらなと思います。(もちろん Ethna ネタもやっていきますよー。) それでは!

preload preload preload