2005年07月25日

第七回タイトル 「形状の挿入」

前回で表現方法が増えたかと思います。
しかし、形状を作成するのが困難と言う問題があります。さすがに三角形だけを組み合わせて作るのには限界があります。
そこで他のソフトで作った物を取り込んで表現しようと言うのが今回の取り組みです。

今回使用するのはCADソフトの中でも一番オーソドックスなSTLと言うものを使用します。
大体のCADソフトならこのSTLを出力することが出来ます。
STLのフォーマットなんて知りませんという人、ご安心を今回もSTLを読込むクラスを作成しております。

まずはこのファイルをダウンロード
し、プロジェクトに追加してください。

さらに今回はテスト用のSTLをここからダウンロード
してください。

それではプログラムのほうに移ります。
まず新しく追加したクラスをCOpenGLクラスのメンバー変数として追加してください。

	CSolidFile m_CSolidFile;

もちろんインクルードもお忘れなく

次にViewのクラスにクラスウィザードでOnSizeの関数を追加してください。
さらに関数内に次の一文を追加

	m_pOpenGL->Resize( cx,cy );

これで初期設定は完了です。

次にSTL読込む準備をしましょう。
今回は最初に読込む設定です。

COpenGLクラスのInitOpenGL()関数の最後に

	m_CSolidFile.OpenSLTFile();

を追加してください。
この関数でSTLファイルを読込むことが出来ます。

では最後に描画しましょう。

DrawOpenGL関数はこの用に記述します。

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	//色と奥行きのクリアー
	glLoadIdentity();	//行列の初期化	

gluLookAt( //カメラの設定
300, 300, 300, //カメラの焦点位置、X,Y,Z
0, 0, 0, //カメラの位置 X,Y,Z
0, 0, 1); //画面の縦座標軸


float lightAmbient0[]={0.3f,0.3,0.3,1.0f}; //環境光反射
float lightSpecular0[]={0.3f,0.3,0.3,1.0f}; //鏡面反射
float lightDiffuse0[]={1.0f,1.0f,1.0f,0.8f}; //拡散反射

glLightfv(GL_LIGHT0,GL_AMBIENT,lightAmbient0); //環境光反射設定
glLightfv(GL_LIGHT0,GL_SPECULAR,lightSpecular0);//鏡面反射設定
glLightfv(GL_LIGHT0,GL_DIFFUSE,lightDiffuse0); //拡散反射設定

float lightPosition0[]={ -10000.0f, 10000.0f, 100.0f}; //光源位置
glLightfv(GL_LIGHT0,GL_POSITION,lightPosition0);//光源位置設定
glEnable(GL_LIGHTING); //光源有効
glEnable(GL_LIGHT0); //光源0有効

float MaterialAmbient0[]={0.3f,0.8,0.3,0.8f}; //環境光反射
float MaterialSpecular0[]={0.3f,0.8,0.3,0.8f}; //鏡面反射
float MaterialDiffuse0[]={0.3f,0.8,0.3,0.8f}; //拡散反射

glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,MaterialAmbient0);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,MaterialSpecular0);
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,MaterialDiffuse0);

float MaterialAmbient1[]={0.8f,0.3,0.8,0.8f}; //環境光反射
float MaterialSpecular1[]={0.8f,0.3,0.8,0.8f}; //鏡面反射
float MaterialDiffuse1[]={0.8f,0.3,0.8,0.8f}; //拡散反射

glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,MaterialAmbient1);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,MaterialSpecular1);
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,MaterialDiffuse1);

m_CSolidFile.DrawSTL();

SwapBuffers(m_pCDC->m_hDC); //描画実行


以上で設定は完了です。
実行してみましょう。

実行するとファイルを開くダイアログが出るはずです。
そこでダウンロードしたSTLファイルを読み込んで見ましょう。

表示されましたか?
これで簡単なSTLビューアーが完成です。

あとはみなさんでカスタマイズしてみてください。

