Large Display Size Middle Display Size Small Display Size
印刷用 概要 キーワード 著者

3次元コンピューターグラフィクス

 3Dダンジョンを絵ではなく計算で描きたいけど、いったいどんな計算をすればいいのか。
 悩んだことありませんか?

 sin, cos, tan。それから行列とか、そういう難しい計算を使うのでは??

 大丈夫です。そんなに難しい計算はひとまず不要です。
 ただ、ここでは陰面処理について説明していません(私がわかりません)ので、3Dダンジョンを作るには別途、陰面処理の方法を見つける必要があります。


JavaScript
Firefox, Internet Explorer ok
test
Please press a space key to begin demonstration. Or please click here.

スペースキー を押すとデモが始まります。
Androidなどキーボードのない機械では上記のhereをクリックすればデモだけでも見られます。
ちょっと芸のないあまり面白くないデモかもしれません。
デモを途中で止めるにはこのページを 再読込み してください。

デモが終了したら下記のように手動で操作できます。
キー入力操作
キーボードの上下左右 立体が上下左右に動きます。
テンキー7,4ペア 画角(2D Screen Z座標)の前後 この3つのペアは見た目の結果が似ています。
テンキー8,5ペア zoomの上げ下げ
テンキー9,6ペア 視点のZ方向位置変更。
テンキー1,3,2,0 前後左右シフト移動
※キーを押せないAndroid端末などでは残念ながら非対応です。

【注意点】

  • テンキー9,6ペアで操作して物体に近寄りすぎると描画が乱れます。離れると正常描画に戻ります。
  • キー入力の十字キー↑↓で、ブラウザがページスクロールしてしまう問題を回避するため、十字キー↑↓が押されたときだけ特別な処理(イベント伝播中止)をしています。
    そのため、ブラウジングで十字キー↑↓が使えません。同様の理由でスペースキーもブラウジングで使えません。(でもスペースキーはブラウジングで使う場面ない?)

原理

 もともとはWikipediaを読んで知った原理です。

 3次元の座標を2次元の画面の座標に変換するには、
 3次元の座標を x, y, z、2次元の座標を h, v とすると、

 h = x * ( s / z )
 v = y * ( s / z )


 という簡単な式で変換できます。

 式中の s は2次元のスクリーンを3次元中の z 座標のどこに配置するかという値です。 (ソースコード中の ScreenZ )

 詳しくはWikipediaの "3次元コンピュータグラフィクス" のページの原理の項目を参照してください。

新しいウィンドウで開く: Wikipediaの3次元コンピュータグラフィクス

 この式で計算するとデモのように3次元グラフィクスが描けます。
 最初は簡単な四角形を画面に描いてみて、次に立方体を描いて、というようにステップを踏むとトライしやすいです。

 いろいろ要求を満たしていくと上の式は、以下のような式になります。
 赤い部分は上の式と同じ部分です。黒い部分が追加した式です。

 point2D.x = CenterX + x3D * ( ScreenZ / z3D * hosei ) * Camera.zoom;
 point2D.y = CenterY + y3D * ( ScreenZ / z3D * hosei ) * Camera.zoom;
  • CenterX,Y : 画面の中央を0,0にします。
  • * hosei : Z方向の まのび を直す補正です。下記で説明しています。
  • * Camera.zoom : 単純な画面拡大機能です。

 Wikipediaのそのままの式だとちょっと奥行きが まのび している感じがあったのでソースコードで簡易的に補正を加えました。以下のような補正です。
(正直言って理論にもとづいていない結果オーライの補正ですが…)

Before
//3次元座標を2次元に変換 function trans( point3D ) { var point2D = new Object(); var x3D = point3D.x + Camera.eyeX; var y3D = point3D.y + Camera.eyeY; var z3D = point3D.z + Camera.eyeZ; //Wikipediaに載っていた式 point2D.x = CenterX + x3D * ( ScreenZ / z3D ) * Camera.zoom; point2D.y = CenterY + y3D * ( ScreenZ / z3D ) * Camera.zoom; return point2D; }
↓ ↓   
After
//3次元座標を2次元に変換 function trans( point3D ) { var point2D = new Object(); var x3D = point3D.x + Camera.eyeX; var y3D = point3D.y + Camera.eyeY; var z3D = point3D.z + Camera.eyeZ; var hosei = 2; //Wikipediaに載っていた式 point2D.x = CenterX + x3D * ( ScreenZ / z3D * hosei ) * Camera.zoom; point2D.y = CenterY + y3D * ( ScreenZ / z3D * hosei ) * Camera.zoom; return point2D; }

 3次元から2次元の変換は、この方法のほかに行列などの難しい計算をする方法がありますが、この式のほうが手軽ですね。

 奥行きZ座標と、水平方向のX座標について三角関数を使えば、目の前で回転する表現もできると思います。

陰面処理はむずかしい…

 あと、陰面処理をしないと、手前の壁で見えないはずの向こう側の線も見えてしまって、このままだと3Dダンジョンなどのゲーム作成は難しいと思います。

「画面のすべてのピクセルに、見えている画素のZ座標を記録して、新しい物体のピクセルを描くときに、その記録したZ座標よりも奥であれば描かない、手前であれば描く」という「Zバッファ」という陰面処理があります。(深度バッファ、デプスバッファなどとも言います)
 画面のすべて、なのでメモリが多く必要で、画面が細かいほど処理量も増えるでしょう。
 そのため解像度を落としたほうが良さそうです。320x200とかでしょうか。(上のデモは640x480です)
 それから物体を描くときに開始点から終了点までただラインを引くのではなく、そのラインの1ピクセルずつについてZ座標を計算する必要があるし、ラインではなく面であれば、その面全体のピクセルのZ座標を計算する必要があると思います。
 ゲームでリアルタイムにその処理を行うとすれば、簡単ではなさそうです。
 私もやったことがないのでわかりませんが…。

 それで『webGLってたしかインターネットブラウザで3DCGを扱う何かだったような』と思い、「webGL Zバッファ」をキーワードに検索してみたら、面白いページが見つかりました。
 webGLについていろいろ解説しているサイトです。
URL: http://wgld.org/d/webgl/

 webGLを使えば、陰面処理はwebGLにおまかせできると思います。
 …でも自分でスクラッチ(ゼロから、最初から自分の力で開発)で作りたいなぁとも思いませんか?

ダウンロード

最初に紹介したデモの単体のファイルはこちらです。

※ダウンロード後、上記htmlを開くときに、key.jsがhtmlファイルと同じディレクトリにあるようにしてください。


ページ制作 homepage6047


ページの上端へ (もくじ開く)