「3D-CGプログラマーのためのクォータニオン入門」のサンプルコードの動かし方(Windows11 + VS 2022)
はじめに
書籍「3D-CGプログラマーのためのクォータニオン入門」にはGLUTを使用した3DCGのサンプルコードが提供されています。ただし、GLUTの開発が止まっており、自分でfreeglutのビルドをしないといけない等の問題があります。そこで、この記事ではそれらの手順を記録として残します。Windows11 + Visual Studio 2022環境を対象とします。
Visual Studio 2022のインストール
以下のサイトで「Visual Studioのダウンロード」ボタンをクリックし、Visual Studio 2022をダウンロードします。個人利用であればCommunityで良いかと思います。
ダウンロード後インストールしますが、C++環境も忘れずにインストールしてください。
freeglutのビルド
GLUTはOpenGLのツールキットですが、長らく開発されていないようです。かわりにfreeglutが継続的に開発されているのでそちらを使います。
freeglutの入手
2023年06月10日時点で最新版はv3.4.0なので、freeglut-3.4.0.tar.gzをダウンロードし、展開します。CMakeのビルド生成物を置くため、freegult-3.4.0
フォルダ直下にbuild
フォルダを作成しておきます。
CMake
freeglutのビルドにCMakeを使用するのでダウンロードします。zipを展開するといくつかフォルダが見えますが、bin
フォルダの下にcmake-gui.exe
があるのでダブルクリックして実行します。"Where is the source code:"にfreeglutフォルダ、"Where to build the binaries:"に先ほど作成したbuild
フォルダを指定します。
"Configure"ボタンをクリックすると以下のダイアログが表示されるので、ビルド環境を選んで"Finish"をクリックします。私はVisual Studio2022がインストール済みであるため、それを選択しています。
次に"Generate"ボタンをクリックします。これでbuild
フォルダ直下にfreeglut.sln
が作成されており、ビルドの準備が整いました。
Visual Studio 2022でビルド
Cmakeで"Open Project"ボタンをクリックするとVisual Studio 2022が起動し、ソリューションファイルが開かれます(freegult.sln
をダブルクリックしてもOKです)。Visual Studioのメニューで「Buiild」->「Build Solution」を選択してビルドします。また、デフォルトでは以下の画像のようにDebugビルドになっていますが、Releaseを選択し、Releaseビルドも実施します。
以下のファイルがビルドされていたらOKです。
- freeglut-3.4.0/build/bin/Debug/freeglutd.dll
- freeglut-3.4.0/build/bin/Release/freeglut.dll
- freeglut-3.4.0/build/lib/Debug/freeglutd.lib
- freeglut-3.4.0/build/lib/Release/freeglut.lib
freeglutのビルド方法は以下のサイトを参考にさせていただきました。
サンプルプログラムのダウンロード
以下のサイトからダウンロードします。四訂版が見当たらないので三訂版をダウンロードします。
展開するとquatsample.exe
があり、ダブルクリックすると実行できます。
サンプルプログラムのビルド
それではサンプルプログラムをビルド・実行する環境を作っていきます。
ソリューションの準備
Visual Studio 2022を起動し、「Create a new project」でプロジェクトを新規作成します。「C++」「Empty Project」を選択、「Next」ボタンをクリックします。
プロジェクト名等、適宜入力して「Create」をクリックします。
ここで、プロジェクトファイルと同じフォルダにサンプルプログラムの以下のファイルをコピーします。本来はコピーしなくても良いのですが、プロジェクトファイルと同じ場所にソースがある方がわかりやすいのでコピーしておきます。
- quat.h
- quat.c
- quatsample.c
以下のようになっていればOKです。
Visual Studioに戻り、「Solution Explorer」の「Header Files」を右クリックします。「Add」「Exisiing item...」と選択し、開いたダイアログで先程コピーしてきた「quat.h」を選択します。以下のように「Header Files」の下にquat.h
が読み込まれていることを確認してください。
次に「Souce Files」に対して同様にquat.c
、quatsample.c
を追加します。最終的に以下のようになります。
ビルドの準備およびビルド
このままではVisual Studioがfreeglutのヘッダファイルやライブラリファイルの場所を知らないためビルドに失敗します。そこでこれらの設定を行います。
「Solution Explorer」でプロジェクト(この例ではQuestionSample)を右クリックし、「Properties」を選択します。
まず、「C/C++」「General」と開き、「Additional Include Directories」にfreeglutのヘッダファイルがおいてあるフォルダを指定します。私の場合はD:\sources\freeglut-3.4.0\include
と設定しています。
次に「Linker」「General」と開き、「Additional Library Directories」にfreeglutのライブラリファイルがおいてあるフォルダを指定します。私の場合はD:\sources\freeglut-3.4.0\build\lib\Debug
と設定しています。
次に「Debugging」を開き、「Environment」にfreeglutのDLLがおいてあるフォルダを指定します。私の場合はPATH=%PATH%;D:\sources\freeglut-3.4.0\build\bin\Debug $(LocalDebuggerEnvironment)
と設定しています。この設定は実行時にDLLを検索するパスを追加しています。面倒な場合はビルド済み実行ファイルと同じフォルダにfreeglutd.dll
またはfreeglut.dll
をコピーしてきても実行できます。
以上の設定はDebugビルド用の設定です。Releaseビルド用には「Configuration」を「Release」に変更し、同じ設定を行います。ただし、ライブラリ、DLLに関してはパスが異なるので注意してください。
「Buiild」->「Build Solution」を選択してビルドが成功すると思います。Debug/Releaseを切り替えてもビルドできることを確認してください。
実行
さて、この状態で実行ボタンをクリックするとサンプル付属のsample.exe
と同じプログラムが起動します。試しに少し変更を加えてみましょう。たとえば、30行目の色設定
static const GLfloat blue[] = { 0.0, 0.0, 1.0, 1.0 };
を以下のように変更してみます。
static const GLfloat blue[] = { 1.0, 0.0, 0.0, 1.0 };
実行すると正20面体の左・下に存在する板の色が赤色になっていることがわかります。
これで好きにコードをいじって色々実験できますね!
本の感想
二次元のベクトルのXY座標表現から複素数へと基底を変換するのと同じように、三次元のベクトルを複素行列の基底に変換したものがクォータニオンであるという流れの解説が非常にわかりやすかったです。ただし、サラッと読んで分かったつもりになっても実際には深く理解できていないので、あと何回かしっかり読み込んでいきたいです。
たとえばサンプルコードの以下のコードがどこから出てきたのか分からなかったのですが、読み返してみると132ページのT
でした。
/* クォータニオンから回転行列を作る */
static void create_rotation_matrix(GLfloat m[4][4],
const quat *q)
{
m[0][0] = 1.0 - 2.0 * (q->y * q->y + q->z * q->z);
m[0][1] = 2.0 * (q->x * q->y - q->z * q->w);
m[0][2] = 2.0 * (q->z * q->x + q->w * q->y);
m[0][3] = 0.0;
m[1][0] = 2.0 * (q->x * q->y + q->z * q->w);
m[1][1] = 1.0 - 2.0 * (q->z * q->z + q->x * q->x);
m[1][2] = 2.0 * (q->y * q->z - q->w * q->x);
m[1][3] = 0.0;
m[2][0] = 2.0 * (q->z * q->x - q->w * q->y);
m[2][1] = 2.0 * (q->y * q->z + q->x * q->w);
m[2][2] = 1.0 - 2.0 * (q->y * q->y + q->x * q->x);
m[2][3] = 0.0;
m[3][0] = 0.0;
m[3][1] = 0.0;
m[3][2] = 0.0;
m[3][3] = 1.0;
}
Discussion