投稿者 ishii : 11:24 | コメント (0) | トラックバック

2005年07月11日

第六回タイトル 「透明感の表現」

第五回までのところで形状の表示、および移動が出来たかと思います。

このくらいできれば簡単なゲームやシミュレーションができますが、さらにうまい表現力を作るために透明感のある表示を行います。透明感のあるものと言えば水や煙、霧、ガラスと言ったものが上げられます。

それではまず例から

	float FogColor[]={0.8f,0.8,0.8,0.8f};//フォグの色設定
	glEnable(GL_FOG);//フォグを有効にする
	glFogi(GL_FOG_MODE , GL_LINEAR);//フォグをライナー設定
	glFogi(GL_FOG_START , -10);//スタートは-10から
	glFogi(GL_FOG_END , 10);//最後は10まで
	glFogfv(GL_FOG_COLOR , FogColor );//フォグの色設定
この例を描画の最初に設定してください。 そうすることにより白い霧のようなものが形状にかかると思います。

これは奥になればなるほど濃くなり、手前であれば薄くなると言った霧のようなものを表現するときに使います。白以外にも色の設定は出来ますし、奥行きの範囲指定もできますので応用次第では様々なことに使えると思います。

では次はブレンドです。
ブレンドとはその名前の通り混ぜるという意味です。他の言葉で言うと透過処理となります。以前説明した色の設定でアルファの項目があったかと思いますがそれを有効にします。

では例を

	glEnable(GL_BLEND);//ブレンドの有効
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//ブレンドの仕方

この2行をまた描画の最初に設定してください。

この2行を追加することによりブレンドが有効になります。このままでは全ての形状に対して透過してしまうので

	glDisable(GL_BLEND);//ブレンドの無効

これで無効としてください。

透過処理を行いたい場所だけ囲えば問題ないです。


ただしここで気をつけなければならないのが最初に描画したものに対して後から上にかぶさったものだけがブレンドされるということです。描画の順番がブレンドに影響されます。
手前に表示されるものが先に描画され、後から後ろに描画されるものと言う順番になると後ろのものは描画されない設定となっているためうまくブレンドできません。
もしうまくやりたい場合はDEPTHについてもう少し勉強してください。

今回は透過処理についてやりました。
これで表現方法はだいぶ増えたはずです。

では次はより簡単に形状を作成、表示する方法です。


glFogi 関数説明:
第1引数:設定項目
第2引数:第1引数に対応する引数


glBlendFunc関数説明:
第1引数:設定項目
第2引数:第1引数に対応する引数

投稿者 ishii : 13:27 | コメント (0) | トラックバック

2005年07月04日

第五回タイトル 「マトリクスによる移動設定」

前回、並行移動、回転移動と数値を入力することにより形状の移動を行いました。
今回はさらに上級者に向けてマトリクスによる形状の移動を行います。

マトリクスとは4×4の行列のことです。
行列なんてできないよ~ってお思いの方、ご安心を・・・
行列変換に関わる関数は用意しております。

詳しくは述べませんが簡単にマトリクスの原理を
4×4の行列内に回転を表す3×3の行列とX、Y、Zの位置座標を表す3個の数値、拡大率を表す数値となっています。これだけなのになぜか不思議なことにこれらを計算するだけで空間上における物体の位置が出てしまうのです。
もっと詳しく知りたい人は数学の教科書で勉強しましょう。

では早速マトリクスを使って見ましょう。

まずはソースをダウンロードしてください。
そしてプロジェクトに組み込みます。

組み込んだらクラスをCOpenGLのメンバー変数にCTransform m_Transformと宣言しましょう。もちろんインクルードもお忘れなく
まずは使う関数の説明から

Transrate(double x, double y, double z)
関数説明:平行移動を行います。

RotateX(double Angle)
関数説明:X軸で回転します。

RotateY(double Angle)
関数説明:Y軸で回転します。

