OpenGL(Open Graphics Library)は、3Dグラフィックスを使ったアプリケーションを開発するためのライブラリで、UC-win/Road
SDKと連携させてプラグインを開発することで、魅力的な3D表現が可能となります。今回は、実際にSDKでOpenGLを利用する方法を、サンプルコードを使って解説します。
|
OpenGL(Open Graphics Library)は、3Dグラフィックスを使ったアプリケーションを開発するためのライブラリです。OpenGLを使うと、C言語やC++あるいは本書で解説しているDelphiといったプログラミング言語や開発ツールを利用して、3D表現が可能なプログラムを開発することができます【図01】。UC-win/RoadもOpenGLを利用して開発されています。
|
■図01 OpenGLで描画した3Dイメージの例 |
OpenGLによって開発したプログラムでは、3次元の画像を生成するだけでなく、3次元画像をリアルタイムでアニメーション表示させることも可能です。OpenGLは、もともと、アメリカのSGI社(旧Silicon
Graphics社)が開発した、IRIS GLというライブラリがベースとなっています。このライブラリはリアルタイムで動作する3Dグラフィックスプログラムを開発するためのものでしたが、SGI社以外の企業にもその技術が公開され、さまざまな企業で共同開発されるようになったのがOpenGLの始まりです。
OpenGL1.0がリリースされて以降、3Dグラフィックスの技術の進歩とともに発展し、現在はバージョン4.0まで利用できるようになっています。なお、OpenGLはWindowsだけでなく、Mac
OS、UNIX、あるいは携帯電話などの携帯端末用OSなどでも使うことができます。
OpenGLの描画の仕組みを簡単に解説しましょう。OpenGLでは複雑な3次元図形も、点、線、折れ線、三角形、連続した三角形、四角形、連続した四角形、多角形といった、非常に単純な「プリミティブ」という図形を組み合わせて描画しています。OpenGL自体が描画を担当するのは、こうしたプリミティブ図形のみです。
関数を使って、OpenGLのプリミティブを描画する関数を呼び出すと、頂点の座標値や法線ベクトルといったデータがグラフィックスボードに送られます。そして、頂点ごとの座標変換やライティングの計算などの処理を行う「ジオメトリステージ」、頂点の色から面の各ピクセルの色が計算され、テクスチャマッピングという画像をオブジェクトに貼り付けてよりリアルな見ばえにするための処理などをピクセルごとに行う「ラスタライズステージ」を経て、最終的に画面に表示される画像が生成されます。
これらのステージでの計算は、各頂点、あるいは各ピクセルで並列して実行されるため、高速で3次元画像を生成することが可能となります。これは、OpenGLなどの3Dグラフィックスライブラリを使って、3Dアプリケーションを開発する際のメリットといえるでしょう。
OpenGLを利用すると、リアルタイムでのアニメーション表現やインタラクティブでリアルな3D表現など、アプリケーションにおいて3次元イメージを生成する処理を、効率的に楽に開発できます。また、3Dオブジェクトの陰影を表現するシェーダ機能が備わっており、これを使えばさらにリアルな表現効果が容易に実現できます。こういった特徴からOpenGLは、ドライビングシミュレータやフライトシミュレータ、3次元CADなどの設計支援ソフトウェア、ゲームや携帯電話で使える娯楽用のアプリケーションなど、さまざまな3Dグラフィックスアプリケーションの開発に利用されています。
フォーラムエイト製品でも、UC-win/Roadをはじめ、UC-1シリーズの土木建築設計アプリケーションなどの開発で、OpenGLが使用されています。たとえば、UC-win/Roadでは、地形、道路、自動車、建物といった街並みの風景から、火や煙、ヘッドライト、気象などの機能でも使われています。また、UC-win/Road
SDKを使うと、OpenGLを使って自分が開発した機能をUC-win/Road上で使うことができるようになります。
|
OpenGLを使ったUC-win/Roadのプラグイン例 |
|
Exodusプラグイン、xpswmmプラグインや、UC-win/Road SDKに付属のサンプルプラグインの1つであるSpeed
Meterプラグインなど、フォーラムエイト製品でも、プラグインからOpenGLの描画コマンドを呼び出してUC-win/Road上で直接描画を行っているものがあります
たとえば、xpswmmプラグインを使用すると、河川などの氾濫をxpswmmでシミュレーションした結果がUC-win/Road上にコンターや矢印で描画されますが、これはプラグイン側で、xpswmmのシミュレーション結果のデータにしたがって、OpenGLでUC-win/Road上に描画しています。このようにして、シミュレーション結果を視覚的にVRで確認できるようになっています。
|
UC-win/Road SDKでOpenGLを利用する |
|
UC-win/Road SDKでOpenGLでの描画処理を利用するには、まず、作成するプラグインをIF8OpenGLPluginというインタフェースから継承する必要があります。作成するプラグインのクラスの宣言の継承元に、IF8OpenGLPluginを追加します。
このインタフェースを継承する場合、PaintScene、PaintHUD、SetupCameraの3つの新しい関数(procedure)を必ず追加する必要があります。
これらの関数は、クラス宣言部のpublic属性の関数として追加し、必要な処理をその関数の中に記述します。処理が必要ない場合でも、処理を行わない空の関数として定義する必要があります。
PaintSceneは、UC-win/Roadの3次元のシミュレーション画面にOpenGLでの描画処理を入れるための関数です。PaintHUDは、3次元空間上の描画が終わった後に、画面上で2次元の描画を行いたい場合に使用します。
たとえば、ドライブシミュレーション画面にスピードメーターを配置したり、イメージの処理を行うためにフィルタなどを半透明に描画するといった場合になります。SetupCameraは、その他の計算や更新処理を入れるところです。
|
UC-win/Road SDKとOpenGLの連携事例 |
|
実際にサンプルプラグインを作成しながら、SDKでOpenGLを使う方法を学習しましょう。
今回は、UC-win/Roadの初期画面に立方体を置くだけの処理を行う、簡単なプラグインを作ってみます。
■OpenGLによる描画処理
SDKの実装の説明に入る前に、OpenGLの描画処理の簡単な解説をしておきます。OpenGLでの描画処理は、次のような流れで行われます。
1 描画する図形の色マテリアル属性(材質)を設定する
2 座標変換の設定を行う
3 glBeginとglEndを囲んで描画処理に入る
4 描画する図形の法線ベクトルと頂点座標を指定する |
マテリアル属性
光源からのライティングをシミュレートするために、描画する図形のマテリアル、つまり材質属性を設定します。OpenGLでは、光源と物体表面のマテリアル属性を使って、リアルなライティングによる色の変化をシミュレートしています。
OpenGLで物体のマテリアル属性を設定するにはglMaterialfvという関数を使用しますが、これは3つの引数をとります。最初の引数で物体のいずれの面(表か裏か)の属性を設定するかを指定し、2つ目の引数では拡散反射属性、鏡面反射属性、環境光成分のいずれを設定するかを指定し、最後に4つの要素を持つ配列で属性の色を赤、緑、青、不透明度(アルファ値)で指定します。このうち不透明度については、通常は1.0(不透明)でかまいません。
座標変換
描画する3次元オブジェクトの移動、回転、拡大縮小などをしたい場合は、座標変換を行います。OpenGLは、内部的に行列でこれらの変換を管理しています。その中でも、オブジェクトの頂点座標を視点座標系に変換するまでは、モデルビュー変換行列という行列が担当しています。外側からこれらの変換行列を指定することもできますが、移動、回転、拡大縮小といった基本的な座標変換は、OpenGLの関数でサポートされています。
glBegin/glEnd
次に、いよいよ、OpenGLの描画を行う処理に入ります。描画を行う処理の中では、描画する図形の法線ベクトルや座標値などを指定します。描画処理の最初では、glBeginという関数で描画の開始と描画する基本図形を指定し、図形を構成する頂点などを関数で指定した後、glEndで描画の終了を宣言します。
glBeginには引数を1つ指定します。この引数は描画する基本図形(プリミティブ)を指定します。点、線分、折れ線や閉じた折れ線、三角形や連続した三角形、四角形や連続した四角形、凸多角形を指定できます。
法線ベクトルと頂点の指定
描画処理のglBeginとglEndの間では、glVertex**という関数で描画する図形の頂点を指定してやります。この関数には、glVertex2f、glVertex3f、glVertex3fvなどのさまざまなバージョンがあります。
glVertex2**の場合は2次元の座標(x, y)を指定し、gl
Vertex3f**の場合は3次元の座標(x, y, z)を指定します。ここでは3次元なので、glVertex3fvを使用し、3つの座標を配列で渡します。
また、OpenGLがライティングの計算をするために、3次元オブジェクトの各頂点の法線ベクトルが必要になります。法線ベクトルの指定にはglNormal3fvを使用します。これにもいくつかのバージョンがありますが、今回はこのバージョンを使用します。引数には、長さ1に正規化された法線ベクトルのx、y、zの3つの成分を配列で渡してやります。
法線ベクトルは各面の頂点でどれも同じであるため、各面の頂点を並べる最初に1回設定すればよいでしょう。
■UC-win/Roadの初期画面に立方体を置く
いよいよUC-win/Road SDKでOpenGLを使うサンプルを作成していきます。
宣言部
まず、BasePluginをコピーしてフォルダの名前を変えます。
次に、プラグインの宣言部では、OpenGLの関数を使用できるように、usesのところにGLユニットとF8OpenGLユニットを追加します。GLユニットにはOpenGLのさまざまな関数が定義されており、F8OpenGLユニットにはSDKのOpenGLコントロールや型、関数などが定義されています。
クラスの宣言部で、プラグインのクラスをIF8OpenGLPluginインタフェースから継承させます。
TAPlugin = class(TupfVisualPlugin, IF8UserPlugin, IF8OpenGLPlugin) |
このインタフェースで定義する必要がある関数の宣言をpublic部に追加します。
public
...
procedure PaintScene;
procedure PaintHUD;
procedure SetupCamera; |
また、ここでは立方体を置く場所を最初の視点位置の約10メートル手前にするため、表示する位置を保存する変数をprivate部に用意します。この変数はGLPointType型にします。この型は、GLfloat型の4つの要素をもつ配列で、F8OpenGLユニットの中で定義されています。
また、最初だけTrueになる変数としてfirstTimeというBoolean型の変数を用意します。これは、PaintSceneの中で最初だけ視点の位置から10メートル先を計算し、それを、表示する位置を保存する変数に入れておきたいためです。この設定が終わったら、この変数はFlaseにしておきます。
procedure TAPlugin.upfVisualPluginCreate(Sender: TObject);
begin
Supports(ApplicationServices, IF8ApplicationServices, winRoadApplication);
position[_x] := 5000.0;
position[_z] := 5000.0;
end; |
|
2つの変数を初期化する
|
|
PaintScene内の処理
描画処理では、最初だけ視点位置の10メートル先の座標を取得します。そのために、カメラの視点と注視点の差を取得し、それを使って、視点と注視点の距離を求め、xz平面で10メートル先の座標を取得します。これを表示位置のx、z座標とします。
立方体の位置の高さは、GetActualHeightAtという関数で取得します。この関数に、x、z座標を渡すと、地面の高さが求まります。立方体は原点を中心に一辺が1メートルとして描画するので、これに0.5足した値を表示位置の高さとします。
その後、glMaterialfvで描画する立方体のマテリアル属性を指定して、実際の描画を行います。描画するときは、最初にglPushMatrixで現在のモデルビュー変換行列をスタック【注12】
に保存しておきます。そして最後に、glPopMatrixでモデルビュー変換行列を元に戻します。これは、これ以降の変換処理をここだけで使用するようにしておくためです。
変換行列を保存したら、glTranslatefという関数を使って表示したい位置への移動変換を行います。関数の引数には、先ほど保存しておいた表示位置を設定します。こうすることで、立方体が表示させたい位置に平行移動され、正しく描画されます。その後、OpenGLによる立方体の描画処理を行います。glBeginとglEndで囲んで、その中で立方体の各面の法線ベクトルと4つの頂点を指定します。頂点座標、法線ベクトル、各面の頂点のインデックス番号を配列に入れておき、それを使って描画しています。各面は四角形なのでglBeginの引数には、GL_QUADSを渡します。
なお、OpenGLのプログラムでは通常は、光源の設定や投影変換の設定などその他の処理も行いますが、これらは、すべて、UC-win/Road内で行われているため、ここでは行う必要はありません。
procedure TAPlugin.PaintScene;
const
vertices : array [0..7, 0..2] of GLfloat = |
(
(-0.5, -0.5, 0.5),
( 0.5, -0.5, 0.5),
( 0.5, 0.5, 0.5),
(-0.5, 0.5, 0.5),
( 0.5, -0.5, -0.5),
(-0.5, -0.5, -0.5),
(-0.5, 0.5, -0.5),
( 0.5, 0.5, -0.5)
);
normalVectors : array [0..5, 0..2] of GLfloat = |
(
( 0.0, 0.0, 1.0),
( 0.0, 0.0, -1.0),
( 1.0, 0.0, 0.0),
(-1.0, 0.0, 0.0),
( 0.0, 1.0, 0.0),
( 0.0, -1.0, 0.0)
);
indeces : array [0..5, 0..3] of integer =
(
(0, 1, 2, 3),
(4, 5, 6, 7),
(1, 4, 7, 2),
(5, 0, 3, 6),
(3, 2, 7, 6),
(1, 0, 5, 4)
);
diffuse : array [0..2] of GLfloat = (1.0, 0.0 , 0.0);
ambient : array [0..2] of GLfloat = (0.25, 0.25, 0.25);
specular : array [0..2] of GLfloat = (1.0, 1.0, 1.0);
shininess : array [0..0] of GLfloat = (32.0);
var
i : integer;
j : integer;
y : single;
dx : single;
dz : single;
viewDistance : single;
begin
if firstTime then
begin;
dx := winRoadApplication.MainOpenGL.Camera.ViewPoint.x -
winRoadApplication.MainOpenGL.Camera.Eye.x;
dz := winRoadApplication.MainOpenGL.Camera.ViewPoint.z -
winRoadApplication.MainOpenGL.Camera.Eye.z;
viewDistance := sqrt(dx * dx + dz * dz);
position[_x] := winRoadApplication.MainOpenGL.Camera.Eye.x +
dx * 10.0 / viewDistance;
position[_z] := winRoadApplication.MainOpenGL.Camera.Eye.z +
dz * 10.0 / viewDistance;
position[_y] := winRoadApplication.project.GetActualHeightAt(
position[_x], position[_z]) + 0.5; |
firstTime := false;
end;
glMaterialfv(GL_FRONT, GL_DIFFUSE, @diffuse);
glMaterialfv(GL_FRONT, GL_AMBIENT, @ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, @specular);
glMaterialfv(GL_FRONT, GL_SHININESS, @shininess); |
glPushMatrix();
glTranslatef(position[_x], position[_y] , position[_z]); |
glBegin(GL_QUADS);
for i := 0 to 5 do
begin
glNormal3fv(@normalVectors[i]);
for j := 0 to 3 do
begin
glVertex3fv(@vertices[indeces[i, j]]);
end;
end;
glEnd(); |
glPopMatrix();
end; |
PaintHUD、SetupCamera内の処理
これらの関数では、今回は何も処理を行わないため、以下のように記述して、空の関数として定義します。
procedure TAPlugin.PaintHUD;
begin
end;
procedure TAPlugin.SetupCamera;
begin
end; |
|
■図3 UC-win/Roadの初期画面に立方体を置くプラグインの実行画面 |
有償セミナーのお知らせ
UC-win/Road SDKセミナー |
● 日時 |
2013年 3月 15日(金) 9:30 〜 16:30 |
● 受講費 |
1 名様 \18,000(税別) |
● 本会場 |
フォーラムエイト東京本社 GTタワーセミナールーム
※TV会議システムにて東京・大阪・名古屋・福岡・仙台同時開催 |
|
|
(Up&Coming '13 新年号掲載) |
|
|
>> 製品総合カタログ
>> プレミアム会員サービス
>> ファイナンシャルサポート
|