Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

Java3Dを使わずにパースをかけて立方体を表示する

透視投影変換と背面消去による立体図形の描画

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2005/12/16 10:35

本稿では、Java3DなどのAPIを使用せずに、立方体を描画するプログラムを紹介します。陰面消去の処理は、凸な立体図形を1つだけ描画する前提で省力化しました。その代わり、透視投影変換でパースをかけて描画し、マウスによる回転・移動・ズームのオペレーションを加えました。

目次

はじめに

 パースのかかった立方体を描画するプログラムをJavaで作ってみました。プログラミングには、Java3DなどのAPIは使用せず、ホームページなどに貼り付けて簡単に実行できる、Javaアプレットで作成しました。

 陰面消去の処理は、凸な立体図形を1つだけ描画する前提で省力化しました。その代わり、透視投影変換でパースをかけて描画し、マウスによる回転・移動・ズームのオペレーションを加えました。

 以下に、その実行画面を示します。

アプレット実行画面
アプレット実行画面

対象読者

 Javaと線形代数(高校程度)の基礎知識があり、3次元CGに興味のある人。

必要な環境

 開発には以下の環境を使用しました。

 また実行環境として、Javaアプレットを実行できるWebブラウザが必要です。

陰面消去

 「陰面消去」とは、見えない部分を描画されないようにする処理のことです。今回は描画対象が立方体、すなわち凸な多面体のため、面の法線ベクトルと視線ベクトルを使用した背面消去を利用します。

 ここで、面の裏側が視点に向いているとき、法線ベクトルnと視点から面への視線ベクトルeの成す角θは90°より小さくなります。したがって、cosθ>0.0のとき、つまりneの内積が0より大きい場合、面は裏側を向いているため、描画する必要はありません。

 立方体の場合、視点から見えるのは、表を向いている面だけなので、ne>0.0となる場合は、面のレンダリングを行いません。

法線ベクトルと視線ベクトル
法線ベクトルと視線ベクトル
面の表側が視点の方を向いているとき
面の表側が視点の方を向いているとき
面の裏側が視点の方を向いているとき
面の裏側が視点の方を向いているとき
面の延長線上に視点があるとき
面の延長線上に視点があるとき

 これについて、もう少し詳しく説明します。立方体の6つの面で、視点側に見えるのは多くとも3面までです。このとき、視点側を向いているのは、いずれも表側、つまり法線ベクトルが視点側を向いている面で、残りの面はすべて、これらの面で隠されます。これは、直感的にも分かると思います。したがって、立方体の陰面消去の処理は、背面消去で十分ということになります。これは、凸な多面体ならどのような立体図形でも同じで、zバッファ法などで奥にある面を隠す処理が必要になるのは、2つ以上の立体図形を描画する場合や、表側の面が他の面に隠れるような凹んだ部分のある立体図形を描画する場合だけとなります。

視点側に見える面は多くとも3面 すべての面が表側を向いている
視点側に見える面は多くとも3面 すべての面が表側を向いている

 ところで、視点から面への視線ベクトルとは、どのようなベクトルでしょうか。サンプルプログラムでは、視点から面の重心へのベクトルとしていますが、視点から面上の任意の点までのベクトルでかまいません。平らな長方形の板を見ながら考えていただければ分かると思いますが、面の表側を向いているときは、視点から面の任意の点へのベクトルと面の法線ベクトルの成す角は90°以上となっています。これを、だんだん寝かせていき、視点が、面の延長線に来るように動かしてやると、いずれの点へのベクトルも、面に平行、つまり、面の法線ベクトルに垂直になっていきます。そして、視点が完全に面の延長線に来ると、いずれの点へのベクトルも面に平行になります。視点が、面の裏側にあるときも、同じように考えられます。

 背面消去の処理を、Javaで書いたソースコードは、以下のようになります。ここで、Vector2dは2次元ベクトルクラス、Vector3dは3次元ベクトルクラス、Matrix4x4dは4×4行列クラス、modelMはモデル変換行列、rotMはモデル変換の中の回転変換の行列です。

背面消去の処理
// M:モデル変換行列、c:面の中心点、Mc:モデル変換後の面の中心点
Vector3d Mc = modelM.multiplyVecRight(center);
// n:回転変換後法線ベクトル(n' = Rn)
Vector3d n = rotM.multiplyVecRight(normal);
n.normalize();
// e:視線ベクトル(e' = Mc - e)
Vector3d e = Mc.subtract(eyePos);
e.normalize();

// 法線ベクトルと視線ベクトルの成す角が90°以内
// のときはレンダリングをしない
//    
//         n   e
//         |θ /
//         | /
//    表   |/ 
//    --------------
//    裏  /
//       /
//     eye
//     視点
if (n.dot(e) > 0.0) {
    return;
}

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 伊藤拡(イトウヒロム)

    元CGプログラマ 現在業務系システムのソフトウェア開発技術者 著書 『Javaアプレット 3Dゲーム開発とレンダリング』(共著、工学社) 『MFCによるOpenGL 3Dプログラミング』(工学社) 細々とホームページ公開中  

All contents copyright © 2005-2019 Shoeisha Co., Ltd. All rights reserved. ver.1.5