RotateZ(double Angle)
関数説明:Z軸で回転します。

これら関数を使用し移動してみましょう。

	double x = 1.0;
m_Transform.RotateX( x );
glMultMatrixd(m_Transform.m_XForm);

まずはこのような形で記述してみました。

これを実行するとX軸周りに回転していることが分かるかと思います。

前回の回転移動と何が違うかと言うと毎回同じ値を入力しているのにも関わらず回転していることです。
前回の位置を覚えており、さらに位置を移動させると相対的に移動することが可能です。

これで毎回無駄な計算をせずに済み処理時間の向上にもつながります。

次回はちょっとした表示上のテクニックをお教えします。

glMultMatrixd 関数説明:
第1引数:doubleの配列16個
引数はマトリクスであること。

投稿者 ishii : 16:45 | コメント (0) | トラックバック

2005年06月27日

第四回タイトル 「形状の空間移動設定」

やっと3次元で表現できるようになりました。
しかし、止まっていてはつまらないですよね。

で、今回は動きを取り入れてみようかと思います。

動きには2パターンあります。
自分が動くか、相手が動くかです。

自分が動くとは視点を移動させると言うことです。
相手が動くとは物体の位置座標を変えると言うことです。

自分が動く方は以前説明した視点の設定で変更することが可能です。
今回は相手が動く方の説明を行います。

視点の設定と形状を作成するプログラムの間に以下のプログラムを入れて下さい。


static double z = 0;
z += 0.001;
glTranslated( 0.0, 0.0, z );//平行移動関数

これを実行すると形状がZ方向に移動すると思います。

