blog

OpenGLの包括的な例

描画では、いくつかのヘッダーファイルの役割を確認しましょう。 次にいくつかのグローバル変数を外部宣言する必要があります。 modeは以下の値またはその組み合わせを取ることができます: SetupRCで...

Sep 23, 2020 · 7 min. read
シェア

図面を描くにあたって、いくつかのヘッダーファイルの役割を説明しましょう。

// GLTool.hヘッダーファイルには、GLToolのC言語ライクなスタンドアロン関数のほとんどが含まれている。
#include "GLTools.h"
// シェーダマネージャ
#include "GLShaderManager.h"
// 行列を扱う:GLMatrixStackを使用して、単位行列/行列/行列の乗算/積み重ね/拡大縮小/移動/回転をロードできる。
#include "GLMatrixStack.h"
// オブザーバーの位置を表すマトリックスツールクラス.vOrigin、vForward、vUpsなどを設定する。
#include "GLFrame.h"
// 正射投影/透視投影行列を素早く設定するための行列ユーティリティクラス。.3Dからの座標変更を終了する。>2Dキーボードのマッピング処理は
#include "GLFrustum.h"
// 三角バッチクラスは、頂点/照明/テクスチャ/色のデータをカラライザーに転送するヘルパークラスだ。
#include "GLBatch.h"
// 変換パイプラインクラスは、ビュー行列/投影行列/ビュー投影変換行列などをコード内で素早く転送するために使用する。
#include "GLGeometryTransform.h"

次に、いくつかのグローバル変数を外部で宣言する必要があります。

// シェーダマネージャ
GLShaderManager shaderManager;
// モデルビュー行列
GLMatrixStack modelViewMatrix;
// 投影マトリックス
GLMatrixStack projectionMatrix;
// オブジェクトの3Dから2Dへのマッピングを完了するために使用されるView Body。
GLFrustum			viewFrustum;
// ジオメトリ変換パイプライン
GLGeometryTransform	transformPipeline;
//  
GLTriangleBatch torusBatch;
//  
GLTriangleBatch sphereBatch; 
// 
GLBatch floorBatch; 
// 文字フレーム カメラ文字フレーム
GLFrame cameraFrame;
// ランダムボールを追加する
#define NUM_SPHERES 50
GLFrame spheres[NUM_SPHERES];

床の描画

main関数のワークフロー

int main(int argc, char* argv[])
{
 // 作業ディレクトリを設定する。
 gltSetWorkingDirectory(argv[0]);
 // GLUT環境を初期化する。
 glutInit(&argc, argv);
 // 表示モードを設定する
 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
 // 初期化ウィンドウのサイズを設定する。
 glutInitWindowSize(800,600);
 // OpenGL SphereWorldというウィンドウを作成する。
 glutCreateWindow("OpenGL SphereWorld");
 // ウィンドウが変化したときのコールバック関数を登録する。
 glutReshapeFunc(ChangeSize);
 // 描画用の関数を登録する。
 glutDisplayFunc(RenderScene);
 // GLEWライブラリを初期化し、OpenGL APIがプログラムから完全に利用可能であることを確認する。レンダリングを行う前に、ドライバの初期化に問題がないことを確認する。
 GLenum err = glewInit();
 if (GLEW_OK != err) {
 fprintf(stderr, "GLEW Error: %s
", glewGetErrorString(err));
 return 1;
 }
 // 変数の初期化を行うカスタム関数
 SetupRC();
 // OCのrunloopに相当するmainloopを開く。
 glutMainLoop(); 
 return 0;
}

glutInitDisplayMode

この関数は、初期表示モードを設定します:

SetupRC

void SetupRC()
{ //背景色をクリアする。
 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 //1. 
 shaderManager.InitializeStockShaders();
 //2.深度テストをオンにする
 glEnable(GL_DEPTH_TEST);
 //3.床の頂点データを設定する
 floorBatch.Begin(GL_LINES, 324);
 for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5) {
 floorBatch.Vertex3f(x, -0.55f, 20.0f);
 floorBatch.Vertex3f(x, -0.55f, -20.0f);
 floorBatch.Vertex3f(20.0f, -0.55f, x);
 floorBatch.Vertex3f(-20.0f, -0.55f, x);
 }
 floorBatch.End();
}

ChangeSize

void ChangeSize(int nWidth, int nHeight)
{
 //1.ビューポートの設定
 glViewport(0, 0, nWidth, nHeight);
 //2.投影行列を作成する。
 viewFrustum.SetPerspective(35.0f, float(nWidth)/float(nHeight), 1.0f, 100.0f);
 //viewFrustum.GetProjectionMatrix() viewFrustum投影行列を取得し、投影行列スタックにロードする。
 projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
 //3.変換パイプラインが使用する2つの行列スタックを設定する。
 //GLGeometryTransformのインスタンス、transformPipelineを初期化する。.初期化は、内部ポインタをモデルビュー行列スタックと投影行列スタックのインスタンスに設定することで行う。
 //もちろん、これはSetupRC関数の中でも可能だが、ウィンドウサイズが変わったときやウィンドウが作成されたときに設定しておいて損はない。また、こうすることでマトリックスとパイプラインを一度に設定することができる。
 transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

RenderScene

void RenderScene(void)
{
 //1. 
 GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
 //2.カラーバッファと深度バッファのデータをクリアする。
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 //3.平面シェーダを使って、地面を描く。
 shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vFloorColor);
 floorBatch.Draw();
 //4.バッファスワップを実装する。
 glutSwapBuffers();
}

大きなボールを描画