これはZ方向に変数zだけ移動しますよと言うものです。
実際にはstaticで宣言せずメンバ変数などで指定したほうが便利です。(^^;

続いて回転です。先ほどの部分を次に置き換えてみてください。


static double RotZ;
Z++;
glRotated( RotZ, 0, 0, 1 );//回転移動関数

これでZ軸周りに回転すると思います。
第1引数は回転量、単位はラジアンです。
第2引数~第4引数まではどの軸で回すかという指定です。単位ベクトルで指定します。

この2個組み合わせて形状の空間移動を行います。
しかし、組み合わせていくうちに使いにくいことが分かるかと思います。
それは、すべて移動関数が足し算を行っていくと言うことです。
絶対座標で表したいのに相対座標で設定しなければならないのは不便です。
そこで次の関数があります。


glPushMatrix(); //マトリクスの挿入
glPopMatrix(); //1個前のマトリクスの解除

移動関数の最初にglPushMatrix関数を入れ形状を作成し、glPopMatrix関数で閉じれば間にある形状に対してのみ移動関数は作用されます。

多数の形状を操作するときはこの関数を使用すると絶対座標で指定出来るので管理が楽になります。

平行移動関数と回転移動関数を紹介しましたがこれとは別にマトリクスの指定による移動も可能です。マトリクスで指定するほうが簡単で演算も少なくて済むので速く処理が行います。

しかし、マトリクスとは4行4列の行列で表され数学の知識が必要となります。数学は苦手だ~と言う人もご安心下さい、別に数学出来なくても大丈夫です。次回はマトリクスについてご説明いたします。

glTranslated 関数説明:
第1引数:X座標並行移動量
第2引数:Y座標並行移動量
第3引数:Z座標並行移動量
glRotated関数説明:
第1引数:回転移動量(単位ラジアン)
第2引数:X軸回転指定
第3引数:Y軸回転指定
第4引数:Z軸回転指定
第2引数~第4引数は単位ベクトルで指定

投稿者 ishii : 13:38 | コメント (0) | トラックバック

2005年06月21日

第3回タイトル 「光源設定」

さて前回までで形状を表示することが出来ました。
今回は表示した形状をより3次元に見せるようにします。

より3次元っぽく見せるには光源の設定を行います。
今回は少し長いですが気長にやってください。ちょっと光の設定はめんどくさいのです。

まず光について説明します。
光には3種類あり、環境光反射(AMBIENT)、鏡面反射(SPECULAR)、拡散反射(DIFFUSE)があります。
環境光反射とは直接光源は見えなくとも辺りの色が分かると言うもの、みなさんは部屋に電気を点けないで廊下など外の明かりで部屋のものを認識するときがあるかと思います。それが環境光反射です。
鏡面反射とは光源から出た光が形状に反射し見えると言うものです。これを設定する上では光源の位置、形状の位置、視点の位置が重要となってきます。太陽からの光が鏡面反射に近いと言えます。
最後に拡散反射とは鏡面反射の全体版です。光源から反射するのは全体に反射するものです。さすがに裏から光を当てたものは反射しませんがその他は全体に反射するようになります。

さてこれを頭に入れたところで光源の設定です。
DrawOpenGL関数のglLoadIdentity();の下に入れて下さい。

	float lightAmbient0[]={0.3f,0.3,0.3,1.0f};		//環境光反射
	float lightSpecular0[]={0.3f,0.3,0.3,1.0f};		//鏡面反射
	float lightDiffuse0[]={1.0f,1.0f,1.0f,0.8f};		//拡散反射
	
	glLightfv(GL_LIGHT0,GL_AMBIENT,lightAmbient0);	//環境光反射設定
	glLightfv(GL_LIGHT0,GL_SPECULAR,lightSpecular0);	//鏡面反射設定
	glLightfv(GL_LIGHT0,GL_DIFFUSE,lightDiffuse0);	//拡散反射設定
	
	float lightPosition0[]={  0.0f, 0.0f, 100.0f};		//光源位置
	glLightfv(GL_LIGHT0,GL_POSITION,lightPosition0);	//光源位置設定	
	glEnable(GL_LIGHTING);			//光源有効
	glEnable(GL_LIGHT0);				//光源0有効

光の色は好きなように設定してかまいません。青い光にするのも赤い光にするのも自由です。
今回は普通に白の光を当てています。

これで光の設定は出来ました。次は形状に色の設定を行います。
形状も光同様に設定します。

	float MaterialAmbient0[]={0.3f,0.3,0.3,1.0f};		//環境光反射
	float MaterialSpecular0[]={0.3f,0.3,0.3,1.0f};		//鏡面反射
	float MaterialDiffuse0[]={1.0f,1.0f,1.0f,0.8f};		//拡散反射

glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,MaterialAmbient0);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,MaterialSpecular0);
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,MaterialDiffuse0);

ここで注意しなければならないのが以前色の設定に使用したglColor3d関数は使用できないと言うことです。glColor3d関数はglEnable(GL_LIGHTING);をした時点で効果はなくなります。

色の設定の変わりに面に法線方向を設定しなければなりません。

	glNormal3d(0.0, 0.0, 1.0); //法線方向ベクトルの設定

必ず単位ベクトルで設定しなければなりません。この設定で光源をどう反射するかが決定します。

これで光源の設定は終わりです。あとは形状をうまく配置すれば3次元っぽく見えるはずです。

ためしに私はこんな形状を用意しました。
視点の設定を


gluLookAt( //カメラの設定
0, 0, 0, //カメラの焦点位置、X,Y,Z
40, 0, 10, //カメラの位置 X,Y,Z
0, 1, 0); //画面の縦座標軸

に変更し、形状を次のようにしました。

	double x = 0.0,y = 1.0,z = 0.0,w = 0.2;
	glBegin(GL_QUADS);
		glNormal3d(0.0, 0.0, 1.0);
		glVertex3d(0.0+x, 0.0+y, w+z);
		glVertex3d(0.0+x, 0.0, w+z);
		glVertex3d(w+x, 0.0, w+z);
		glVertex3d(w+x, 0.0+y, w+z);
	glEnd();
	glBegin(GL_QUADS);
		glNormal3d(0.0, 0.0, -1.0);
		glVertex3d(0.0+x, 0.0, z);
		glVertex3d(0.0+x, 0.0+y, z);
		glVertex3d(w+x, 0.0+y, z);
		glVertex3d(w+x, 0.0, z);
	glEnd();
	glBegin(GL_QUADS);
		glNormal3d(-1.0,0.0,0.0);
		glVertex3d(0.0+x, 0.0+y, z);
		glVertex3d(0.0+x, 0.0, z);
		glVertex3d(0.0+x, 0.0,  w+z);
		glVertex3d(0.0+x, 0.0+y,  w+z);
	glEnd();
	glBegin(GL_QUADS);
		glNormal3d(1.0,0.0,0.0);
		glVertex3d(w+x, 0.0, z);
		glVertex3d(w+x, 0.0+y, z);
		glVertex3d(w+x, 0.0+y,  w+z);
		glVertex3d(w+x, 0.0,  w+z);
	glEnd();
	glBegin(GL_QUADS);
		glNormal3d(0.0,1.0,0.0);
		glVertex3d(w+x, y, z);
		glVertex3d(x, y, z);
		glVertex3d(x, y,  w+z);
		glVertex3d(w+x, y,  w+z);
	glEnd();

ビルのようなものが見えるかと思います。上記までのソースはこちら
ビルをたくさん建てて町並みを表現することも可能ですね。

次回は物体の移動を行います。

第1引数:光源番号(GL_LIGHT0~GL_LIGHT4)
第2引数:光源の種類(GL_AMBIENT、GL_SPECULAR、GL_DIFFUSE、GL_POSITION)
第3引数:光源の数値設定GL_POSITION の場合はfloat の配列3個の3次元座標(X,Y,Z)上記以外はfloatの配列4個(赤、緑、青、アルファ)
glMaterialfv関数説明:glLightfvと同様
第1引数:X座標ベクトル
第2引数:Y座標ベクトル
第3引数:Z座標ベクトル

投稿者 ishii : 10:50 | コメント (0) | トラックバック

2005年06月13日

第二回 「OpenGLによる三角形表示」

前回は本当に初歩の初歩、OpenGLの第一歩を踏みました。
まだ3次元形状とまでは行きませんが今回は形状を作成(表示)します。

COpenGLクラスにあるDrawOpenGL関数に
以下のようにしてみてください。

//////////////////////////////////////////////////////ここから
        glLoadIdentity();    //行列の初期化
        gluLookAt(                  //カメラの設定
                         0, 0, 0,      //カメラの焦点位置、X,Y,Z
                         0, 0, 10,    //カメラの位置 X,Y,Z
                         0, 1,  0);    //画面の縦座標軸
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    //色と奥行きのクリアー
        glBegin(GL_TRIANGLES);     //三角形状の始まり
            glColor3d(1,0,0);             //色の設定
            glVertex3d(0,0,0);           //頂点の座標
            glVertex3d(0.2,0.1,0);      //頂点の座標
            glVertex3d(0.2,-0.1,0);    //頂点の座標
        glEnd();                             //終わり
        SwapBuffers(m_pCDC->m_hDC);    //描画実行
//////////////////////////////////////////////////////ここまで


これでコンパイルして赤い三角形が表示されたら成功です。
OpenGLではこの三角形が基本となります。
頂点の座標を変えれば三角形の形が変わります。
またglBeginからglEndまでを繰り返せばいくつも三角形ができます。
三角形のほかにもポリゴンやら四角形やらありますがその辺りは自分で調べてみてください。

またここで重要なのが視点の設定です。
基本的にカメラの焦点、カメラの位置、上が何軸かで決定されます。

これがカメラワークとなるわけです。
カメラが焦点に近づけば形状は大きく表示されますし、遠ざかれば小さくなります。
右に回り込んだり、左に回り込んだりも出来るわけです。