SetupRC

SetupRC で球のデータを初期化します。

// 球体の三角形バッチを初期化し、球体の半径、セグメント数、スタック数の順にパラメータを指定する。
gltMakeSphere(torusBatch, 0.5f, 300, 80);

RenderScene

大きなボールはRenderScene関数で描画されます。

// 球体の色を定義する。
static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
// 球を回転させるタイマーを定義する。
static CStopWatch rotTimer;
float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
 
// 球体を描画する
// 光源の位置を取得する
M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
// 大きなボールの位置を平行移動させる。.0)を画面の内側に追加する。
modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
// 球体の回転を処理するために、スタックをモデルビュー行列に押し込む。
modelViewMatrix.PushMatrix();
// 球体を回転させる
modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
// ポイントソースシェーダーを使う
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
 transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
//  
torusBatch.Draw();
// 描画後にスタックから取り出す
modelViewMatrix.PopMatrix();

上記のコードを追加します。この時点で球体はレンダリングされましたが、この時点では動いていません。動くようにするには、再レンダリングのために送信する必要があります。

glutPostRedisplay();

RenderSceneの最終コード

void RenderScene(void)
{
 //1.色の値
 static GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
 static GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
 
 //2.時間ベースのアニメーション
 static CStopWatch rotTimer;
 float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
 
 //2.カラーバッファと深度バッファをクリアする。
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 //**//  
 modelViewMatrix.PushMatrix();
 
 //3.地面を描く
 shaderManager.UseStockShader(GLT_SHADER_FLAT,
 transformPipeline.GetModelViewProjectionMatrix(),
 vFloorColor);
 floorBatch.Draw();
 
 
 //4.光源の位置を取得する
 M3DVector4f vLightPos = {0.0f,10.0f,5.0f,1.0f};
 
 //5.大玉の位置を平行移動させる(3.0)スクリーン内部
 modelViewMatrix.Translate(0.0f, 0.0f, -3.0f);
 //6.スタックを押す
 modelViewMatrix.PushMatrix();
 //7.大きなボールを回転させる
 modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
 //8.適切なシェーダーを指定する。
 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
 transformPipeline.GetProjectionMatrix(), vLightPos, vTorusColor);
 torusBatch.Draw();
 //9.描画が終了したらポップする
 modelViewMatrix.PopMatrix();
 modelViewMatrix.PopMatrix();
 
 //10.バッファスワップを実装する。
 glutSwapBuffers();
 glutPostRedisplay();
}

ブロブの描画

SetupRC

SetupRC関数でのボールのモデルの設定

// ブロブモデルをセットアップする
gltMakeSphere(sphereBatch, 0.1f, 13, 26);
// パックをランダムな位置に置く
for (int i = 0; i < NUM_SPHERES; i++) {
 //y軸はそのままで、X,Zはランダムな値を生成する。
 GLfloat x = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
 GLfloat z = ((GLfloat)((rand() % 400) - 200 ) * 0.1f);
 //y方向に、球を0に設定する。.0キーボードの位置を変更することで、目の高さに浮いているように見える。
 //spheres配列の各頂点に、頂点データをセットする。
 spheres[i].SetOrigin(x, 0.0f, z);
}

RenderScene

RenderScene関数でのボールの描画

//  
for (int i = 0; i < NUM_SPHERES; i++) {
 modelViewMatrix.PushMatrix();
 modelViewMatrix.MultMatrix(spheres[i]);
 shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
 transformPipeline.GetProjectionMatrix(), vLightPos, vSphereColor);
 sphereBatch.Draw();
 modelViewMatrix.PopMatrix();
}

次に、大きなボールの周りを小さなボールが回転するようにするには、RenderScene関数に次のコードを追加します。

modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF,transformPipeline.GetModelViewMatrix(),transformPipeline.GetProjectionMatrix(),vLightPos,vSphereColor);
sphereBatch.Draw();

オブザーバの移動

まず、RenderScene関数に以下のコードを追加して、モデルビューの行列スタックにオブザーバ行列を追加します。

// オブザーバー行列を作成する
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
// オブザーバー行列をモデルビュースタックに押し込む。
modelViewMatrix.PushMatrix(mCamera);
。。。。
// 最後に
modelViewMatrix.PopMatrix();

次にSpeacialKeys関数を実装する必要があります。キーボードコントロールの実装

void SpeacialKeys(int key,int x,int y){
 float linear = 0.1f;
 float angular = float(m3dDegToRad(5.0f));
 
 if (key == GLUT_KEY_UP) {
 cameraFrame.MoveForward(linear);
 }
 if (key == GLUT_KEY_DOWN) {
 cameraFrame.MoveForward(-linear);
 }
 
 if (key == GLUT_KEY_LEFT) {
 cameraFrame.RotateWorld(angular, 0, 1, 0);
 }
 if (key == GLUT_KEY_RIGHT) {
 cameraFrame.RotateWorld(-angular, 0, 1, 0);
 }
}
Read next

立体地図のネイチャーペーパーは、もともとこのように描かれていた。

これは2次元の地図で、難易度は全くなく、地図上に直接表示されます。 海底地形3Dステレオマップ+3D散布図、この効果を描画するためにバグgmtを修正した後に使用する必要があり、必要なすべてのプログラムは、ドッカーイメージの中にあります。3つの簡単なコマンドを使うだけで、全くストレスなく使えます! 海底地形3Dステレオマップ+3D散布図+スライスデータ+スライスしたキャストポイントとカーブ、これを作らなければなりません...

Sep 23, 2020 · 3 min read