ちなみにカメラを移動させるか、形状を移動させるかどちらも表示上(見た目)は変わりません。
(カメラを右にずらすのも、形状を右にずらしたことと同じことです)
考えやすいほうで移動し表示してください。
ちなみにOpenGL内には決まった単位などはありません。自分でこれはミリやインチで使用すると考えてプログラムを組んでください。

これでOpenGLの形状を表示できるようになりました。
しかしまだまだ3次元のようには見えません。次はいよいよ3次元のように見せる光の設定方法を教えます。

glColor3d関数説明:
第1引数:赤0.0~1.0までで設定
第2引数:緑0.0~1.0までで設定
第3引数:青0.0~1.0までで設定
glVertex3d関数説明:
第1引数:X座標設定
第2引数:Y座標設定
第3引数:Z座標設定
gluLookAt関数説明:
第1~3引数:カメラの焦点位置、X,Y,Z
第4~6引数:カメラの位置 X,Y,Z
第7~9引数:画面の縦座標軸 単位ベクトルで指定すること

投稿者 Tsuda : 20:02 | コメント (0) | トラックバック

2005年05月24日

第一回 「まずOpenGLとは・・・。」

 OpenGL とVC++を使用して遊びましょう。OpenGL説明中にVC++、MFCの言葉が入ってくるかと思います。
一応ここを見る人はVC++を使用して開発する人を前提に書きますのでその辺はよろしくお願いします。
C#やWinAPIでも出来なくはないのですがそれはまた別のお話で。

まずはここから!
OpenGLってなに?
OpenGLとは3次元グラフィックAPIのことを言います。
3次元のコンピューターグラフィックを描くのであればDirectXもあるではないかと思った人。その通りです。
DirectXでも3次元コンピューターグラフィックは描けます。
ちなみにOpenGLはグラフィックを描くだけですがDirectXはネットワークやサウンドも合わせて提供してくれますので最近のゲームに多く使用されています。(開発が楽なのです)

ではOpenGLでは何が良いか?もちろん3次元グラフィックの描画速度はDirectXより速いです。
さらにDirectXのようにバージョンがいくつもあるなんてこともないのでOpenGLでは

「自分のPCでは動くのに他人のPCでは動かない!」

なんてことはまずないです。
さすがにグラフィックカードの性能によっては多少変な表示はされるようですが(^^;

OpenGLは描画速度が速いのでCAD,CAM、シミュレーションに多く使われています。

では早速手始めにOpenGLを使ってみましょう。
OpenGLのAPIにどんなのがあるかなんて後回しで表示してみましょう。
10個の手順で単純に表示まで出来ます。

1.まずVC++のプロジェクトでMFC-SDIを作成します。
2.ファイルをダウンロードしてみてください。⇒ダウンロード
3.2でダウンロードしたファイルをプロジェクトに追加します。
4.Viewクラスのヘッダーに次の1行を追加してください。
	#include "OpenGL.h"
5.さらにViewクラスのヘッダーに次の1行を追加してください。
	COpenGL *m_pOpenGL;
6.クラスウィザードでViewにOnInitialUpdateを追加してください。
7.View のOnInitialUpdate関数に次の1行を追加してください
	m_pOpenGL = new COpenGL( this );
8.View のOnDrawに次の1行を追加してください。
	m_pOpenGL->DrawOpenGL();
9.コンパイルしてください
10.実行

これで青い画面が表示されれば成功です。
画面が青いだけで何も表示されていませんが一応OpenGLで描かれています。

ちなみにInitOpenGL関数内にあるglClearColorの引数を変更すると画面の色が変更されます。

glClearColor関数説明:
第1引数:赤0.0~1.0までで設定
第2引数:緑0.0~1.0までで設定
第3引数:青0.0~1.0までで設定
第4引数:アルファ0.0~1.0までで設定


次回はいよいよ形状を表示させましょう。

投稿者 Tsuda : 16:17 | コメント (0) | トラックバック